--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -49,28 +49,35 @@ using namespace js;
using namespace js::frontend;
using namespace js::jit;
using namespace js::wasm;
using mozilla::Compression::LZ4;
using mozilla::HashGeneric;
using mozilla::IsNaN;
using mozilla::IsNegativeZero;
-using mozilla::MallocSizeOf;
using mozilla::Move;
using mozilla::PodCopy;
using mozilla::PodEqual;
using mozilla::PodZero;
using mozilla::PositiveInfinity;
using JS::AsmJSOption;
using JS::GenericNaN;
+
/*****************************************************************************/
// asm.js module object
+static void
+TraceNameField(JSTracer* trc, PropertyName* const* name, const char* label)
+{
+ if (*name)
+ TraceManuallyBarrieredEdge(trc, const_cast<PropertyName**>(name), label);
+}
+
// The asm.js spec recognizes this set of builtin Math functions.
enum AsmJSMathBuiltinFunction
{
AsmJSMathBuiltin_sin, AsmJSMathBuiltin_cos, AsmJSMathBuiltin_tan,
AsmJSMathBuiltin_asin, AsmJSMathBuiltin_acos, AsmJSMathBuiltin_atan,
AsmJSMathBuiltin_ceil, AsmJSMathBuiltin_floor, AsmJSMathBuiltin_exp,
AsmJSMathBuiltin_log, AsmJSMathBuiltin_pow, AsmJSMathBuiltin_sqrt,
AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul,
@@ -118,604 +125,363 @@ IsSignedIntSimdType(AsmJSSimdType type)
// Set of known operations, for a given SIMD type (int32x4, float32x4,...)
enum AsmJSSimdOperation
{
#define ASMJSSIMDOPERATION(op) AsmJSSimdOperation_##op,
FORALL_SIMD_ASMJS_OP(ASMJSSIMDOPERATION)
#undef ASMJSSIMDOPERATION
};
-// An AsmJSModule extends (via containment) a wasm::Module with the extra
-// persistent state necessary to represent a compiled asm.js module.
-class js::AsmJSModule
+// An AsmJSGlobal represents a JS global variable in the asm.js module function.
+class AsmJSGlobal
{
public:
- class Global
- {
- public:
- enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction,
- AtomicsBuiltinFunction, Constant, SimdCtor, SimdOperation };
- enum VarInitKind { InitConstant, InitImport };
- enum ConstantKind { GlobalConstant, MathConstant };
-
- private:
- struct CacheablePod {
- Which which_;
- union {
- struct {
- uint32_t globalDataOffset_;
- VarInitKind initKind_;
- union {
- wasm::ValType importType_;
- wasm::Val val_;
- } u;
- } var;
- uint32_t ffiIndex_;
- Scalar::Type viewType_;
- AsmJSMathBuiltinFunction mathBuiltinFunc_;
- AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
- AsmJSSimdType simdCtorType_;
- struct {
- AsmJSSimdType type_;
- AsmJSSimdOperation which_;
- } simdOp;
- struct {
- ConstantKind kind_;
- double value_;
- } constant;
- } u;
- } pod;
- PropertyName* name_;
-
- friend class AsmJSModule;
-
- Global(Which which, PropertyName* name) {
- mozilla::PodZero(&pod); // zero padding for Valgrind
- pod.which_ = which;
- name_ = name;
- MOZ_ASSERT_IF(name_, name_->isTenured());
- }
-
- void trace(JSTracer* trc) {
- if (name_)
- TraceManuallyBarrieredEdge(trc, &name_, "asm.js global name");
- }
-
- public:
- Global() {}
- Which which() const {
- return pod.which_;
- }
- uint32_t varGlobalDataOffset() const {
- MOZ_ASSERT(pod.which_ == Variable);
- return pod.u.var.globalDataOffset_;
- }
- VarInitKind varInitKind() const {
- MOZ_ASSERT(pod.which_ == Variable);
- return pod.u.var.initKind_;
- }
- wasm::Val varInitVal() const {
- MOZ_ASSERT(pod.which_ == Variable);
- MOZ_ASSERT(pod.u.var.initKind_ == InitConstant);
- return pod.u.var.u.val_;
- }
- wasm::ValType varInitImportType() const {
- MOZ_ASSERT(pod.which_ == Variable);
- MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
- return pod.u.var.u.importType_;
- }
- PropertyName* varImportField() const {
- MOZ_ASSERT(pod.which_ == Variable);
- MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
- return name_;
- }
- PropertyName* ffiField() const {
- MOZ_ASSERT(pod.which_ == FFI);
- return name_;
- }
- uint32_t ffiIndex() const {
- MOZ_ASSERT(pod.which_ == FFI);
- return pod.u.ffiIndex_;
- }
- // When a view is created from an imported constructor:
- // var I32 = stdlib.Int32Array;
- // var i32 = new I32(buffer);
- // the second import has nothing to validate and thus has a null field.
- PropertyName* maybeViewName() const {
- MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
- return name_;
- }
- Scalar::Type viewType() const {
- MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
- return pod.u.viewType_;
- }
- PropertyName* mathName() const {
- MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
- return name_;
- }
- PropertyName* atomicsName() const {
- MOZ_ASSERT(pod.which_ == AtomicsBuiltinFunction);
- return name_;
- }
- AsmJSMathBuiltinFunction mathBuiltinFunction() const {
- MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
- return pod.u.mathBuiltinFunc_;
- }
- AsmJSAtomicsBuiltinFunction atomicsBuiltinFunction() const {
- MOZ_ASSERT(pod.which_ == AtomicsBuiltinFunction);
- return pod.u.atomicsBuiltinFunc_;
- }
- AsmJSSimdType simdCtorType() const {
- MOZ_ASSERT(pod.which_ == SimdCtor);
- return pod.u.simdCtorType_;
- }
- PropertyName* simdCtorName() const {
- MOZ_ASSERT(pod.which_ == SimdCtor);
- return name_;
- }
- PropertyName* simdOperationName() const {
- MOZ_ASSERT(pod.which_ == SimdOperation);
- return name_;
- }
- AsmJSSimdOperation simdOperation() const {
- MOZ_ASSERT(pod.which_ == SimdOperation);
- return pod.u.simdOp.which_;
- }
- AsmJSSimdType simdOperationType() const {
- MOZ_ASSERT(pod.which_ == SimdOperation);
- return pod.u.simdOp.type_;
- }
- PropertyName* constantName() const {
- MOZ_ASSERT(pod.which_ == Constant);
- return name_;
- }
- ConstantKind constantKind() const {
- MOZ_ASSERT(pod.which_ == Constant);
- return pod.u.constant.kind_;
- }
- double constantValue() const {
- MOZ_ASSERT(pod.which_ == Constant);
- return pod.u.constant.value_;
- }
-
- WASM_DECLARE_SERIALIZABLE(Global);
- };
-
- typedef Vector<Global, 0, SystemAllocPolicy> GlobalVector;
-
- // An import is slightly different than an asm.js FFI function: a single
- // asm.js FFI function can be called with many different signatures. When
- // compiled to wasm, each unique FFI function paired with signature
- // generates a wasm import.
- class Import
- {
- uint32_t ffiIndex_;
- public:
- Import() = default;
- explicit Import(uint32_t ffiIndex) : ffiIndex_(ffiIndex) {}
- uint32_t ffiIndex() const { return ffiIndex_; }
- };
-
- typedef Vector<Import, 0, SystemAllocPolicy> ImportVector;
-
- class Export
- {
- PropertyName* name_;
- PropertyName* maybeFieldName_;
- struct CacheablePod {
- uint32_t startOffsetInModule_; // Store module-start-relative offsets
- uint32_t endOffsetInModule_; // so preserved by serialization.
- } pod;
-
- public:
- Export() {}
- Export(PropertyName* name, PropertyName* maybeFieldName,
- uint32_t startOffsetInModule, uint32_t endOffsetInModule)
- : name_(name),
- maybeFieldName_(maybeFieldName)
- {
- MOZ_ASSERT(name_->isTenured());
- MOZ_ASSERT_IF(maybeFieldName_, maybeFieldName_->isTenured());
- pod.startOffsetInModule_ = startOffsetInModule;
- pod.endOffsetInModule_ = endOffsetInModule;
- }
-
- void trace(JSTracer* trc) {
- TraceManuallyBarrieredEdge(trc, &name_, "asm.js export name");
- if (maybeFieldName_)
- TraceManuallyBarrieredEdge(trc, &maybeFieldName_, "asm.js export field");
- }
-
- PropertyName* name() const {
- return name_;
- }
- PropertyName* maybeFieldName() const {
- return maybeFieldName_;
- }
- uint32_t startOffsetInModule() const {
- return pod.startOffsetInModule_;
- }
- uint32_t endOffsetInModule() const {
- return pod.endOffsetInModule_;
- }
-
- WASM_DECLARE_SERIALIZABLE(Export)
- };
-
- typedef Vector<Export, 0, SystemAllocPolicy> ExportVector;
-
- typedef JS::UniquePtr<wasm::Module, JS::DeletePolicy<wasm::Module>> UniqueWasmModule;
+ enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction,
+ AtomicsBuiltinFunction, Constant, SimdCtor, SimdOperation };
+ enum VarInitKind { InitConstant, InitImport };
+ enum ConstantKind { GlobalConstant, MathConstant };
private:
- UniqueWasmModule wasmModule_;
- wasm::UniqueStaticLinkData linkData_;
struct CacheablePod {
- uint32_t minHeapLength_;
- uint32_t numFFIs_;
- uint32_t srcLength_;
- uint32_t srcLengthWithRightBrace_;
- bool strict_;
- bool hasArrayView_;
- bool isSharedView_;
+ Which which_;
+ union {
+ struct {
+ uint32_t globalDataOffset_;
+ VarInitKind initKind_;
+ union {
+ ValType importType_;
+ Val val_;
+ } u;
+ } var;
+ uint32_t ffiIndex_;
+ Scalar::Type viewType_;
+ AsmJSMathBuiltinFunction mathBuiltinFunc_;
+ AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
+ AsmJSSimdType simdCtorType_;
+ struct {
+ AsmJSSimdType type_;
+ AsmJSSimdOperation which_;
+ } simdOp;
+ struct {
+ ConstantKind kind_;
+ double value_;
+ } constant;
+ } u;
} pod;
- const ScriptSourceHolder scriptSource_;
- const uint32_t srcStart_;
- const uint32_t srcBodyStart_;
- GlobalVector globals_;
- ImportVector imports_;
- ExportVector exports_;
- PropertyName* globalArgumentName_;
- PropertyName* importArgumentName_;
- PropertyName* bufferArgumentName_;
+ PropertyName* name_;
+
+ friend class ModuleValidator;
public:
- explicit AsmJSModule(ScriptSource* scriptSource, uint32_t srcStart, uint32_t srcBodyStart,
- bool strict)
- : scriptSource_(scriptSource),
- srcStart_(srcStart),
- srcBodyStart_(srcBodyStart),
- globalArgumentName_(nullptr),
- importArgumentName_(nullptr),
- bufferArgumentName_(nullptr)
+ AsmJSGlobal() {}
+ AsmJSGlobal(Which which, PropertyName* name) {
+ mozilla::PodZero(&pod); // zero padding for Valgrind
+ pod.which_ = which;
+ name_ = name;
+ MOZ_ASSERT_IF(name_, name_->isTenured());
+ }
+ void trace(JSTracer* trc) const {
+ TraceNameField(trc, &name_, "asm.js global name");
+ }
+ Which which() const {
+ return pod.which_;
+ }
+ uint32_t varGlobalDataOffset() const {
+ MOZ_ASSERT(pod.which_ == Variable);
+ return pod.u.var.globalDataOffset_;
+ }
+ VarInitKind varInitKind() const {
+ MOZ_ASSERT(pod.which_ == Variable);
+ return pod.u.var.initKind_;
+ }
+ Val varInitVal() const {
+ MOZ_ASSERT(pod.which_ == Variable);
+ MOZ_ASSERT(pod.u.var.initKind_ == InitConstant);
+ return pod.u.var.u.val_;
+ }
+ ValType varInitImportType() const {
+ MOZ_ASSERT(pod.which_ == Variable);
+ MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
+ return pod.u.var.u.importType_;
+ }
+ PropertyName* varImportField() const {
+ MOZ_ASSERT(pod.which_ == Variable);
+ MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
+ return name_;
+ }
+ PropertyName* ffiField() const {
+ MOZ_ASSERT(pod.which_ == FFI);
+ return name_;
+ }
+ uint32_t ffiIndex() const {
+ MOZ_ASSERT(pod.which_ == FFI);
+ return pod.u.ffiIndex_;
+ }
+ // When a view is created from an imported constructor:
+ // var I32 = stdlib.Int32Array;
+ // var i32 = new I32(buffer);
+ // the second import has nothing to validate and thus has a null field.
+ PropertyName* maybeViewName() const {
+ MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
+ return name_;
+ }
+ Scalar::Type viewType() const {
+ MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
+ return pod.u.viewType_;
+ }
+ PropertyName* mathName() const {
+ MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
+ return name_;
+ }
+ PropertyName* atomicsName() const {
+ MOZ_ASSERT(pod.which_ == AtomicsBuiltinFunction);
+ return name_;
+ }
+ AsmJSMathBuiltinFunction mathBuiltinFunction() const {
+ MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
+ return pod.u.mathBuiltinFunc_;
+ }
+ AsmJSAtomicsBuiltinFunction atomicsBuiltinFunction() const {
+ MOZ_ASSERT(pod.which_ == AtomicsBuiltinFunction);
+ return pod.u.atomicsBuiltinFunc_;
+ }
+ AsmJSSimdType simdCtorType() const {
+ MOZ_ASSERT(pod.which_ == SimdCtor);
+ return pod.u.simdCtorType_;
+ }
+ PropertyName* simdCtorName() const {
+ MOZ_ASSERT(pod.which_ == SimdCtor);
+ return name_;
+ }
+ PropertyName* simdOperationName() const {
+ MOZ_ASSERT(pod.which_ == SimdOperation);
+ return name_;
+ }
+ AsmJSSimdOperation simdOperation() const {
+ MOZ_ASSERT(pod.which_ == SimdOperation);
+ return pod.u.simdOp.which_;
+ }
+ AsmJSSimdType simdOperationType() const {
+ MOZ_ASSERT(pod.which_ == SimdOperation);
+ return pod.u.simdOp.type_;
+ }
+ PropertyName* constantName() const {
+ MOZ_ASSERT(pod.which_ == Constant);
+ return name_;
+ }
+ ConstantKind constantKind() const {
+ MOZ_ASSERT(pod.which_ == Constant);
+ return pod.u.constant.kind_;
+ }
+ double constantValue() const {
+ MOZ_ASSERT(pod.which_ == Constant);
+ return pod.u.constant.value_;
+ }
+
+ WASM_DECLARE_SERIALIZABLE(AsmJSGlobal);
+};
+
+typedef Vector<AsmJSGlobal, 0, SystemAllocPolicy> AsmJSGlobalVector;
+
+// An AsmJSImport is slightly different than an asm.js FFI function: a single
+// asm.js FFI function can be called with many different signatures. When
+// compiled to wasm, each unique FFI function paired with signature generates a
+// wasm import.
+class AsmJSImport
+{
+ uint32_t ffiIndex_;
+ public:
+ AsmJSImport() = default;
+ explicit AsmJSImport(uint32_t ffiIndex) : ffiIndex_(ffiIndex) {}
+ uint32_t ffiIndex() const { return ffiIndex_; }
+};
+
+typedef Vector<AsmJSImport, 0, SystemAllocPolicy> AsmJSImportVector;
+
+// An AsmJSExport represents a field in the export object.
+class AsmJSExport
+{
+ PropertyName* name_;
+ PropertyName* maybeFieldName_;
+ struct CacheablePod {
+ uint32_t startOffsetInModule_; // Store module-start-relative offsets
+ uint32_t endOffsetInModule_; // so preserved by serialization.
+ } pod;
+
+ public:
+ AsmJSExport() {}
+ AsmJSExport(PropertyName* name, PropertyName* maybeFieldName,
+ uint32_t startOffsetInModule, uint32_t endOffsetInModule)
+ : name_(name),
+ maybeFieldName_(maybeFieldName)
{
- mozilla::PodZero(&pod);
- pod.minHeapLength_ = RoundUpToNextValidAsmJSHeapLength(0);
- pod.strict_ = strict;
-
- MOZ_ASSERT(srcStart_ <= srcBodyStart_);
-
- // AsmJSCheckedImmediateRange should be defined to be at most the minimum
- // heap length so that offsets can be folded into bounds checks.
- MOZ_ASSERT(pod.minHeapLength_ - jit::AsmJSCheckedImmediateRange <= pod.minHeapLength_);
- }
-
- void trace(JSTracer* trc) {
- if (wasmModule_)
- wasmModule_->trace(trc);
- for (Global& global : globals_)
+ MOZ_ASSERT(name_->isTenured());
+ MOZ_ASSERT_IF(maybeFieldName_, maybeFieldName_->isTenured());
+ pod.startOffsetInModule_ = startOffsetInModule;
+ pod.endOffsetInModule_ = endOffsetInModule;
+ }
+ void trace(JSTracer* trc) const {
+ TraceNameField(trc, &name_, "asm.js export name");
+ TraceNameField(trc, &maybeFieldName_, "asm.js export field");
+ }
+ PropertyName* name() const {
+ return name_;
+ }
+ PropertyName* maybeFieldName() const {
+ return maybeFieldName_;
+ }
+ uint32_t startOffsetInModule() const {
+ return pod.startOffsetInModule_;
+ }
+ uint32_t endOffsetInModule() const {
+ return pod.endOffsetInModule_;
+ }
+
+ WASM_DECLARE_SERIALIZABLE(AsmJSExport)
+};
+
+typedef Vector<AsmJSExport, 0, SystemAllocPolicy> AsmJSExportVector;
+
+// Holds the trivially-memcpy()able, serializable portion of AsmJSModuleData.
+struct AsmJSModuleCacheablePod
+{
+ uint32_t minHeapLength;
+ uint32_t numFFIs;
+ uint32_t srcLength;
+ uint32_t srcLengthWithRightBrace;
+};
+
+// Holds the immutable guts of an AsmJSModule. This struct is mutably built up
+// by ModuleValidator and then handed over to the AsmJSModule constructor in
+// finish().
+struct AsmJSModuleData
+{
+ AsmJSModuleCacheablePod pod;
+ AsmJSGlobalVector globals;
+ AsmJSImportVector imports;
+ AsmJSExportVector exports;
+ PropertyName* globalArgumentName;
+ PropertyName* importArgumentName;
+ PropertyName* bufferArgumentName;
+
+ // These values are not serialized since they are relative to the
+ // containing script which can be different between serialization and
+ // deserialization contexts. Thus, they must be set explicitly using the
+ // ambient Parser/ScriptSource after deserialization. Cloning, however,
+ // preserves the same exact parsing context and can copy these values.
+ uint32_t srcStart;
+ uint32_t srcBodyStart;
+ bool strict;
+ ScriptSourceHolder scriptSource;
+
+ AsmJSModuleData()
+ : globalArgumentName(nullptr),
+ importArgumentName(nullptr),
+ bufferArgumentName(nullptr),
+ srcStart(0),
+ srcBodyStart(0),
+ strict(false)
+ {
+ PodZero(&pod);
+ }
+
+ void trace(JSTracer* trc) const {
+ for (const AsmJSGlobal& global : globals)
global.trace(trc);
- for (Export& exp : exports_)
+ for (const AsmJSExport& exp : exports)
exp.trace(trc);
- if (globalArgumentName_)
- TraceManuallyBarrieredEdge(trc, &globalArgumentName_, "asm.js global argument name");
- if (importArgumentName_)
- TraceManuallyBarrieredEdge(trc, &importArgumentName_, "asm.js import argument name");
- if (bufferArgumentName_)
- TraceManuallyBarrieredEdge(trc, &bufferArgumentName_, "asm.js buffer argument name");
- }
-
- /*************************************************************************/
- // These functions may be used as soon as the module is constructed:
-
- ScriptSource* scriptSource() const {
- return scriptSource_.get();
- }
- bool strict() const {
- return pod.strict_;
- }
+ TraceNameField(trc, &globalArgumentName, "asm.js global argument name");
+ TraceNameField(trc, &importArgumentName, "asm.js import argument name");
+ TraceNameField(trc, &bufferArgumentName, "asm.js buffer argument name");
+ }
+
+ WASM_DECLARE_SERIALIZABLE(AsmJSModuleData)
+};
+
+typedef UniquePtr<AsmJSModuleData, JS::DeletePolicy<AsmJSModuleData>> UniqueAsmJSModuleData;
+
+// An AsmJSModule is-a Module with the extra persistent state necessary to
+// represent a compiled asm.js module.
+class js::AsmJSModule final : public Module
+{
+ typedef UniquePtr<const AsmJSModuleData,
+ JS::DeletePolicy<const AsmJSModuleData>> UniqueConstAsmJSModuleData;
+ typedef UniquePtr<const StaticLinkData,
+ JS::DeletePolicy<const StaticLinkData>> UniqueConstStaticLinkData;
+
+ const UniqueConstStaticLinkData linkData_;
+ const UniqueConstAsmJSModuleData data_;
+
+ public:
+ AsmJSModule(UniqueModuleData baseData,
+ UniqueStaticLinkData linkData,
+ UniqueAsmJSModuleData data)
+ : Module(Move(baseData), Module::IsAsmJS),
+ linkData_(Move(linkData)),
+ data_(Move(data))
+ {}
+
+ virtual void trace(JSTracer* trc) override {
+ Module::trace(trc);
+ data_->trace(trc);
+ }
+
+ uint32_t minHeapLength() const { return data_->pod.minHeapLength; }
+ uint32_t numFFIs() const { return data_->pod.numFFIs; }
+ bool strict() const { return data_->strict; }
+ ScriptSource* scriptSource() const { return data_->scriptSource.get(); }
+ const AsmJSGlobalVector& asmJSGlobals() const { return data_->globals; }
+ const AsmJSImportVector& asmJSImports() const { return data_->imports; }
+ const AsmJSExportVector& asmJSExports() const { return data_->exports; }
+ PropertyName* globalArgumentName() const { return data_->globalArgumentName; }
+ PropertyName* importArgumentName() const { return data_->importArgumentName; }
+ PropertyName* bufferArgumentName() const { return data_->bufferArgumentName; }
// srcStart() refers to the offset in the ScriptSource to the beginning of
// the asm.js module function. If the function has been created with the
// Function constructor, this will be the first character in the function
// source. Otherwise, it will be the opening parenthesis of the arguments
// list.
uint32_t srcStart() const {
- return srcStart_;
+ return data_->srcStart;
+ }
+ uint32_t srcEndBeforeCurly() const {
+ return data_->srcStart + data_->pod.srcLength;
+ }
+ uint32_t srcEndAfterCurly() const {
+ return data_->srcStart + data_->pod.srcLengthWithRightBrace;
}
// srcBodyStart() refers to the offset in the ScriptSource to the end
// of the 'use asm' string-literal token.
uint32_t srcBodyStart() const {
- return srcBodyStart_;
- }
-
- // While these functions may be accessed at any time, their values will
- // change as the module is compiled.
- uint32_t minHeapLength() const {
- return pod.minHeapLength_;
- }
-
- void initGlobalArgumentName(PropertyName* n) {
- MOZ_ASSERT(!isFinished());
- MOZ_ASSERT_IF(n, n->isTenured());
- globalArgumentName_ = n;
- }
- void initImportArgumentName(PropertyName* n) {
- MOZ_ASSERT(!isFinished());
- MOZ_ASSERT_IF(n, n->isTenured());
- importArgumentName_ = n;
- }
- void initBufferArgumentName(PropertyName* n) {
- MOZ_ASSERT(!isFinished());
- MOZ_ASSERT_IF(n, n->isTenured());
- bufferArgumentName_ = n;
- }
- PropertyName* globalArgumentName() const {
- return globalArgumentName_;
- }
- PropertyName* importArgumentName() const {
- return importArgumentName_;
- }
- PropertyName* bufferArgumentName() const {
- return bufferArgumentName_;
- }
-
- bool addGlobalVarInit(const wasm::Val& v, uint32_t globalDataOffset) {
- MOZ_ASSERT(!isFinished());
- Global g(Global::Variable, nullptr);
- g.pod.u.var.initKind_ = Global::InitConstant;
- g.pod.u.var.u.val_ = v;
- g.pod.u.var.globalDataOffset_ = globalDataOffset;
- return globals_.append(g);
- }
- bool addGlobalVarImport(PropertyName* name, wasm::ValType importType, uint32_t globalDataOffset) {
- MOZ_ASSERT(!isFinished());
- Global g(Global::Variable, name);
- g.pod.u.var.initKind_ = Global::InitImport;
- g.pod.u.var.u.importType_ = importType;
- g.pod.u.var.globalDataOffset_ = globalDataOffset;
- return globals_.append(g);
- }
- // See Import comment above for FFI vs. Import.
- bool addFFI(PropertyName* field, uint32_t* ffiIndex) {
- MOZ_ASSERT(!isFinished());
- if (pod.numFFIs_ == UINT32_MAX)
- return false;
- Global g(Global::FFI, field);
- g.pod.u.ffiIndex_ = *ffiIndex = pod.numFFIs_++;
- return globals_.append(g);
- }
- bool addArrayView(Scalar::Type vt, PropertyName* maybeField) {
- MOZ_ASSERT(!isFinished());
- pod.hasArrayView_ = true;
- pod.isSharedView_ = false;
- Global g(Global::ArrayView, maybeField);
- g.pod.u.viewType_ = vt;
- return globals_.append(g);
- }
- bool addArrayViewCtor(Scalar::Type vt, PropertyName* field) {
- MOZ_ASSERT(!isFinished());
- MOZ_ASSERT(field);
- pod.isSharedView_ = false;
- Global g(Global::ArrayViewCtor, field);
- g.pod.u.viewType_ = vt;
- return globals_.append(g);
- }
- bool addMathBuiltinFunction(AsmJSMathBuiltinFunction func, PropertyName* field) {
- MOZ_ASSERT(!isFinished());
- Global g(Global::MathBuiltinFunction, field);
- g.pod.u.mathBuiltinFunc_ = func;
- return globals_.append(g);
- }
- bool addMathBuiltinConstant(double value, PropertyName* field) {
- MOZ_ASSERT(!isFinished());
- Global g(Global::Constant, field);
- g.pod.u.constant.value_ = value;
- g.pod.u.constant.kind_ = Global::MathConstant;
- return globals_.append(g);
- }
- bool addAtomicsBuiltinFunction(AsmJSAtomicsBuiltinFunction func, PropertyName* field) {
- MOZ_ASSERT(!isFinished());
- Global g(Global::AtomicsBuiltinFunction, field);
- g.pod.u.atomicsBuiltinFunc_ = func;
- return globals_.append(g);
- }
- bool addSimdCtor(AsmJSSimdType type, PropertyName* field) {
- MOZ_ASSERT(!isFinished());
- Global g(Global::SimdCtor, field);
- g.pod.u.simdCtorType_ = type;
- return globals_.append(g);
- }
- bool addSimdOperation(AsmJSSimdType type, AsmJSSimdOperation op, PropertyName* field) {
- MOZ_ASSERT(!isFinished());
- Global g(Global::SimdOperation, field);
- g.pod.u.simdOp.type_ = type;
- g.pod.u.simdOp.which_ = op;
- return globals_.append(g);
- }
- bool addGlobalConstant(double value, PropertyName* name) {
- MOZ_ASSERT(!isFinished());
- Global g(Global::Constant, name);
- g.pod.u.constant.value_ = value;
- g.pod.u.constant.kind_ = Global::GlobalConstant;
- return globals_.append(g);
- }
- // See Import comment above for FFI vs. Import.
- bool addImport(uint32_t ffiIndex, uint32_t importIndex) {
- MOZ_ASSERT(imports_.length() == importIndex);
- return imports_.emplaceBack(ffiIndex);
- }
- bool addExport(PropertyName* name, PropertyName* maybeFieldName, uint32_t begin, uint32_t end) {
- // The begin/end offsets are given relative to the ScriptSource (the
- // entire file) and ExportedFunctions store offsets relative to the
- // beginning of the module (so that they are caching-invariant).
- MOZ_ASSERT(!isFinished());
- MOZ_ASSERT(srcStart_ < begin);
- MOZ_ASSERT(begin < end);
- uint32_t startOffsetInModule = begin - srcStart_;
- uint32_t endOffsetInModule = end - srcStart_;
- return exports_.emplaceBack(name, maybeFieldName, startOffsetInModule, endOffsetInModule);
- }
-
- const GlobalVector& globals() const {
- return globals_;
- }
- const ImportVector& imports() const {
- return imports_;
- }
- const ExportVector& exports() const {
- return exports_;
- }
-
- void setViewsAreShared() {
- if (pod.hasArrayView_)
- pod.isSharedView_ = true;
- }
- bool hasArrayView() const {
- return pod.hasArrayView_;
- }
- bool isSharedView() const {
- return pod.isSharedView_;
- }
- void requireHeapLengthToBeAtLeast(uint32_t len) {
- MOZ_ASSERT(!isFinished());
- len = RoundUpToNextValidAsmJSHeapLength(len);
- if (len > pod.minHeapLength_)
- pod.minHeapLength_ = len;
- }
-
- /*************************************************************************/
- // A module isFinished() when compilation completes. After being finished,
- // a module must be statically and dynamically linked before execution.
-
- bool isFinished() const {
- return !!wasmModule_;
- }
- void finish(wasm::Module* wasmModule, wasm::UniqueStaticLinkData linkData,
- uint32_t endBeforeCurly, uint32_t endAfterCurly)
- {
- MOZ_ASSERT(!isFinished());
-
- wasmModule_.reset(wasmModule);
- linkData_ = Move(linkData);
-
- MOZ_ASSERT(endBeforeCurly >= srcBodyStart_);
- MOZ_ASSERT(endAfterCurly >= srcBodyStart_);
- pod.srcLength_ = endBeforeCurly - srcStart_;
- pod.srcLengthWithRightBrace_ = endAfterCurly - srcStart_;
-
- MOZ_ASSERT(isFinished());
- }
-
- /*************************************************************************/
- // These accessor functions can only be used after finish():
-
- wasm::Module& wasmModule() const {
- MOZ_ASSERT(isFinished());
- return *wasmModule_;
- }
- uint32_t numFFIs() const {
- MOZ_ASSERT(isFinished());
- return pod.numFFIs_;
- }
- uint32_t srcEndBeforeCurly() const {
- MOZ_ASSERT(isFinished());
- return srcStart_ + pod.srcLength_;
- }
- uint32_t srcEndAfterCurly() const {
- MOZ_ASSERT(isFinished());
- return srcStart_ + pod.srcLengthWithRightBrace_;
- }
+ return data_->srcBodyStart;
+ }
+
bool staticallyLink(ExclusiveContext* cx) {
- return wasmModule_->staticallyLink(cx, *linkData_);
- }
-
- // See WASM_DECLARE_SERIALIZABLE.
+ return Module::staticallyLink(cx, *linkData_);
+ }
+
+ // Clone this AsmJSModule into a new AsmJSModule that isn't statically or
+ // dynamically linked for cases where a single asm.js module function is
+ // linked several times.
+ bool clone(JSContext* cx, MutableHandleWasmModule moduleObj) const;
+
+ // These are the top-level serialization functions used by caching to
+ // cache an AsmJSModule.
size_t serializedSize() const;
uint8_t* serialize(uint8_t* cursor) const;
- const uint8_t* deserialize(ExclusiveContext* cx, const uint8_t* cursor);
- bool clone(JSContext* cx, HandleAsmJSModule moduleObj) const;
- void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
-};
-
-static void
-AsmJSModuleObject_finalize(FreeOp* fop, JSObject* obj)
-{
- AsmJSModuleObject& moduleObj = obj->as<AsmJSModuleObject>();
- if (moduleObj.hasModule())
- fop->delete_(&moduleObj.module());
-}
-
-static void
-AsmJSModuleObject_trace(JSTracer* trc, JSObject* obj)
-{
- AsmJSModuleObject& moduleObj = obj->as<AsmJSModuleObject>();
- if (moduleObj.hasModule())
- moduleObj.module().trace(trc);
-}
-
-const Class AsmJSModuleObject::class_ = {
- "AsmJSModuleObject",
- JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_CALLBACK |
- JSCLASS_HAS_RESERVED_SLOTS(AsmJSModuleObject::RESERVED_SLOTS),
- nullptr, /* addProperty */
- nullptr, /* delProperty */
- nullptr, /* getProperty */
- nullptr, /* setProperty */
- nullptr, /* enumerate */
- nullptr, /* resolve */
- nullptr, /* mayResolve */
- AsmJSModuleObject_finalize,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- AsmJSModuleObject_trace
+ static const uint8_t* deserialize(ExclusiveContext* cx, const uint8_t* cursor,
+ AsmJSParser& parser, MutableHandleWasmModule moduleObj);
+
+ // This function is called for memory reporting and Overrides
+ // Module::addSizeOfMisc() to add extra memory used for asm.js.
+ virtual void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data) override;
};
-static AsmJSModuleObject*
-NewAsmJSModuleObject(ExclusiveContext* cx)
-{
- AutoSetNewObjectMetadata metadata(cx);
- JSObject* obj = NewObjectWithGivenProto(cx, &AsmJSModuleObject::class_, nullptr);
- if (!obj)
- return nullptr;
-
- return &obj->as<AsmJSModuleObject>();
-}
-
-bool
-AsmJSModuleObject::hasModule() const
-{
- MOZ_ASSERT(is<AsmJSModuleObject>());
- return !getReservedSlot(MODULE_SLOT).isUndefined();
-}
-
-void
-AsmJSModuleObject::setModule(AsmJSModule* newModule)
-{
- MOZ_ASSERT(is<AsmJSModuleObject>());
- if (hasModule())
- js_delete(&module());
- setReservedSlot(MODULE_SLOT, PrivateValue(newModule));
-}
-
-AsmJSModule&
-AsmJSModuleObject::module() const
-{
- MOZ_ASSERT(is<AsmJSModuleObject>());
- return *(AsmJSModule*)getReservedSlot(MODULE_SLOT).toPrivate();
-}
-
-void
-AsmJSModuleObject::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
-{
- if (hasModule())
- module().addSizeOfMisc(mallocSizeOf, code, data);
-}
-
/*****************************************************************************/
// ParseNode utilities
static inline ParseNode*
NextNode(ParseNode* pn)
{
return pn->pn_next;
}
@@ -1241,17 +1007,17 @@ class NumLit
MOZ_ASSERT(which_ != OutOfRangeInt);
return u.scalar_;
}
bool isSimd() const {
return which_ == Int32x4 || which_ == Float32x4 || which_ == Bool32x4;
}
- const jit::SimdConstant& simdValue() const {
+ const SimdConstant& simdValue() const {
MOZ_ASSERT(isSimd());
return u.simd_;
}
bool valid() const {
return which_ != OutOfRangeInt;
}
@@ -1575,18 +1341,16 @@ class Type
case Void: return "void";
}
MOZ_CRASH("Invalid Type");
}
};
static const unsigned VALIDATION_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
-namespace {
-
// The ModuleValidator encapsulates the entire validation of an asm.js module.
// Its lifetime goes from the validation of the top components of an asm.js
// module (all the globals), the emission of bytecode for all the functions in
// the module and the validation of function's pointer tables. It also finishes
// the compilation of all the module's stubs.
//
// Rooting note: ModuleValidator is a stack class that contains unrooted
// PropertyName (JSAtom) pointers. This is safe because it cannot be
@@ -1839,87 +1603,45 @@ class MOZ_STACK_CLASS ModuleValidator
};
private:
typedef HashMap<PropertyName*, Global*> GlobalMap;
typedef HashMap<PropertyName*, MathBuiltin> MathNameMap;
typedef HashMap<PropertyName*, AsmJSAtomicsBuiltinFunction> AtomicsNameMap;
typedef HashMap<PropertyName*, AsmJSSimdOperation> SimdOperationNameMap;
typedef Vector<ArrayView> ArrayViewVector;
-
- public:
typedef HashMap<ImportDescriptor, unsigned, ImportDescriptor> ImportMap;
- private:
- ExclusiveContext* cx_;
- AsmJSParser& parser_;
-
- ModuleGenerator mg_;
- AsmJSModule* module_;
-
- LifoAlloc validationLifo_;
- FuncVector functions_;
- FuncPtrTableVector funcPtrTables_;
- GlobalMap globals_;
- ArrayViewVector arrayViews_;
- ImportMap imports_;
-
- MathNameMap standardLibraryMathNames_;
- AtomicsNameMap standardLibraryAtomicsNames_;
- SimdOperationNameMap standardLibrarySimdOpNames_;
-
- ParseNode* moduleFunctionNode_;
- PropertyName* moduleFunctionName_;
-
- UniqueChars errorString_;
- uint32_t errorOffset_;
- bool errorOverRecursed_;
-
- bool supportsSimd_;
- bool atomicsPresent_;
-
- public:
- ModuleValidator(ExclusiveContext* cx, AsmJSParser& parser)
- : cx_(cx),
- parser_(parser),
- mg_(cx),
- validationLifo_(VALIDATION_LIFO_DEFAULT_CHUNK_SIZE),
- functions_(cx),
- funcPtrTables_(cx),
- globals_(cx),
- arrayViews_(cx),
- imports_(cx),
- standardLibraryMathNames_(cx),
- standardLibraryAtomicsNames_(cx),
- standardLibrarySimdOpNames_(cx),
- moduleFunctionNode_(parser.pc->maybeFunction),
- moduleFunctionName_(nullptr),
- errorString_(nullptr),
- errorOffset_(UINT32_MAX),
- errorOverRecursed_(false),
- supportsSimd_(cx->jitSupportsSimd()),
- atomicsPresent_(false)
- {
- MOZ_ASSERT(moduleFunctionNode_->pn_funbox == parser.pc->sc->asFunctionBox());
- }
-
- ~ModuleValidator() {
- if (errorString_) {
- MOZ_ASSERT(errorOffset_ != UINT32_MAX);
- tokenStream().reportAsmJSError(errorOffset_,
- JSMSG_USE_ASM_TYPE_FAIL,
- errorString_.get());
- }
- if (errorOverRecursed_)
- ReportOverRecursed(cx_);
- }
-
- private:
-
- // Helpers
+ ExclusiveContext* cx_;
+ AsmJSParser& parser_;
+ ParseNode* moduleFunctionNode_;
+ PropertyName* moduleFunctionName_;
+ MathNameMap standardLibraryMathNames_;
+ AtomicsNameMap standardLibraryAtomicsNames_;
+ SimdOperationNameMap standardLibrarySimdOpNames_;
+
+ // Validation-internal state:
+ LifoAlloc validationLifo_;
+ FuncVector functions_;
+ FuncPtrTableVector funcPtrTables_;
+ GlobalMap globalMap_;
+ ImportMap importMap_;
+ ArrayViewVector arrayViews_;
+ bool atomicsPresent_;
+
+ // State used to build the AsmJSModule in finish():
+ ModuleGenerator mg_;
+ UniqueAsmJSModuleData moduleData_;
+
+ // Error reporting:
+ UniqueChars errorString_;
+ uint32_t errorOffset_;
+ bool errorOverRecursed_;
+
+ // Helpers:
bool addStandardLibraryMathName(const char* name, AsmJSMathBuiltinFunction func) {
JSAtom* atom = Atomize(cx_, name, strlen(name));
if (!atom)
return false;
MathBuiltin builtin(func);
return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin);
}
bool addStandardLibraryMathName(const char* name, double cst) {
@@ -1938,19 +1660,62 @@ class MOZ_STACK_CLASS ModuleValidator
bool addStandardLibrarySimdOpName(const char* name, AsmJSSimdOperation op) {
JSAtom* atom = Atomize(cx_, name, strlen(name));
if (!atom)
return false;
return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op);
}
public:
-
- bool init(HandleAsmJSModule moduleObj) {
- if (!globals_.init() || !imports_.init())
+ ModuleValidator(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* moduleFunctionNode)
+ : cx_(cx),
+ parser_(parser),
+ moduleFunctionNode_(moduleFunctionNode),
+ moduleFunctionName_(FunctionName(moduleFunctionNode)),
+ standardLibraryMathNames_(cx),
+ standardLibraryAtomicsNames_(cx),
+ standardLibrarySimdOpNames_(cx),
+ validationLifo_(VALIDATION_LIFO_DEFAULT_CHUNK_SIZE),
+ functions_(cx),
+ funcPtrTables_(cx),
+ globalMap_(cx),
+ importMap_(cx),
+ arrayViews_(cx),
+ atomicsPresent_(false),
+ mg_(cx),
+ errorString_(nullptr),
+ errorOffset_(UINT32_MAX),
+ errorOverRecursed_(false)
+ {
+
+ }
+
+ ~ModuleValidator() {
+ if (errorString_) {
+ MOZ_ASSERT(errorOffset_ != UINT32_MAX);
+ tokenStream().reportAsmJSError(errorOffset_,
+ JSMSG_USE_ASM_TYPE_FAIL,
+ errorString_.get());
+ }
+ if (errorOverRecursed_)
+ ReportOverRecursed(cx_);
+ }
+
+ bool init() {
+ moduleData_ = cx_->make_unique<AsmJSModuleData>();
+ if (!moduleData_)
+ return false;
+
+ moduleData_->pod.minHeapLength = RoundUpToNextValidAsmJSHeapLength(0);
+ moduleData_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
+ moduleData_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
+ moduleData_->strict = parser_.pc->sc->strict() && !parser_.pc->sc->hasExplicitUseStrict();
+ moduleData_->scriptSource.reset(parser_.ss);
+
+ if (!globalMap_.init() || !importMap_.init())
return false;
if (!standardLibraryMathNames_.init() ||
!addStandardLibraryMathName("sin", AsmJSMathBuiltin_sin) ||
!addStandardLibraryMathName("cos", AsmJSMathBuiltin_cos) ||
!addStandardLibraryMathName("tan", AsmJSMathBuiltin_tan) ||
!addStandardLibraryMathName("asin", AsmJSMathBuiltin_asin) ||
!addStandardLibraryMathName("acos", AsmJSMathBuiltin_acos) ||
@@ -1999,216 +1764,243 @@ class MOZ_STACK_CLASS ModuleValidator
#define ADDSTDLIBSIMDOPNAME(op) || !addStandardLibrarySimdOpName(#op, AsmJSSimdOperation_##op)
if (!standardLibrarySimdOpNames_.init()
FORALL_SIMD_ASMJS_OP(ADDSTDLIBSIMDOPNAME))
{
return false;
}
#undef ADDSTDLIBSIMDOPNAME
- uint32_t srcStart = parser_.pc->maybeFunction->pn_body->pn_pos.begin;
- uint32_t srcBodyStart = tokenStream().currentToken().pos.end;
-
- // "use strict" should be added to the source if we are in an implicit
- // strict context, see also comment above addUseStrict in
- // js::FunctionToString.
- bool strict = parser_.pc->sc->strict() && !parser_.pc->sc->hasExplicitUseStrict();
-
- module_ = cx_->new_<AsmJSModule>(parser_.ss, srcStart, srcBodyStart, strict);
- if (!module_)
- return false;
-
- moduleObj->setModule(module_);
-
return mg_.init();
}
- bool finish(SlowFunctionVector* slowFuncs) {
- uint32_t endBeforeCurly = tokenStream().currentToken().pos.end;
- TokenPos pos;
- JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
- uint32_t endAfterCurly = pos.end;
-
- HeapUsage heapUsage = module_->hasArrayView()
- ? module_->isSharedView()
- ? HeapUsage::Shared
- : HeapUsage::Unshared
- : HeapUsage::None;
-
- auto mutedErrors = Module::MutedBool(parser_.ss->mutedErrors());
-
- CacheableChars filename;
- if (parser_.ss->filename()) {
- filename = make_string_copy(parser_.ss->filename());
- if (!filename)
- return false;
- }
-
- CacheableTwoByteChars displayURL;
- if (parser_.ss->hasDisplayURL()) {
- uint32_t length = js_strlen(parser_.ss->displayURL());
- displayURL.reset(js_pod_calloc<char16_t>(length + 1));
- if (!displayURL)
- return false;
- PodCopy(displayURL.get(), parser_.ss->displayURL(), length);
- }
-
- UniqueStaticLinkData linkData;
- Module* wasm = mg_.finish(heapUsage, mutedErrors, Move(filename), Move(displayURL),
- &linkData, slowFuncs);
- if (!wasm)
- return false;
-
- module_->finish(wasm, Move(linkData), endBeforeCurly, endAfterCurly);
- return true;
- }
-
- // Mutable interface.
- void initModuleFunctionName(PropertyName* name) { moduleFunctionName_ = name; }
- void initGlobalArgumentName(PropertyName* n) { module().initGlobalArgumentName(n); }
- void initImportArgumentName(PropertyName* n) { module().initImportArgumentName(n); }
- void initBufferArgumentName(PropertyName* n) { module().initBufferArgumentName(n); }
-
+ ExclusiveContext* cx() const { return cx_; }
+ PropertyName* moduleFunctionName() const { return moduleFunctionName_; }
+ PropertyName* globalArgumentName() const { return moduleData_->globalArgumentName; }
+ PropertyName* importArgumentName() const { return moduleData_->importArgumentName; }
+ PropertyName* bufferArgumentName() const { return moduleData_->bufferArgumentName; }
+ ModuleGenerator& mg() { return mg_; }
+ AsmJSParser& parser() const { return parser_; }
+ TokenStream& tokenStream() const { return parser_.tokenStream; }
+ bool supportsSimd() const { return cx_->jitSupportsSimd(); }
+ bool atomicsPresent() const { return atomicsPresent_; }
+ uint32_t minHeapLength() const { return moduleData_->pod.minHeapLength; }
+
+ void initModuleFunctionName(PropertyName* name) {
+ MOZ_ASSERT(!moduleFunctionName_);
+ moduleFunctionName_ = name;
+ }
+ void initGlobalArgumentName(PropertyName* n) {
+ MOZ_ASSERT(n->isTenured());
+ moduleData_->globalArgumentName = n;
+ }
+ void initImportArgumentName(PropertyName* n) {
+ MOZ_ASSERT(n->isTenured());
+ moduleData_->importArgumentName = n;
+ }
+ void initBufferArgumentName(PropertyName* n) {
+ MOZ_ASSERT(n->isTenured());
+ moduleData_->bufferArgumentName = n;
+ }
bool addGlobalVarInit(PropertyName* var, const NumLit& lit, bool isConst) {
uint32_t globalDataOffset;
if (!mg_.allocateGlobalVar(lit.type(), &globalDataOffset))
return false;
+
Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable;
Global* global = validationLifo_.new_<Global>(which);
if (!global)
return false;
global->u.varOrConst.globalDataOffset_ = globalDataOffset;
global->u.varOrConst.type_ = (isConst ? Type::lit(lit) : Type::var(lit.type())).which();
if (isConst)
global->u.varOrConst.literalValue_ = lit;
- return globals_.putNew(var, global) &&
- module().addGlobalVarInit(lit.value(), globalDataOffset);
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::Variable, nullptr);
+ g.pod.u.var.initKind_ = AsmJSGlobal::InitConstant;
+ g.pod.u.var.u.val_ = lit.value();
+ g.pod.u.var.globalDataOffset_ = globalDataOffset;
+ return moduleData_->globals.append(g);
}
bool addGlobalVarImport(PropertyName* var, PropertyName* field, ValType type, bool isConst) {
uint32_t globalDataOffset;
if (!mg_.allocateGlobalVar(type, &globalDataOffset))
return false;
+
Global::Which which = isConst ? Global::ConstantImport : Global::Variable;
Global* global = validationLifo_.new_<Global>(which);
if (!global)
return false;
global->u.varOrConst.globalDataOffset_ = globalDataOffset;
global->u.varOrConst.type_ = Type::var(type).which();
- return globals_.putNew(var, global) &&
- module().addGlobalVarImport(field, type, globalDataOffset);
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::Variable, field);
+ g.pod.u.var.initKind_ = AsmJSGlobal::InitImport;
+ g.pod.u.var.u.importType_ = type;
+ g.pod.u.var.globalDataOffset_ = globalDataOffset;
+ return moduleData_->globals.append(g);
}
bool addArrayView(PropertyName* var, Scalar::Type vt, PropertyName* maybeField) {
if (!arrayViews_.append(ArrayView(var, vt)))
return false;
+
Global* global = validationLifo_.new_<Global>(Global::ArrayView);
if (!global)
return false;
global->u.viewInfo.viewType_ = vt;
- return globals_.putNew(var, global) &&
- module().addArrayView(vt, maybeField);
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::ArrayView, maybeField);
+ g.pod.u.viewType_ = vt;
+ return moduleData_->globals.append(g);
}
bool addMathBuiltinFunction(PropertyName* var, AsmJSMathBuiltinFunction func,
PropertyName* field)
{
Global* global = validationLifo_.new_<Global>(Global::MathBuiltinFunction);
if (!global)
return false;
global->u.mathBuiltinFunc_ = func;
- return globals_.putNew(var, global) &&
- module().addMathBuiltinFunction(func, field);
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::MathBuiltinFunction, field);
+ g.pod.u.mathBuiltinFunc_ = func;
+ return moduleData_->globals.append(g);
}
private:
bool addGlobalDoubleConstant(PropertyName* var, double constant) {
Global* global = validationLifo_.new_<Global>(Global::ConstantLiteral);
if (!global)
return false;
global->u.varOrConst.type_ = Type::Double;
global->u.varOrConst.literalValue_ = NumLit(NumLit::Double, DoubleValue(constant));
- return globals_.putNew(var, global);
+ return globalMap_.putNew(var, global);
}
public:
bool addMathBuiltinConstant(PropertyName* var, double constant, PropertyName* field) {
- return addGlobalDoubleConstant(var, constant) &&
- module().addMathBuiltinConstant(constant, field);
+ if (!addGlobalDoubleConstant(var, constant))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::Constant, field);
+ g.pod.u.constant.value_ = constant;
+ g.pod.u.constant.kind_ = AsmJSGlobal::MathConstant;
+ return moduleData_->globals.append(g);
}
bool addGlobalConstant(PropertyName* var, double constant, PropertyName* field) {
- return addGlobalDoubleConstant(var, constant) &&
- module().addGlobalConstant(constant, field);
+ if (!addGlobalDoubleConstant(var, constant))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::Constant, field);
+ g.pod.u.constant.value_ = constant;
+ g.pod.u.constant.kind_ = AsmJSGlobal::GlobalConstant;
+ return moduleData_->globals.append(g);
}
bool addAtomicsBuiltinFunction(PropertyName* var, AsmJSAtomicsBuiltinFunction func,
PropertyName* field)
{
+ atomicsPresent_ = true;
+
Global* global = validationLifo_.new_<Global>(Global::AtomicsBuiltinFunction);
if (!global)
return false;
- atomicsPresent_ = true;
global->u.atomicsBuiltinFunc_ = func;
- return globals_.putNew(var, global) &&
- module().addAtomicsBuiltinFunction(func, field);
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::AtomicsBuiltinFunction, field);
+ g.pod.u.atomicsBuiltinFunc_ = func;
+ return moduleData_->globals.append(g);
}
bool addSimdCtor(PropertyName* var, AsmJSSimdType type, PropertyName* field) {
Global* global = validationLifo_.new_<Global>(Global::SimdCtor);
if (!global)
return false;
global->u.simdCtorType_ = type;
- return globals_.putNew(var, global) &&
- module().addSimdCtor(type, field);
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::SimdCtor, field);
+ g.pod.u.simdCtorType_ = type;
+ return moduleData_->globals.append(g);
}
bool addSimdOperation(PropertyName* var, AsmJSSimdType type, AsmJSSimdOperation op,
PropertyName* opName)
{
Global* global = validationLifo_.new_<Global>(Global::SimdOperation);
if (!global)
return false;
global->u.simdOp.type_ = type;
global->u.simdOp.which_ = op;
- return globals_.putNew(var, global) &&
- module().addSimdOperation(type, op, opName);
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::SimdOperation, opName);
+ g.pod.u.simdOp.type_ = type;
+ g.pod.u.simdOp.which_ = op;
+ return moduleData_->globals.append(g);
}
bool addArrayViewCtor(PropertyName* var, Scalar::Type vt, PropertyName* field) {
Global* global = validationLifo_.new_<Global>(Global::ArrayViewCtor);
if (!global)
return false;
global->u.viewInfo.viewType_ = vt;
- return globals_.putNew(var, global) &&
- module().addArrayViewCtor(vt, field);
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::ArrayViewCtor, field);
+ g.pod.u.viewType_ = vt;
+ return moduleData_->globals.append(g);
}
bool addFFI(PropertyName* var, PropertyName* field) {
+ if (moduleData_->pod.numFFIs == UINT32_MAX)
+ return false;
+ uint32_t ffiIndex = moduleData_->pod.numFFIs++;
+
Global* global = validationLifo_.new_<Global>(Global::FFI);
if (!global)
return false;
- uint32_t index;
- if (!module().addFFI(field, &index))
- return false;
- global->u.ffiIndex_ = index;
- return globals_.putNew(var, global);
+ global->u.ffiIndex_ = ffiIndex;
+ if (!globalMap_.putNew(var, global))
+ return false;
+
+ AsmJSGlobal g(AsmJSGlobal::FFI, field);
+ g.pod.u.ffiIndex_ = ffiIndex;
+ return moduleData_->globals.append(g);
}
bool addExport(ParseNode* pn, const Func& func, PropertyName* maybeFieldName) {
MallocSig::ArgVector args;
if (!args.appendAll(func.sig().args()))
return false;
MallocSig sig(Move(args), func.sig().ret());
return mg_.declareExport(Move(sig), func.index()) &&
- module().addExport(func.name(), maybeFieldName, func.srcBegin(), func.srcEnd());
+ moduleData_->exports.emplaceBack(func.name(), maybeFieldName,
+ func.srcBegin() - moduleData_->srcStart,
+ func.srcEnd() - moduleData_->srcStart);
}
private:
const LifoSig* getLifoSig(const LifoSig& sig) {
return &sig;
}
const LifoSig* getLifoSig(const MallocSig& sig) {
return mg_.newLifoSig(sig);
}
public:
bool addFunction(PropertyName* name, uint32_t firstUse, const MallocSig& sig, Func** func) {
uint32_t funcIndex = numFunctions();
Global* global = validationLifo_.new_<Global>(Global::Function);
if (!global)
return false;
global->u.funcIndex_ = funcIndex;
- if (!globals_.putNew(name, global))
+ if (!globalMap_.putNew(name, global))
return false;
const LifoSig* lifoSig = getLifoSig(sig);
if (!lifoSig)
return false;
*func = validationLifo_.new_<Func>(name, firstUse, *lifoSig, funcIndex);
return *func && functions_.append(*func);
}
template <class SigT>
@@ -2217,17 +2009,17 @@ class MOZ_STACK_CLASS ModuleValidator
{
if (!mg_.declareFuncPtrTable(/* numElems = */ mask + 1, index))
return false;
MOZ_ASSERT(*index == numFuncPtrTables());
Global* global = validationLifo_.new_<Global>(Global::FuncPtrTable);
if (!global)
return false;
global->u.funcPtrTableIndex_ = *index;
- if (!globals_.putNew(name, global))
+ if (!globalMap_.putNew(name, global))
return false;
const LifoSig* lifoSig = getLifoSig(sig);
if (!lifoSig)
return false;
FuncPtrTable* t = validationLifo_.new_<FuncPtrTable>(cx_, name, firstUse, *lifoSig, mask);
return t && funcPtrTables_.append(t);
}
bool defineFuncPtrTable(uint32_t funcPtrTableIndex, const Vector<uint32_t>& elems) {
@@ -2237,43 +2029,44 @@ class MOZ_STACK_CLASS ModuleValidator
table.define();
mg_.defineFuncPtrTable(funcPtrTableIndex, elems);
return true;
}
bool addImport(PropertyName* name, MallocSig&& sig, unsigned ffiIndex, unsigned* importIndex,
const LifoSig** lifoSig)
{
ImportDescriptor::Lookup lookup(name, sig);
- ImportMap::AddPtr p = imports_.lookupForAdd(lookup);
+ ImportMap::AddPtr p = importMap_.lookupForAdd(lookup);
if (p) {
*lifoSig = &p->key().sig();
*importIndex = p->value();
return true;
}
*lifoSig = getLifoSig(sig);
if (!*lifoSig)
return false;
- return mg_.declareImport(Move(sig), importIndex) &&
- imports_.add(p, ImportDescriptor(name, **lifoSig), *importIndex) &&
- module().addImport(ffiIndex, *importIndex);
+ if (!mg_.declareImport(Move(sig), importIndex))
+ return false;
+ if (!importMap_.add(p, ImportDescriptor(name, **lifoSig), *importIndex))
+ return false;
+ MOZ_ASSERT(moduleData_->imports.length() == *importIndex);
+ return moduleData_->imports.emplaceBack(ffiIndex);
}
bool tryConstantAccess(uint64_t start, uint64_t width) {
MOZ_ASSERT(UINT64_MAX - start > width);
- uint64_t end = start + width;
- if (end > uint64_t(INT32_MAX) + 1)
- return false;
- module().requireHeapLengthToBeAtLeast(end);
+ uint64_t len = start + width;
+ if (len > uint64_t(INT32_MAX) + 1)
+ return false;
+ len = RoundUpToNextValidAsmJSHeapLength(len);
+ if (len > moduleData_->pod.minHeapLength)
+ moduleData_->pod.minHeapLength = len;
return true;
}
- bool usesSharedMemory() const {
- return atomicsPresent_;
- }
-
// Error handling.
bool hasAlreadyFailed() const {
return !!errorString_;
}
bool failOffset(uint32_t offset, const char* str) {
MOZ_ASSERT(!hasAlreadyFailed());
MOZ_ASSERT(errorOffset_ == UINT32_MAX);
@@ -2325,26 +2118,16 @@ class MOZ_STACK_CLASS ModuleValidator
return failNameOffset(pn->pn_pos.begin, fmt, name);
}
bool failOverRecursed() {
errorOverRecursed_ = true;
return false;
}
- // Read-only interface
- ExclusiveContext* cx() const { return cx_; }
- ParseNode* moduleFunctionNode() const { return moduleFunctionNode_; }
- PropertyName* moduleFunctionName() const { return moduleFunctionName_; }
- ModuleGenerator& mg() { return mg_; }
- AsmJSModule& module() const { return *module_; }
- AsmJSParser& parser() const { return parser_; }
- TokenStream& tokenStream() const { return parser_.tokenStream; }
- bool supportsSimd() const { return supportsSimd_; }
-
unsigned numArrayViews() const {
return arrayViews_.length();
}
const ArrayView& arrayView(unsigned i) const {
return arrayViews_[i];
}
unsigned numFunctions() const {
return functions_.length();
@@ -2355,23 +2138,23 @@ class MOZ_STACK_CLASS ModuleValidator
unsigned numFuncPtrTables() const {
return funcPtrTables_.length();
}
FuncPtrTable& funcPtrTable(unsigned i) const {
return *funcPtrTables_[i];
}
const Global* lookupGlobal(PropertyName* name) const {
- if (GlobalMap::Ptr p = globals_.lookup(name))
+ if (GlobalMap::Ptr p = globalMap_.lookup(name))
return p->value();
return nullptr;
}
Func* lookupFunction(PropertyName* name) {
- if (GlobalMap::Ptr p = globals_.lookup(name)) {
+ if (GlobalMap::Ptr p = globalMap_.lookup(name)) {
Global* value = p->value();
if (value->which() == Global::Function)
return functions_[value->funcIndex()];
}
return nullptr;
}
bool lookupStandardLibraryMathName(PropertyName* name, MathBuiltin* mathBuiltin) const {
@@ -2393,32 +2176,86 @@ class MOZ_STACK_CLASS ModuleValidator
*op = p->value();
return true;
}
return false;
}
bool startFunctionBodies() {
if (atomicsPresent_) {
-#if defined(ENABLE_SHARED_ARRAY_BUFFER)
- module().setViewsAreShared();
-#else
+#if !defined(ENABLE_SHARED_ARRAY_BUFFER)
return failOffset(parser_.tokenStream.currentToken().pos.begin,
"shared memory and atomics not supported by this build");
#endif
}
return true;
}
bool finishFunctionBodies() {
return mg_.finishFuncs();
}
+ bool finish(MutableHandleWasmModule moduleObj, SlowFunctionVector* slowFuncs) {
+ moduleObj.set(WasmModuleObject::create(cx_));
+ if (!moduleObj)
+ return false;
+
+ HeapUsage heapUsage = arrayViews_.empty()
+ ? HeapUsage::None
+ : atomicsPresent_
+ ? HeapUsage::Shared
+ : HeapUsage::Unshared;
+
+ auto mutedErrors = MutedErrorsBool(parser_.ss->mutedErrors());
+
+ CacheableChars filename;
+ if (parser_.ss->filename()) {
+ filename = make_string_copy(parser_.ss->filename());
+ if (!filename)
+ return false;
+ }
+
+ CacheableTwoByteChars displayURL;
+ if (parser_.ss->hasDisplayURL()) {
+ uint32_t length = js_strlen(parser_.ss->displayURL());
+ displayURL.reset(js_pod_calloc<char16_t>(length + 1));
+ if (!displayURL)
+ return false;
+ PodCopy(displayURL.get(), parser_.ss->displayURL(), length);
+ }
+
+
+ uint32_t endBeforeCurly = tokenStream().currentToken().pos.end;
+ moduleData_->pod.srcLength = endBeforeCurly - moduleData_->srcStart;
+
+ TokenPos pos;
+ JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
+ uint32_t endAfterCurly = pos.end;
+ moduleData_->pod.srcLengthWithRightBrace = endAfterCurly - moduleData_->srcStart;
+
+ UniqueModuleData baseData;
+ UniqueStaticLinkData linkData;
+ if (!mg_.finish(heapUsage,
+ mutedErrors,
+ Move(filename),
+ Move(displayURL),
+ &baseData,
+ &linkData,
+ slowFuncs))
+ {
+ return false;
+ }
+
+ auto module = cx_->make_unique<AsmJSModule>(Move(baseData), Move(linkData), Move(moduleData_));
+ if (!module)
+ return false;
+
+ moduleObj->initModule(Move(module));
+ return true;
+ }
};
-} // namespace
-
/*****************************************************************************/
// Numeric literal utilities
static bool
IsNumericNonFloatLiteral(ParseNode* pn)
{
// Note: '-' is never rolled into the number; numbers are always positive
// and negations must be applied manually.
@@ -2742,17 +2579,16 @@ class MOZ_STACK_CLASS FunctionValidator
: m_(m),
fn_(fn),
locals_(m.cx()),
labels_(m.cx()),
hasAlreadyReturned_(false)
{}
ModuleValidator& m() const { return m_; }
- const AsmJSModule& module() const { return m_.module(); }
FuncIR& funcIR() const { return fg_.func(); }
ExclusiveContext* cx() const { return m_.cx(); }
ParseNode* fn() const { return fn_; }
bool init(PropertyName* name, unsigned line, unsigned column) {
return locals_.init() &&
labels_.init() &&
m_.mg().startFunc(name, line, column, &fg_);
@@ -2966,19 +2802,19 @@ CheckIdentifier(ModuleValidator& m, Pars
static bool
CheckModuleLevelName(ModuleValidator& m, ParseNode* usepn, PropertyName* name)
{
if (!CheckIdentifier(m, usepn, name))
return false;
if (name == m.moduleFunctionName() ||
- name == m.module().globalArgumentName() ||
- name == m.module().importArgumentName() ||
- name == m.module().bufferArgumentName() ||
+ name == m.globalArgumentName() ||
+ name == m.importArgumentName() ||
+ name == m.bufferArgumentName() ||
m.lookupGlobal(name))
{
return m.failName(usepn, "duplicate name '%s' not allowed", name);
}
return true;
}
@@ -3113,17 +2949,17 @@ CheckGlobalVariableImportExpr(ModuleVali
ParseNode* coercedExpr, bool isConst)
{
if (!coercedExpr->isKind(PNK_DOT))
return m.failName(coercedExpr, "invalid import expression for global '%s'", varName);
ParseNode* base = DotBase(coercedExpr);
PropertyName* field = DotMember(coercedExpr);
- PropertyName* importName = m.module().importArgumentName();
+ PropertyName* importName = m.importArgumentName();
if (!importName)
return m.fail(coercedExpr, "cannot import without an asm.js foreign parameter");
if (!IsUseOfName(base, importName))
return m.failName(coercedExpr, "base of import expression must be '%s'", importName);
return m.addGlobalVarImport(varName, field, coerceTo, isConst);
}
@@ -3175,21 +3011,21 @@ CheckNewArrayViewArgs(ModuleValidator& m
return m.failName(bufArg, "argument to array view constructor must be '%s'", bufferName);
return true;
}
static bool
CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
{
- PropertyName* globalName = m.module().globalArgumentName();
+ PropertyName* globalName = m.globalArgumentName();
if (!globalName)
return m.fail(newExpr, "cannot create array view without an asm.js global parameter");
- PropertyName* bufferName = m.module().bufferArgumentName();
+ PropertyName* bufferName = m.bufferArgumentName();
if (!bufferName)
return m.fail(newExpr, "cannot create array view without an asm.js heap parameter");
ParseNode* ctorExpr = ListHead(newExpr);
PropertyName* field;
Scalar::Type type;
if (ctorExpr->isKind(PNK_DOT)) {
@@ -3333,17 +3169,17 @@ CheckGlobalDotImport(ModuleValidator& m,
{
ParseNode* base = DotBase(initNode);
PropertyName* field = DotMember(initNode);
if (base->isKind(PNK_DOT)) {
ParseNode* global = DotBase(base);
PropertyName* mathOrAtomicsOrSimd = DotMember(base);
- PropertyName* globalName = m.module().globalArgumentName();
+ PropertyName* globalName = m.globalArgumentName();
if (!globalName)
return m.fail(base, "import statement requires the module have a stdlib parameter");
if (!IsUseOfName(global, globalName)) {
if (global->isKind(PNK_DOT)) {
return m.failName(base, "imports can have at most two dot accesses "
"(e.g. %s.Math.sin)", globalName);
}
@@ -3357,30 +3193,30 @@ CheckGlobalDotImport(ModuleValidator& m,
if (mathOrAtomicsOrSimd == m.cx()->names().SIMD)
return CheckGlobalSimdImport(m, initNode, varName, field);
return m.failName(base, "expecting %s.{Math|SIMD}", globalName);
}
if (!base->isKind(PNK_NAME))
return m.fail(base, "expected name of variable or parameter");
- if (base->name() == m.module().globalArgumentName()) {
+ if (base->name() == m.globalArgumentName()) {
if (field == m.cx()->names().NaN)
return m.addGlobalConstant(varName, GenericNaN(), field);
if (field == m.cx()->names().Infinity)
return m.addGlobalConstant(varName, PositiveInfinity<double>(), field);
Scalar::Type type;
if (IsArrayViewCtorName(m, field, &type))
return m.addArrayViewCtor(varName, type, field);
return m.failName(initNode, "'%s' is not a standard constant or typed array name", field);
}
- if (base->name() == m.module().importArgumentName())
+ if (base->name() == m.importArgumentName())
return m.addFFI(varName, field);
const ModuleValidator::Global* global = m.lookupGlobal(base->name());
if (!global)
return m.failName(initNode, "%s not found in module global scope", base->name());
if (!global->isSimdCtor())
return m.failName(base, "expecting SIMD constructor name, got %s", field);
@@ -3706,17 +3542,17 @@ FoldMaskedArrayIndex(FunctionValidator&
uint32_t mask2;
if (IsLiteralOrConstInt(f, maskNode, &mask2)) {
// Flag the access to skip the bounds check if the mask ensures that an
// 'out of bounds' access can not occur based on the current heap length
// constraint. The unsigned maximum of a masked index is the mask
// itself, so check that the mask is not negative and compare the mask
// to the known minimum heap length.
- if (int32_t(mask2) >= 0 && mask2 < f.m().module().minHeapLength())
+ if (int32_t(mask2) >= 0 && mask2 < f.m().minHeapLength())
*needsBoundsCheck = NO_BOUNDS_CHECK;
*mask &= mask2;
*indexExpr = indexNode;
return true;
}
return false;
}
@@ -4190,18 +4026,20 @@ CheckSharedArrayAtomicAccess(FunctionVal
{
if (!CheckAndPrepareArrayAccess(f, viewName, indexExpr, viewType, needsBoundsCheck, mask))
return false;
// Atomic accesses may be made on shared integer arrays only.
// The global will be sane, CheckArrayAccess checks it.
const ModuleValidator::Global* global = f.lookupGlobal(viewName->name());
- if (global->which() != ModuleValidator::Global::ArrayView || !f.m().module().isSharedView())
- return f.fail(viewName, "base of array access must be a shared typed array view name");
+ if (global->which() != ModuleValidator::Global::ArrayView)
+ return f.fail(viewName, "base of array access must be a typed array view");
+
+ MOZ_ASSERT(f.m().atomicsPresent());
switch (*viewType) {
case Scalar::Int8:
case Scalar::Int16:
case Scalar::Int32:
case Scalar::Uint8:
case Scalar::Uint16:
case Scalar::Uint32:
@@ -7191,35 +7029,32 @@ CheckModuleEnd(ModuleValidator &m)
"top-level export (return) must be the last statement");
}
m.parser().tokenStream.ungetToken();
return true;
}
static bool
-CheckModule(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList, HandleAsmJSModule obj,
- unsigned* time, SlowFunctionVector* slowFuncs)
+CheckModule(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList,
+ MutableHandleWasmModule moduleObj, unsigned* time, SlowFunctionVector* slowFuncs)
{
int64_t before = PRMJ_Now();
- ModuleValidator m(cx, parser);
- if (!m.init(obj))
- return false;
-
- if (PropertyName* moduleFunctionName = FunctionName(m.moduleFunctionNode())) {
- if (!CheckModuleLevelName(m, m.moduleFunctionNode(), moduleFunctionName))
- return false;
- m.initModuleFunctionName(moduleFunctionName);
- }
-
- if (!CheckFunctionHead(m, m.moduleFunctionNode()))
- return false;
-
- if (!CheckModuleArguments(m, m.moduleFunctionNode()))
+ ParseNode* moduleFunctionNode = parser.pc->maybeFunction;
+ MOZ_ASSERT(moduleFunctionNode);
+
+ ModuleValidator m(cx, parser, moduleFunctionNode);
+ if (!m.init())
+ return false;
+
+ if (!CheckFunctionHead(m, moduleFunctionNode))
+ return false;
+
+ if (!CheckModuleArguments(m, moduleFunctionNode))
return false;
if (!CheckPrecedingStatements(m, stmtList))
return false;
if (!CheckModuleProcessingDirectives(m))
return false;
@@ -7239,52 +7074,52 @@ CheckModule(ExclusiveContext* cx, AsmJSP
return false;
if (!CheckModuleReturn(m))
return false;
if (!CheckModuleEnd(m))
return false;
- if (!m.finish(slowFuncs))
+ if (!m.finish(moduleObj, slowFuncs))
return false;
*time = (PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC;
return true;
}
/*****************************************************************************/
// Link-time validation
-static AsmJSModuleObject&
+static WasmModuleObject&
FunctionToModuleObject(JSFunction* fun)
{
MOZ_ASSERT(IsAsmJSFunction(fun) || IsAsmJSModule(fun));
const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_MODULE_SLOT);
- return v.toObject().as<AsmJSModuleObject>();
+ return v.toObject().as<WasmModuleObject>();
}
static unsigned
FunctionToExportIndex(JSFunction* fun)
{
MOZ_ASSERT(IsAsmJSFunction(fun));
const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT);
return v.toInt32();
}
static bool
CallAsmJS(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction callee(cx, &args.callee().as<JSFunction>());
- AsmJSModule& module = FunctionToModuleObject(callee).module();
+ Module& module = FunctionToModuleObject(callee).module();
uint32_t exportIndex = FunctionToExportIndex(callee);
- return module.wasmModule().callExport(cx, exportIndex, args);
+ return module.callExport(cx, exportIndex, args);
}
static bool
LinkFail(JSContext* cx, const char* str)
{
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage,
nullptr, JSMSG_USE_ASM_LINK_FAIL, str);
return false;
@@ -7335,23 +7170,23 @@ HasPureCoercion(JSContext* cx, HandleVal
{
return true;
}
return false;
}
static bool
-ValidateGlobalVariable(JSContext* cx, const AsmJSModule::Global& global, uint8_t* globalData,
+ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, uint8_t* globalData,
HandleValue importVal)
{
void* datum = globalData + global.varGlobalDataOffset();
switch (global.varInitKind()) {
- case AsmJSModule::Global::InitConstant: {
+ case AsmJSGlobal::InitConstant: {
Val v = global.varInitVal();
switch (v.type()) {
case ValType::I32:
*(int32_t*)datum = v.i32();
break;
case ValType::I64:
MOZ_CRASH("int64");
case ValType::F32:
@@ -7367,17 +7202,17 @@ ValidateGlobalVariable(JSContext* cx, co
break;
case ValType::F32x4:
memcpy(datum, v.f32x4(), Simd128DataSize);
break;
}
break;
}
- case AsmJSModule::Global::InitImport: {
+ case AsmJSGlobal::InitImport: {
RootedPropertyName field(cx, global.varImportField());
RootedValue v(cx);
if (!GetDataProperty(cx, importVal, field, &v))
return false;
if (!v.isPrimitive() && !HasPureCoercion(cx, v))
return LinkFail(cx, "Imported values must be primitives");
@@ -7422,33 +7257,33 @@ ValidateGlobalVariable(JSContext* cx, co
break;
}
}
return true;
}
static bool
-ValidateFFI(JSContext* cx, const AsmJSModule::Global& global, HandleValue importVal,
+ValidateFFI(JSContext* cx, const AsmJSGlobal& global, HandleValue importVal,
AutoVectorRooter<JSFunction*>* ffis)
{
RootedPropertyName field(cx, global.ffiField());
RootedValue v(cx);
if (!GetDataProperty(cx, importVal, field, &v))
return false;
if (!v.isObject() || !v.toObject().is<JSFunction>())
return LinkFail(cx, "FFI imports must be functions");
(*ffis)[global.ffiIndex()].set(&v.toObject().as<JSFunction>());
return true;
}
static bool
-ValidateArrayView(JSContext* cx, const AsmJSModule::Global& global, HandleValue globalVal)
+ValidateArrayView(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
{
RootedPropertyName field(cx, global.maybeViewName());
if (!field)
return true;
RootedValue v(cx);
if (!GetDataProperty(cx, globalVal, field, &v))
return false;
@@ -7456,17 +7291,17 @@ ValidateArrayView(JSContext* cx, const A
bool tac = IsTypedArrayConstructor(v, global.viewType());
if (!tac)
return LinkFail(cx, "bad typed array constructor");
return true;
}
static bool
-ValidateMathBuiltinFunction(JSContext* cx, const AsmJSModule::Global& global, HandleValue globalVal)
+ValidateMathBuiltinFunction(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
{
RootedValue v(cx);
if (!GetDataProperty(cx, globalVal, cx->names().Math, &v))
return false;
RootedPropertyName field(cx, global.mathName());
if (!GetDataProperty(cx, v, field, &v))
return false;
@@ -7518,25 +7353,25 @@ AsmJSSimdTypeToTypeDescrType(AsmJSSimdTy
case AsmJSSimdType_int32x4: return Int32x4::type;
case AsmJSSimdType_float32x4: return Float32x4::type;
case AsmJSSimdType_bool32x4: return Bool32x4::type;
}
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected AsmJSSimdType");
}
static bool
-ValidateSimdType(JSContext* cx, const AsmJSModule::Global& global, HandleValue globalVal,
+ValidateSimdType(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal,
MutableHandleValue out)
{
RootedValue v(cx);
if (!GetDataProperty(cx, globalVal, cx->names().SIMD, &v))
return false;
AsmJSSimdType type;
- if (global.which() == AsmJSModule::Global::SimdCtor)
+ if (global.which() == AsmJSGlobal::SimdCtor)
type = global.simdCtorType();
else
type = global.simdOperationType();
RootedPropertyName simdTypeName(cx, SimdTypeToName(cx, type));
if (!GetDataProperty(cx, v, simdTypeName, &v))
return false;
@@ -7550,24 +7385,24 @@ ValidateSimdType(JSContext* cx, const As
if (AsmJSSimdTypeToTypeDescrType(type) != simdDesc->as<SimdTypeDescr>().type())
return LinkFail(cx, "bad SIMD type");
out.set(v);
return true;
}
static bool
-ValidateSimdType(JSContext* cx, const AsmJSModule::Global& global, HandleValue globalVal)
+ValidateSimdType(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
{
RootedValue _(cx);
return ValidateSimdType(cx, global, globalVal, &_);
}
static bool
-ValidateSimdOperation(JSContext* cx, const AsmJSModule::Global& global, HandleValue globalVal)
+ValidateSimdOperation(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
{
// SIMD operations are loaded from the SIMD type, so the type must have been
// validated before the operation.
RootedValue v(cx);
JS_ALWAYS_TRUE(ValidateSimdType(cx, global, globalVal, &v));
RootedPropertyName opName(cx, global.simdOperationName());
if (!GetDataProperty(cx, v, opName, &v))
@@ -7610,17 +7445,17 @@ ValidateSimdOperation(JSContext* cx, con
#undef SET_NATIVE
}
if (!native || !IsNativeFunction(v, native))
return LinkFail(cx, "bad SIMD.type.* operation");
return true;
}
static bool
-ValidateAtomicsBuiltinFunction(JSContext* cx, const AsmJSModule::Global& global, HandleValue globalVal)
+ValidateAtomicsBuiltinFunction(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
{
RootedValue v(cx);
if (!GetDataProperty(cx, globalVal, cx->names().Atomics, &v))
return false;
RootedPropertyName field(cx, global.atomicsName());
if (!GetDataProperty(cx, v, field, &v))
return false;
@@ -7641,22 +7476,22 @@ ValidateAtomicsBuiltinFunction(JSContext
if (!IsNativeFunction(v, native))
return LinkFail(cx, "bad Atomics.* builtin function");
return true;
}
static bool
-ValidateConstant(JSContext* cx, const AsmJSModule::Global& global, HandleValue globalVal)
+ValidateConstant(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
{
RootedPropertyName field(cx, global.constantName());
RootedValue v(cx, globalVal);
- if (global.constantKind() == AsmJSModule::Global::MathConstant) {
+ if (global.constantKind() == AsmJSGlobal::MathConstant) {
if (!GetDataProperty(cx, v, cx->names().Math, &v))
return false;
}
if (!GetDataProperty(cx, v, field, &v))
return false;
if (!v.isNumber())
@@ -7673,20 +7508,20 @@ ValidateConstant(JSContext* cx, const As
return true;
}
static bool
CheckBuffer(JSContext* cx, AsmJSModule& module, HandleValue bufferVal,
MutableHandle<ArrayBufferObjectMaybeShared*> buffer)
{
- if (module.isSharedView() && !IsSharedArrayBuffer(bufferVal))
+ if (module.hasSharedHeap() && !IsSharedArrayBuffer(bufferVal))
return LinkFail(cx, "shared views can only be constructed onto SharedArrayBuffer");
- if (!module.isSharedView() && !IsArrayBuffer(bufferVal))
+ if (!module.hasSharedHeap() && !IsArrayBuffer(bufferVal))
return LinkFail(cx, "unshared views can only be constructed onto ArrayBuffer");
buffer.set(&AsAnyArrayBuffer(bufferVal));
uint32_t heapLength = buffer->byteLength();
if (!IsValidAsmJSHeapLength(heapLength)) {
UniqueChars msg(
JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
@@ -7706,96 +7541,96 @@ CheckBuffer(JSContext* cx, AsmJSModule&
heapLength,
module.minHeapLength()));
return LinkFail(cx, msg.get());
}
// Shell builtins may have disabled signal handlers since the module we're
// cloning was compiled. LookupAsmJSModuleInCache checks for signal handlers
// as well for the caching case.
- if (module.wasmModule().compileArgs() != CompileArgs(cx))
+ if (module.compileArgs() != CompileArgs(cx))
return LinkFail(cx, "Signals have been toggled since compilation");
if (buffer->is<ArrayBufferObject>()) {
Rooted<ArrayBufferObject*> abheap(cx, &buffer->as<ArrayBufferObject>());
- bool useSignalHandlers = module.wasmModule().compileArgs().useSignalHandlersForOOB;
+ bool useSignalHandlers = module.compileArgs().useSignalHandlersForOOB;
if (!ArrayBufferObject::prepareForAsmJS(cx, abheap, useSignalHandlers))
return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use");
}
return true;
}
static bool
DynamicallyLinkModule(JSContext* cx, const CallArgs& args, AsmJSModule& module)
{
HandleValue globalVal = args.get(0);
HandleValue importVal = args.get(1);
HandleValue bufferVal = args.get(2);
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx);
- if (module.hasArrayView() && !CheckBuffer(cx, module, bufferVal, &buffer))
+ if (module.usesHeap() && !CheckBuffer(cx, module, bufferVal, &buffer))
return false;
AutoVectorRooter<JSFunction*> ffis(cx);
if (!ffis.resize(module.numFFIs()))
return false;
- for (const AsmJSModule::Global& global : module.globals()) {
+ for (const AsmJSGlobal& global : module.asmJSGlobals()) {
switch (global.which()) {
- case AsmJSModule::Global::Variable:
- if (!ValidateGlobalVariable(cx, global, module.wasmModule().globalData(), importVal))
+ case AsmJSGlobal::Variable:
+ if (!ValidateGlobalVariable(cx, global, module.globalData(), importVal))
return false;
break;
- case AsmJSModule::Global::FFI:
+ case AsmJSGlobal::FFI:
if (!ValidateFFI(cx, global, importVal, &ffis))
return false;
break;
- case AsmJSModule::Global::ArrayView:
- case AsmJSModule::Global::ArrayViewCtor:
+ case AsmJSGlobal::ArrayView:
+ case AsmJSGlobal::ArrayViewCtor:
if (!ValidateArrayView(cx, global, globalVal))
return false;
break;
- case AsmJSModule::Global::MathBuiltinFunction:
+ case AsmJSGlobal::MathBuiltinFunction:
if (!ValidateMathBuiltinFunction(cx, global, globalVal))
return false;
break;
- case AsmJSModule::Global::AtomicsBuiltinFunction:
+ case AsmJSGlobal::AtomicsBuiltinFunction:
if (!ValidateAtomicsBuiltinFunction(cx, global, globalVal))
return false;
break;
- case AsmJSModule::Global::Constant:
+ case AsmJSGlobal::Constant:
if (!ValidateConstant(cx, global, globalVal))
return false;
break;
- case AsmJSModule::Global::SimdCtor:
+ case AsmJSGlobal::SimdCtor:
if (!ValidateSimdType(cx, global, globalVal))
return false;
break;
- case AsmJSModule::Global::SimdOperation:
+ case AsmJSGlobal::SimdOperation:
if (!ValidateSimdOperation(cx, global, globalVal))
return false;
break;
}
}
AutoVectorRooter<JSFunction*> imports(cx);
- for (const AsmJSModule::Import& import : module.imports()) {
+ for (const AsmJSImport& import : module.asmJSImports()) {
if (!imports.append(ffis[import.ffiIndex()]))
return false;
}
- return module.wasmModule().dynamicallyLink(cx, buffer, imports);
+ return module.dynamicallyLink(cx, buffer, imports);
}
static JSFunction*
-NewExportedFunction(JSContext* cx, const AsmJSModule& module, const AsmJSModule::Export& func,
+NewExportedFunction(JSContext* cx, const Module& module, const AsmJSExport& func,
HandleObject moduleObj, unsigned exportIndex)
{
- unsigned numArgs = module.wasmModule().exports()[exportIndex].sig().args().length();
+ unsigned numArgs = module.exports()[exportIndex].sig().args().length();
RootedPropertyName name(cx, func.name());
JSFunction* fun =
NewNativeConstructor(cx, CallAsmJS, numArgs, name,
gc::AllocKind::FUNCTION_EXTENDED, GenericObject,
JSFunction::ASMJS_CTOR);
if (!fun)
return nullptr;
@@ -7870,34 +7705,34 @@ HandleDynamicLinkFailure(JSContext* cx,
return false;
// Call the function we just recompiled.
args.setCallee(ObjectValue(*fun));
return Invoke(cx, args, args.isConstructing() ? CONSTRUCT : NO_CONSTRUCT);
}
static JSObject*
-CreateExportObject(JSContext* cx, HandleAsmJSModule moduleObj)
-{
- AsmJSModule& module = moduleObj->module();
- const AsmJSModule::ExportVector& exports = module.exports();
+CreateExportObject(JSContext* cx, HandleWasmModule moduleObj)
+{
+ AsmJSModule& module = moduleObj->module().asAsmJS();
+ const AsmJSExportVector& exports = module.asmJSExports();
if (exports.length() == 1) {
- const AsmJSModule::Export& func = exports[0];
+ const AsmJSExport& func = exports[0];
if (!func.maybeFieldName())
return NewExportedFunction(cx, module, func, moduleObj, 0);
}
gc::AllocKind allocKind = gc::GetGCObjectKind(exports.length());
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, allocKind));
if (!obj)
return nullptr;
for (unsigned i = 0; i < exports.length(); i++) {
- const AsmJSModule::Export& func = exports[i];
+ const AsmJSExport& func = exports[i];
RootedFunction fun(cx, NewExportedFunction(cx, module, func, moduleObj, i));
if (!fun)
return nullptr;
MOZ_ASSERT(func.maybeFieldName() != nullptr);
RootedId id(cx, NameToId(func.maybeFieldName()));
RootedValue val(cx, ObjectValue(*fun));
@@ -7912,34 +7747,30 @@ CreateExportObject(JSContext* cx, Handle
static bool
LinkAsmJS(JSContext* cx, unsigned argc, JS::Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// The LinkAsmJS builtin (created by NewAsmJSModuleFunction) is an extended
// function and stores its module in an extended slot.
RootedFunction fun(cx, &args.callee().as<JSFunction>());
- Rooted<AsmJSModuleObject*> moduleObj(cx, &FunctionToModuleObject(fun));
+ Rooted<WasmModuleObject*> moduleObj(cx, &FunctionToModuleObject(fun));
// When a module is linked, it is dynamically specialized to the given
// arguments (buffer, ffis). Thus, if the module is linked again (it is just
// a function so it can be called multiple times), we need to clone a new
// module.
- if (moduleObj->module().wasmModule().dynamicallyLinked()) {
- Rooted<AsmJSModuleObject*> clone(cx, NewAsmJSModuleObject(cx));
- if (!clone)
- return false;
-
- if (!moduleObj->module().clone(cx, clone))
- return false;
-
- moduleObj = clone;
- }
-
- AsmJSModule& module = moduleObj->module();
+ if (moduleObj->module().dynamicallyLinked()) {
+ if (!moduleObj->module().asAsmJS().clone(cx, &moduleObj))
+ return false;
+ if (!moduleObj->module().asAsmJS().staticallyLink(cx))
+ return false;
+ }
+
+ AsmJSModule& module = moduleObj->module().asAsmJS();
// Link the module by performing the link-time validation checks in the
// asm.js spec and then patching the generated module to associate it with
// the given heap (ArrayBuffer) and a new global data segment (the closure
// state shared by the inner asm.js functions).
if (!DynamicallyLinkModule(cx, args, module)) {
// Linking failed, so reparse the entire asm.js module from scratch to
// get normal interpreted bytecode which we can simply Invoke. Very slow.
@@ -7974,180 +7805,246 @@ NewModuleFunction(ExclusiveContext* cx,
moduleFun->setExtendedSlot(FunctionExtended::WASM_MODULE_SLOT, ObjectValue(*moduleObj));
return moduleFun;
}
/*****************************************************************************/
// Caching and cloning
uint8_t*
-AsmJSModule::Global::serialize(uint8_t* cursor) const
+AsmJSGlobal::serialize(uint8_t* cursor) const
{
cursor = WriteBytes(cursor, &pod, sizeof(pod));
cursor = SerializeName(cursor, name_);
return cursor;
}
size_t
-AsmJSModule::Global::serializedSize() const
+AsmJSGlobal::serializedSize() const
{
return sizeof(pod) +
SerializedNameSize(name_);
}
const uint8_t*
-AsmJSModule::Global::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
+AsmJSGlobal::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
{
(cursor = ReadBytes(cursor, &pod, sizeof(pod))) &&
(cursor = DeserializeName(cx, cursor, &name_));
return cursor;
}
bool
-AsmJSModule::Global::clone(JSContext* cx, Global* out) const
+AsmJSGlobal::clone(JSContext* cx, AsmJSGlobal* out) const
{
*out = *this;
return true;
}
uint8_t*
-AsmJSModule::Export::serialize(uint8_t* cursor) const
+AsmJSExport::serialize(uint8_t* cursor) const
{
cursor = SerializeName(cursor, name_);
cursor = SerializeName(cursor, maybeFieldName_);
cursor = WriteBytes(cursor, &pod, sizeof(pod));
return cursor;
}
size_t
-AsmJSModule::Export::serializedSize() const
+AsmJSExport::serializedSize() const
{
return SerializedNameSize(name_) +
SerializedNameSize(maybeFieldName_) +
sizeof(pod);
}
const uint8_t*
-AsmJSModule::Export::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
+AsmJSExport::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
{
(cursor = DeserializeName(cx, cursor, &name_)) &&
(cursor = DeserializeName(cx, cursor, &maybeFieldName_)) &&
(cursor = ReadBytes(cursor, &pod, sizeof(pod)));
return cursor;
}
bool
-AsmJSModule::Export::clone(JSContext* cx, Export* out) const
+AsmJSExport::clone(JSContext* cx, AsmJSExport* out) const
{
out->name_ = name_;
out->maybeFieldName_ = maybeFieldName_;
out->pod = pod;
return true;
}
size_t
-AsmJSModule::serializedSize() const
-{
- MOZ_ASSERT(isFinished());
- return wasmModule_->serializedSize() +
- linkData_->serializedSize() +
- sizeof(pod) +
- SerializedVectorSize(globals_) +
- SerializedPodVectorSize(imports_) +
- SerializedVectorSize(exports_) +
- SerializedNameSize(globalArgumentName_) +
- SerializedNameSize(importArgumentName_) +
- SerializedNameSize(bufferArgumentName_);
+AsmJSModuleData::serializedSize() const
+{
+ return sizeof(pod) +
+ SerializedVectorSize(globals) +
+ SerializedPodVectorSize(imports) +
+ SerializedVectorSize(exports) +
+ SerializedNameSize(globalArgumentName) +
+ SerializedNameSize(importArgumentName) +
+ SerializedNameSize(bufferArgumentName);
}
uint8_t*
-AsmJSModule::serialize(uint8_t* cursor) const
-{
- MOZ_ASSERT(isFinished());
- cursor = wasmModule_->serialize(cursor);
- cursor = linkData_->serialize(cursor);
+AsmJSModuleData::serialize(uint8_t* cursor) const
+{
cursor = WriteBytes(cursor, &pod, sizeof(pod));
- cursor = SerializeVector(cursor, globals_);
- cursor = SerializePodVector(cursor, imports_);
- cursor = SerializeVector(cursor, exports_);
- cursor = SerializeName(cursor, globalArgumentName_);
- cursor = SerializeName(cursor, importArgumentName_);
- cursor = SerializeName(cursor, bufferArgumentName_);
+ cursor = SerializeVector(cursor, globals);
+ cursor = SerializePodVector(cursor, imports);
+ cursor = SerializeVector(cursor, exports);
+ cursor = SerializeName(cursor, globalArgumentName);
+ cursor = SerializeName(cursor, importArgumentName);
+ cursor = SerializeName(cursor, bufferArgumentName);
return cursor;
}
const uint8_t*
-AsmJSModule::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
-{
- linkData_ = cx->make_unique<StaticLinkData>();
- if (!linkData_)
- return nullptr;
-
- // To avoid GC-during-deserialization corner cases, prevent atoms from
- // being collected.
- AutoKeepAtoms aka(cx->perThreadData);
-
- (cursor = Module::deserialize(cx, cursor, &wasmModule_)) &&
- (cursor = linkData_->deserialize(cx, cursor)) &&
+AsmJSModuleData::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
+{
(cursor = ReadBytes(cursor, &pod, sizeof(pod))) &&
- (cursor = DeserializeVector(cx, cursor, &globals_)) &&
- (cursor = DeserializePodVector(cx, cursor, &imports_)) &&
- (cursor = DeserializeVector(cx, cursor, &exports_)) &&
- (cursor = DeserializeName(cx, cursor, &globalArgumentName_)) &&
- (cursor = DeserializeName(cx, cursor, &importArgumentName_)) &&
- (cursor = DeserializeName(cx, cursor, &bufferArgumentName_));
-
+ (cursor = DeserializeVector(cx, cursor, &globals)) &&
+ (cursor = DeserializePodVector(cx, cursor, &imports)) &&
+ (cursor = DeserializeVector(cx, cursor, &exports)) &&
+ (cursor = DeserializeName(cx, cursor, &globalArgumentName)) &&
+ (cursor = DeserializeName(cx, cursor, &importArgumentName)) &&
+ (cursor = DeserializeName(cx, cursor, &bufferArgumentName));
return cursor;
}
bool
-AsmJSModule::clone(JSContext* cx, HandleAsmJSModule obj) const
-{
- auto out = cx->new_<AsmJSModule>(scriptSource(), srcStart_, srcBodyStart_, pod.strict_);
- if (!out)
- return false;
-
- obj->setModule(out);
-
- out->wasmModule_ = wasmModule_->clone(cx, *linkData_);
- if (!out->wasmModule_)
- return false;
-
- out->linkData_ = cx->make_unique<StaticLinkData>();
- if (!out->linkData_ || !linkData_->clone(cx, out->linkData_.get()))
- return false;
-
+AsmJSModuleData::clone(JSContext* cx, AsmJSModuleData* out) const
+{
out->pod = pod;
-
- if (!CloneVector(cx, globals_, &out->globals_) ||
- !ClonePodVector(cx, imports_, &out->imports_) ||
- !CloneVector(cx, exports_, &out->exports_))
- {
- return false;
- }
-
- out->globalArgumentName_ = globalArgumentName_;
- out->importArgumentName_ = importArgumentName_;
- out->bufferArgumentName_ = bufferArgumentName_;
- return true;
+ out->globalArgumentName = globalArgumentName;
+ out->importArgumentName = importArgumentName;
+ out->bufferArgumentName = bufferArgumentName;
+ out->srcStart = srcStart;
+ out->srcBodyStart = srcBodyStart;
+ out->strict = strict;
+ out->scriptSource.reset(scriptSource.get());
+ return CloneVector(cx, globals, &out->globals) &&
+ ClonePodVector(cx, imports, &out->imports) &&
+ CloneVector(cx, exports, &out->exports);
+}
+
+size_t
+AsmJSModuleData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
+{
+ return globals.sizeOfExcludingThis(mallocSizeOf) +
+ imports.sizeOfExcludingThis(mallocSizeOf) +
+ exports.sizeOfExcludingThis(mallocSizeOf);
+}
+
+size_t
+AsmJSModule::serializedSize() const
+{
+ return baseData().serializedSize() +
+ linkData_->serializedSize() +
+ data_->serializedSize();
+}
+
+uint8_t*
+AsmJSModule::serialize(uint8_t* cursor) const
+{
+ cursor = baseData().serialize(cursor);
+ cursor = linkData_->serialize(cursor);
+ cursor = data_->serialize(cursor);
+ return cursor;
+}
+
+/* static */ const uint8_t*
+AsmJSModule::deserialize(ExclusiveContext* cx, const uint8_t* cursor, AsmJSParser& parser,
+ MutableHandleWasmModule moduleObj)
+{
+ moduleObj.set(WasmModuleObject::create(cx));
+ if (!moduleObj)
+ return nullptr;
+
+ // Deserialization GC-allocates a bunch of atoms and stores them in unrooted
+ // Vectors so, for simplicity, inhibit GC of the atoms zone.
+ AutoKeepAtoms aka(cx->perThreadData);
+
+ UniqueModuleData baseData = cx->make_unique<ModuleData>();
+ if (!baseData)
+ return nullptr;
+ cursor = baseData->deserialize(cx, cursor);
+ if (!cursor)
+ return nullptr;
+
+ MOZ_ASSERT(!baseData->loadedFromCache);
+ baseData->loadedFromCache = true;
+
+ UniqueStaticLinkData linkData = cx->make_unique<StaticLinkData>();
+ if (!linkData)
+ return nullptr;
+ cursor = linkData->deserialize(cx, cursor);
+ if (!cursor)
+ return nullptr;
+
+ UniqueAsmJSModuleData data = cx->make_unique<AsmJSModuleData>();
+ if (!data)
+ return nullptr;
+ cursor = data->deserialize(cx, cursor);
+ if (!cursor)
+ return nullptr;
+
+ // See AsmJSModuleData comment as well as ModuleValidator::init().
+ data->srcStart = parser.pc->maybeFunction->pn_body->pn_pos.begin;
+ data->srcBodyStart = parser.tokenStream.currentToken().pos.end;
+ data->strict = parser.pc->sc->strict() && !parser.pc->sc->hasExplicitUseStrict();
+ data->scriptSource.reset(parser.ss);
+
+ auto module = cx->make_unique<AsmJSModule>(Move(baseData), Move(linkData), Move(data));
+ if (!module)
+ return nullptr;
+
+ moduleObj->initModule(Move(module));
+ return cursor;
+}
+
+bool
+AsmJSModule::clone(JSContext* cx, MutableHandleWasmModule moduleObj) const
+{
+ moduleObj.set(WasmModuleObject::create(cx));
+ if (!moduleObj)
+ return false;
+
+ // Prevent any GC that may move the temporarily-unrooted atoms being cloned.
+ AutoKeepAtoms aka(cx->perThreadData);
+
+ UniqueModuleData baseData = cx->make_unique<ModuleData>();
+ if (!baseData || !this->baseData().clone(cx, baseData.get()))
+ return false;
+
+ UniqueStaticLinkData linkData = cx->make_unique<StaticLinkData>();
+ if (!linkData || !linkData_->clone(cx, linkData.get()))
+ return false;
+
+ UniqueAsmJSModuleData data = cx->make_unique<AsmJSModuleData>();
+ if (!data || !data_->clone(cx, data.get()))
+ return false;
+
+ auto module = cx->make_unique<AsmJSModule>(Move(baseData), Move(linkData), Move(data));
+ if (!module)
+ return false;
+
+ moduleObj->initModule(Move(module));
+
+ return Module::clone(cx, *linkData_, &moduleObj->module());
}
void
-AsmJSModule::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
-{
- if (wasmModule_)
- wasmModule_->addSizeOfMisc(mallocSizeOf, code, data);
-
- if (linkData_)
- *data += linkData_->sizeOfExcludingThis(mallocSizeOf);
-
- *data += mallocSizeOf(this) +
- globals_.sizeOfExcludingThis(mallocSizeOf) +
- imports_.sizeOfExcludingThis(mallocSizeOf) +
- exports_.sizeOfExcludingThis(mallocSizeOf);
+AsmJSModule::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
+{
+ Module::addSizeOfMisc(mallocSizeOf, code, data);
+ *data += mallocSizeOf(linkData_.get()) + linkData_->sizeOfExcludingThis(mallocSizeOf);
+ *data += mallocSizeOf(data_.get()) + data_->sizeOfExcludingThis(mallocSizeOf);
}
namespace {
struct PropertyNameWrapper
{
PropertyName* name;
@@ -8354,18 +8251,18 @@ StoreAsmJSModuleInCache(AsmJSParser& par
cursor = moduleChars.serialize(cursor);
cursor = module.serialize(cursor);
MOZ_ASSERT(cursor == entry.memory + serializedSize);
return JS::AsmJSCache_Success;
}
static bool
-LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, HandleAsmJSModule moduleObj,
- bool* loadedFromCache, UniqueChars* compilationTimeReport)
+LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loadedFromCache,
+ MutableHandleWasmModule moduleObj, UniqueChars* compilationTimeReport)
{
int64_t usecBefore = PRMJ_Now();
*loadedFromCache = false;
MachineId machineId;
if (!machineId.extractCurrentState(cx))
return true;
@@ -8390,41 +8287,34 @@ LookupAsmJSModuleInCache(ExclusiveContex
if (machineId != cachedMachineId)
return true;
ModuleCharsForLookup moduleChars;
cursor = moduleChars.deserialize(cx, cursor);
if (!moduleChars.match(parser))
return true;
- uint32_t srcStart = parser.pc->maybeFunction->pn_body->pn_pos.begin;
- uint32_t srcBodyStart = parser.tokenStream.currentToken().pos.end;
- bool strict = parser.pc->sc->strict() && !parser.pc->sc->hasExplicitUseStrict();
-
- AsmJSModule* module = cx->new_<AsmJSModule>(parser.ss, srcStart, srcBodyStart, strict);
- if (!module)
- return false;
-
- moduleObj->setModule(module);
-
- cursor = module->deserialize(cx, cursor);
+ cursor = AsmJSModule::deserialize(cx, cursor, parser, moduleObj);
if (!cursor)
return false;
bool atEnd = cursor == entry.memory + entry.serializedSize;
MOZ_ASSERT(atEnd, "Corrupt cache file");
if (!atEnd)
return true;
- if (module->wasmModule().compileArgs() != CompileArgs(cx))
+ AsmJSModule& module = moduleObj->module().asAsmJS();
+
+ if (module.compileArgs() != CompileArgs(cx))
return true;
- module->staticallyLink(cx);
-
- if (!parser.tokenStream.advance(module->srcEndBeforeCurly()))
+ if (!module.staticallyLink(cx))
+ return false;
+
+ if (!parser.tokenStream.advance(module.srcEndBeforeCurly()))
return false;
*loadedFromCache = true;
int64_t usecAfter = PRMJ_Now();
int ms = (usecAfter - usecBefore) / PRMJ_USEC_PER_MSEC;
*compilationTimeReport = UniqueChars(JS_smprintf("loaded from cache in %dms", ms));
return true;
@@ -8556,42 +8446,40 @@ bool
js::CompileAsmJS(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList, bool* validated)
{
*validated = false;
// Various conditions disable asm.js optimizations.
if (!EstablishPreconditions(cx, parser))
return NoExceptionPending(cx);
- Rooted<AsmJSModuleObject*> moduleObj(cx, NewAsmJSModuleObject(cx));
- if (!moduleObj)
- return false;
// Before spending any time parsing the module, try to look it up in the
// embedding's cache using the chars about to be parsed as the key.
+ Rooted<WasmModuleObject*> moduleObj(cx);
bool loadedFromCache;
UniqueChars message;
- if (!LookupAsmJSModuleInCache(cx, parser, moduleObj, &loadedFromCache, &message))
+ if (!LookupAsmJSModuleInCache(cx, parser, &loadedFromCache, &moduleObj, &message))
return false;
// If not present in the cache, parse, validate and generate code in a
// single linear pass over the chars of the asm.js module.
if (!loadedFromCache) {
// "Checking" parses, validates and compiles, producing a fully compiled
- // AsmJSModuleObject as result.
+ // WasmModuleObject as result.
unsigned time;
SlowFunctionVector slowFuncs(cx);
- if (!CheckModule(cx, parser, stmtList, moduleObj, &time, &slowFuncs))
+ if (!CheckModule(cx, parser, stmtList, &moduleObj, &time, &slowFuncs))
return NoExceptionPending(cx);
// Try to store the AsmJSModule in the embedding's cache. The
// AsmJSModule must be stored before static linking since static linking
// specializes the AsmJSModule to the current process's address space
// and therefore must be executed after a cache hit.
- AsmJSModule& module = moduleObj->module();
+ AsmJSModule& module = moduleObj->module().asAsmJS();
JS::AsmJSCacheResult cacheResult = StoreAsmJSModuleInCache(parser, module, cx);
if (!module.staticallyLink(cx))
return false;
message = BuildConsoleMessage(cx, module, time, slowFuncs, cacheResult);
if (!message)
return NoExceptionPending(cx);
}
@@ -8703,17 +8591,17 @@ js::IsAsmJSModuleLoadedFromCache(JSConte
JSFunction* fun;
if (!args.hasDefined(0) || !IsMaybeWrappedNativeFunction(args[0], LinkAsmJS, &fun)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_USE_ASM_TYPE_FAIL,
"argument passed to isAsmJSModuleLoadedFromCache is not a "
"validated asm.js module");
return false;
}
- bool loadedFromCache = FunctionToModuleObject(fun).module().wasmModule().loadedFromCache();
+ bool loadedFromCache = FunctionToModuleObject(fun).module().loadedFromCache();
args.rval().set(BooleanValue(loadedFromCache));
return true;
}
/*****************************************************************************/
// asm.js toString/toSource support
@@ -8736,17 +8624,17 @@ AppendUseStrictSource(JSContext* cx, Han
return out.appendSubstring(src, 0, bodyStart) &&
out.append("\n\"use strict\";\n") &&
out.appendSubstring(src, bodyStart, src->length() - bodyStart);
}
JSString*
js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda)
{
- AsmJSModule& module = FunctionToModuleObject(fun).module();
+ AsmJSModule& module = FunctionToModuleObject(fun).module().asAsmJS();
uint32_t begin = module.srcStart();
uint32_t end = module.srcEndAfterCurly();
ScriptSource* source = module.scriptSource();
StringBuffer out(cx);
if (addParenToLambda && fun->isLambda() && !out.append("("))
return nullptr;
@@ -8809,18 +8697,18 @@ js::AsmJSModuleToString(JSContext* cx, H
return nullptr;
return out.finishString();
}
JSString*
js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun)
{
- AsmJSModule& module = FunctionToModuleObject(fun).module();
- const AsmJSModule::Export& f = module.exports()[FunctionToExportIndex(fun)];
+ AsmJSModule& module = FunctionToModuleObject(fun).module().asAsmJS();
+ const AsmJSExport& f = module.asmJSExports()[FunctionToExportIndex(fun)];
uint32_t begin = module.srcStart() + f.startOffsetInModule();
uint32_t end = module.srcStart() + f.endOffsetInModule();
ScriptSource* source = module.scriptSource();
StringBuffer out(cx);
if (!out.append("function "))
return nullptr;
@@ -8873,30 +8761,30 @@ js::AsmJSFunctionToString(JSContext* cx,
static const size_t MinHeapLength = 64 * 1024;
static_assert(MinHeapLength % AsmJSPageSize == 0, "Invalid page size");
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
// Targets define AsmJSImmediateRange to be the size of an address immediate,
// and AsmJSCheckedImmediateRange, to be the size of an address immediate that
// can be supported by signal-handler OOB handling.
-static_assert(jit::AsmJSCheckedImmediateRange <= jit::AsmJSImmediateRange,
+static_assert(AsmJSCheckedImmediateRange <= AsmJSImmediateRange,
"AsmJSImmediateRange should be the size of an unconstrained "
"address immediate");
// To support the use of signal handlers for catching Out Of Bounds accesses,
// the internal ArrayBuffer data array is inflated to 4GiB (only the
// byteLength portion of which is accessible) so that out-of-bounds accesses
// (made using a uint32 index) are guaranteed to raise a SIGSEGV.
// Then, an additional extent is added to permit folding of immediate
// values into addresses. And finally, unaligned accesses and mask optimizations
// might also try to access a few bytes after this limit, so just inflate it by
// AsmJSPageSize.
const size_t js::AsmJSMappedSize = 4 * 1024ULL * 1024ULL * 1024ULL +
- jit::AsmJSImmediateRange +
+ AsmJSImmediateRange +
AsmJSPageSize;
#endif // ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
// From the asm.js spec Linking section:
// the heap object's byteLength must be either
// 2^n for n in [12, 24)
// or
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -71,16 +71,17 @@ wasm::AllocateCode(ExclusiveContext* cx,
MOZ_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
return UniqueCodePtr((uint8_t*)p, CodeDeleter(bytes));
}
void
CodeDeleter::operator()(uint8_t* p)
{
+ MOZ_ASSERT(bytes_ != 0);
DeallocateExecutableMemory(p, bytes_, AsmJSPageSize);
}
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
// On MIPS, CodeLabels are instruction immediates so InternalLinks only
// patch instruction immediates.
StaticLinkData::InternalLink::InternalLink(Kind kind)
{
@@ -457,41 +458,114 @@ CacheableUniquePtr<CharT>::clone(JSConte
return false;
PodCopy(chars.get(), this->get(), length);
*out = Move(chars);
return true;
}
+template <class CharT>
+size_t
+CacheableUniquePtr<CharT>::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
+{
+ return mallocSizeOf(this->get());
+}
+
namespace js {
namespace wasm {
template struct CacheableUniquePtr<char>;
template struct CacheableUniquePtr<char16_t>;
}
}
-class Module::AutoMutateCode
+size_t
+ModuleData::serializedSize() const
+{
+ return sizeof(pod) +
+ pod.codeBytes +
+ SerializedVectorSize(imports) +
+ SerializedVectorSize(exports) +
+ SerializedPodVectorSize(heapAccesses) +
+ SerializedPodVectorSize(codeRanges) +
+ SerializedPodVectorSize(callSites) +
+ SerializedVectorSize(funcNames) +
+ filename.serializedSize() +
+ displayURL.serializedSize();
+}
+
+uint8_t*
+ModuleData::serialize(uint8_t* cursor) const
{
- AutoWritableJitCode awjc_;
- AutoFlushICache afc_;
+ cursor = WriteBytes(cursor, &pod, sizeof(pod));
+ cursor = WriteBytes(cursor, code.get(), pod.codeBytes);
+ cursor = SerializeVector(cursor, imports);
+ cursor = SerializeVector(cursor, exports);
+ cursor = SerializePodVector(cursor, heapAccesses);
+ cursor = SerializePodVector(cursor, codeRanges);
+ cursor = SerializePodVector(cursor, callSites);
+ cursor = SerializeVector(cursor, funcNames);
+ cursor = filename.serialize(cursor);
+ cursor = displayURL.serialize(cursor);
+ return cursor;
+}
+
+/* static */ const uint8_t*
+ModuleData::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
+{
+ cursor = ReadBytes(cursor, &pod, sizeof(pod));
+
+ code = AllocateCode(cx, pod.totalBytes());
+ if (!code)
+ return nullptr;
+ cursor = ReadBytes(cursor, code.get(), pod.codeBytes);
- public:
- AutoMutateCode(JSContext* cx, Module& module, const char* name)
- : awjc_(cx->runtime(), module.code(), module.pod.codeBytes_),
- afc_(name)
- {
- AutoFlushICache::setRange(uintptr_t(module.code()), module.pod.codeBytes_);
- }
-};
+ (cursor = DeserializeVector(cx, cursor, &imports)) &&
+ (cursor = DeserializeVector(cx, cursor, &exports)) &&
+ (cursor = DeserializePodVector(cx, cursor, &heapAccesses)) &&
+ (cursor = DeserializePodVector(cx, cursor, &codeRanges)) &&
+ (cursor = DeserializePodVector(cx, cursor, &callSites)) &&
+ (cursor = DeserializeVector(cx, cursor, &funcNames)) &&
+ (cursor = filename.deserialize(cx, cursor)) &&
+ (cursor = displayURL.deserialize(cx, cursor));
+ return cursor;
+}
+
+bool
+ModuleData::clone(JSContext* cx, ModuleData* out) const
+{
+ out->pod = pod;
+
+ out->code = AllocateCode(cx, pod.totalBytes());
+ if (!out->code)
+ return false;
+ memcpy(out->code.get(), code.get(), pod.codeBytes);
-uint32_t
-Module::totalBytes() const
+ return CloneVector(cx, imports, &out->imports) &&
+ CloneVector(cx, exports, &out->exports) &&
+ ClonePodVector(cx, heapAccesses, &out->heapAccesses) &&
+ ClonePodVector(cx, codeRanges, &out->codeRanges) &&
+ ClonePodVector(cx, callSites, &out->callSites) &&
+ CloneVector(cx, funcNames, &out->funcNames) &&
+ filename.clone(cx, &out->filename) &&
+ displayURL.clone(cx, &out->displayURL);
+}
+
+size_t
+ModuleData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
{
- return pod.codeBytes_ + pod.globalBytes_;
+ // Module::addSizeOfMisc takes care of code and global memory.
+ return SizeOfVectorExcludingThis(imports, mallocSizeOf) +
+ SizeOfVectorExcludingThis(exports, mallocSizeOf) +
+ heapAccesses.sizeOfExcludingThis(mallocSizeOf) +
+ codeRanges.sizeOfExcludingThis(mallocSizeOf) +
+ callSites.sizeOfExcludingThis(mallocSizeOf) +
+ funcNames.sizeOfExcludingThis(mallocSizeOf) +
+ filename.sizeOfExcludingThis(mallocSizeOf) +
+ displayURL.sizeOfExcludingThis(mallocSizeOf);
}
uint8_t*
Module::rawHeapPtr() const
{
return const_cast<Module*>(this)->rawHeapPtr();
}
@@ -519,40 +593,40 @@ Module::specializeToHeap(ArrayBufferObje
uint8_t* ptrBase = heap->dataPointerEither().unwrap(/*safe - protected by Module methods*/);
uint32_t heapLength = heap->byteLength();
#if defined(JS_CODEGEN_X86)
// An access is out-of-bounds iff
// ptr + offset + data-type-byte-size > heapLength
// i.e. ptr > heapLength - data-type-byte-size - offset. data-type-byte-size
// and offset are already included in the addend so we
// just have to add the heap length here.
- for (const HeapAccess& access : heapAccesses_) {
+ for (const HeapAccess& access : data_->heapAccesses) {
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code()), heapLength);
void* addr = access.patchHeapPtrImmAt(code());
uint32_t disp = reinterpret_cast<uint32_t>(X86Encoding::GetPointer(addr));
MOZ_ASSERT(disp <= INT32_MAX);
X86Encoding::SetPointer(addr, (void*)(ptrBase + disp));
}
#elif defined(JS_CODEGEN_X64)
// Even with signal handling being used for most bounds checks, there may be
// atomic operations that depend on explicit checks.
//
// If we have any explicit bounds checks, we need to patch the heap length
// checks at the right places. All accesses that have been recorded are the
// only ones that need bound checks (see also
// CodeGeneratorX64::visitAsmJS{Load,Store,CompareExchange,Exchange,AtomicBinop}Heap)
- for (const HeapAccess& access : heapAccesses_) {
+ for (const HeapAccess& access : data_->heapAccesses) {
// See comment above for x86 codegen.
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code()), heapLength);
}
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
- for (const HeapAccess& access : heapAccesses_)
+ for (const HeapAccess& access : data_->heapAccesses)
Assembler::UpdateBoundsCheck(heapLength, (Instruction*)(access.insnOffset() + code()));
#endif
heap_ = heap;
rawHeapPtr() = ptrBase;
}
void
@@ -562,69 +636,69 @@ Module::despecializeFromHeap(ArrayBuffer
// another dynamically-linked module which we are despecializing from that
// module's heap.
MOZ_ASSERT_IF(heap_, heap_ == heap);
MOZ_ASSERT_IF(rawHeapPtr(), rawHeapPtr() == heap->dataPointerEither().unwrap());
#if defined(JS_CODEGEN_X86)
uint32_t heapLength = heap->byteLength();
uint8_t* ptrBase = heap->dataPointerEither().unwrap(/*safe - used for value*/);
- for (unsigned i = 0; i < heapAccesses_.length(); i++) {
- const HeapAccess& access = heapAccesses_[i];
+ for (unsigned i = 0; i < data_->heapAccesses.length(); i++) {
+ const HeapAccess& access = data_->heapAccesses[i];
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code()), -heapLength);
void* addr = access.patchHeapPtrImmAt(code());
uint8_t* ptr = reinterpret_cast<uint8_t*>(X86Encoding::GetPointer(addr));
MOZ_ASSERT(ptr >= ptrBase);
X86Encoding::SetPointer(addr, reinterpret_cast<void*>(ptr - ptrBase));
}
#elif defined(JS_CODEGEN_X64)
uint32_t heapLength = heap->byteLength();
- for (unsigned i = 0; i < heapAccesses_.length(); i++) {
- const HeapAccess& access = heapAccesses_[i];
+ for (unsigned i = 0; i < data_->heapAccesses.length(); i++) {
+ const HeapAccess& access = data_->heapAccesses[i];
if (access.hasLengthCheck())
X86Encoding::AddInt32(access.patchLengthAt(code()), -heapLength);
}
#endif
heap_ = nullptr;
rawHeapPtr() = nullptr;
}
void
Module::sendCodeRangesToProfiler(JSContext* cx)
{
#ifdef JS_ION_PERF
if (PerfFuncEnabled()) {
- for (const CodeRange& codeRange : codeRanges_) {
+ for (const CodeRange& codeRange : data_->codeRanges) {
if (!codeRange.isFunction())
continue;
uintptr_t start = uintptr_t(code() + codeRange.begin());
uintptr_t end = uintptr_t(code() + codeRange.end());
uintptr_t size = end - start;
- const char* file = filename_.get();
+ const char* file = data_->filename.get();
unsigned line = codeRange.funcLineNumber();
unsigned column = 0;
- const char* name = funcNames_[codeRange.funcNameIndex()].get();
+ const char* name = data_->funcNames[codeRange.funcNameIndex()].get();
writePerfSpewerAsmJSFunctionMap(start, size, file, line, column, name);
}
}
#endif
#ifdef MOZ_VTUNE
if (IsVTuneProfilingActive()) {
- for (const CodeRange& codeRange : codeRanges_) {
+ for (const CodeRange& codeRange : data_->codeRanges) {
if (!codeRange.isFunction())
continue;
uintptr_t start = uintptr_t(code() + codeRange.begin());
uintptr_t end = uintptr_t(code() + codeRange.end());
uintptr_t size = end - start;
- const char* name = funcNames_[codeRange.funcNameIndex()].get();
+ const char* name = data_->funcNames[codeRange.funcNameIndex()].get();
unsigned method_id = iJIT_GetNewMethodID();
if (method_id == 0)
return;
iJIT_Method_Load method;
method.method_id = method_id;
method.method_name = const_cast<char*>(name);
method.method_load_address = (void*)start;
@@ -649,44 +723,46 @@ Module::setProfilingEnabled(JSContext* c
if (profilingEnabled_ == enabled)
return true;
// When enabled, generate profiling labels for every name in funcNames_
// that is the name of some Function CodeRange. This involves malloc() so
// do it now since, once we start sampling, we'll be in a signal-handing
// context where we cannot malloc.
if (enabled) {
- if (!funcLabels_.resize(funcNames_.length())) {
+ if (!funcLabels_.resize(data_->funcNames.length())) {
ReportOutOfMemory(cx);
return false;
}
- for (const CodeRange& codeRange : codeRanges_) {
+ for (const CodeRange& codeRange : data_->codeRanges) {
if (!codeRange.isFunction())
continue;
unsigned lineno = codeRange.funcLineNumber();
- const char* name = funcNames_[codeRange.funcNameIndex()].get();
- UniqueChars label(JS_smprintf("%s (%s:%u)", name, filename_.get(), lineno));
+ const char* name = data_->funcNames[codeRange.funcNameIndex()].get();
+ UniqueChars label(JS_smprintf("%s (%s:%u)", name, data_->filename.get(), lineno));
if (!label) {
ReportOutOfMemory(cx);
return false;
}
funcLabels_[codeRange.funcNameIndex()] = Move(label);
}
} else {
funcLabels_.clear();
}
// Patch callsites and returns to execute profiling prologues/epililogues.
{
- AutoMutateCode amc(cx, *this, "Module::setProfilingEnabled");
+ AutoWritableJitCode awjc(cx->runtime(), code(), codeBytes());
+ AutoFlushICache afc("Module::setProfilingEnabled");
+ AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
- for (const CallSite& callSite : callSites_)
+ for (const CallSite& callSite : data_->callSites)
EnableProfilingPrologue(*this, callSite, enabled);
- for (const CodeRange& codeRange : codeRanges_)
+ for (const CodeRange& codeRange : data_->codeRanges)
EnableProfilingEpilogue(*this, codeRange, enabled);
}
// Update the function-pointer tables to point to profiling prologues.
for (FuncPtrTable& funcPtrTable : funcPtrTables_) {
auto array = reinterpret_cast<void**>(globalData() + funcPtrTable.globalDataOffset);
for (size_t i = 0; i < funcPtrTable.numElems; i++) {
const CodeRange* codeRange = lookupCodeRange(array[i]);
@@ -704,188 +780,135 @@ Module::setProfilingEnabled(JSContext* c
}
Module::ImportExit&
Module::importToExit(const Import& import)
{
return *reinterpret_cast<ImportExit*>(globalData() + import.exitGlobalDataOffset());
}
-/* static */ Module::CacheablePod
-Module::zeroPod()
+bool
+Module::clone(JSContext* cx, const StaticLinkData& linkData, Module* out) const
{
- CacheablePod pod = {0, 0, 0, HeapUsage::None, false, false, false};
- return pod;
+ MOZ_ASSERT(dynamicallyLinked_);
+
+ // The out->data_ field was already cloned and initialized when 'out' was
+ // constructed. This function should clone the rest.
+ MOZ_ASSERT(out->data_);
+
+ out->isAsmJS_ = isAsmJS_;
+ out->profilingEnabled_ = profilingEnabled_;
+
+ if (!CloneVector(cx, funcLabels_, &out->funcLabels_))
+ return false;
+
+#ifdef DEBUG
+ // Put the symbolic links back to -1 so PatchDataWithValueCheck assertions
+ // in Module::staticallyLink are valid.
+ for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
+ void* callee = AddressOf(imm, cx);
+ const StaticLinkData::OffsetVector& offsets = linkData.symbolicLinks[imm];
+ for (uint32_t offset : offsets) {
+ jit::Assembler::PatchDataWithValueCheck(jit::CodeLocationLabel(out->code() + offset),
+ jit::PatchedImmPtr((void*)-1),
+ jit::PatchedImmPtr(callee));
+ }
+ }
+#endif
+
+ // If the copied machine code has been specialized to the heap, it must be
+ // unspecialized in the copy.
+ if (usesHeap())
+ out->despecializeFromHeap(heap_);
+
+ return true;
}
-void
-Module::init()
+
+Module::Module(UniqueModuleData data, AsmJSBool isAsmJS)
+ : data_(Move(data)),
+ isAsmJS_(bool(isAsmJS)),
+ staticallyLinked_(false),
+ interrupt_(nullptr),
+ outOfBounds_(nullptr),
+ dynamicallyLinked_(false),
+ profilingEnabled_(false)
{
- staticallyLinked_ = false;
- interrupt_ = nullptr;
- outOfBounds_ = nullptr;
- dynamicallyLinked_ = false;
-
*(double*)(globalData() + NaN64GlobalDataOffset) = GenericNaN();
*(float*)(globalData() + NaN32GlobalDataOffset) = GenericNaN();
}
-// Private constructor used for deserialization and cloning.
-Module::Module(const CacheablePod& pod,
- UniqueCodePtr code,
- ImportVector&& imports,
- ExportVector&& exports,
- HeapAccessVector&& heapAccesses,
- CodeRangeVector&& codeRanges,
- CallSiteVector&& callSites,
- CacheableCharsVector&& funcNames,
- CacheableChars filename,
- CacheableTwoByteChars displayURL,
- CacheBool loadedFromCache,
- ProfilingBool profilingEnabled,
- FuncLabelVector&& funcLabels)
- : pod(pod),
- code_(Move(code)),
- imports_(Move(imports)),
- exports_(Move(exports)),
- heapAccesses_(Move(heapAccesses)),
- codeRanges_(Move(codeRanges)),
- callSites_(Move(callSites)),
- funcNames_(Move(funcNames)),
- filename_(Move(filename)),
- displayURL_(Move(displayURL)),
- loadedFromCache_(loadedFromCache),
- profilingEnabled_(profilingEnabled),
- funcLabels_(Move(funcLabels))
-{
- MOZ_ASSERT_IF(!profilingEnabled, funcLabels_.empty());
- MOZ_ASSERT_IF(profilingEnabled, funcNames_.length() == funcLabels_.length());
- init();
-}
-
-// Public constructor for compilation.
-Module::Module(CompileArgs args,
- uint32_t functionBytes,
- uint32_t codeBytes,
- uint32_t globalBytes,
- HeapUsage heapUsage,
- MutedBool mutedErrors,
- UniqueCodePtr code,
- ImportVector&& imports,
- ExportVector&& exports,
- HeapAccessVector&& heapAccesses,
- CodeRangeVector&& codeRanges,
- CallSiteVector&& callSites,
- CacheableCharsVector&& funcNames,
- CacheableChars filename,
- CacheableTwoByteChars displayURL)
- : pod(zeroPod()),
- code_(Move(code)),
- imports_(Move(imports)),
- exports_(Move(exports)),
- heapAccesses_(Move(heapAccesses)),
- codeRanges_(Move(codeRanges)),
- callSites_(Move(callSites)),
- funcNames_(Move(funcNames)),
- filename_(Move(filename)),
- displayURL_(Move(displayURL)),
- loadedFromCache_(false),
- profilingEnabled_(false)
-{
- // Work around MSVC 2013 bug around {} member initialization.
- const_cast<uint32_t&>(pod.functionBytes_) = functionBytes;
- const_cast<uint32_t&>(pod.codeBytes_) = codeBytes;
- const_cast<uint32_t&>(pod.globalBytes_) = globalBytes;
- const_cast<HeapUsage&>(pod.heapUsage_) = heapUsage;
- const_cast<bool&>(pod.mutedErrors_) = bool(mutedErrors);
- const_cast<bool&>(pod.usesSignalHandlersForOOB_) = args.useSignalHandlersForOOB;
- const_cast<bool&>(pod.usesSignalHandlersForInterrupt_) = args.useSignalHandlersForInterrupt;
-
- init();
-}
-
Module::~Module()
{
- if (code_) {
- for (unsigned i = 0; i < imports_.length(); i++) {
- ImportExit& exit = importToExit(imports_[i]);
- if (exit.baselineScript)
- exit.baselineScript->removeDependentWasmModule(*this, i);
- }
+ for (unsigned i = 0; i < imports().length(); i++) {
+ ImportExit& exit = importToExit(imports()[i]);
+ if (exit.baselineScript)
+ exit.baselineScript->removeDependentWasmModule(*this, i);
}
}
void
Module::trace(JSTracer* trc)
{
- for (const Import& import : imports_) {
+ for (const Import& import : imports()) {
if (importToExit(import).fun)
TraceEdge(trc, &importToExit(import).fun, "wasm function import");
}
if (heap_)
TraceEdge(trc, &heap_, "wasm buffer");
}
-CompileArgs
-Module::compileArgs() const
-{
- CompileArgs args;
- args.useSignalHandlersForOOB = pod.usesSignalHandlersForOOB_;
- args.useSignalHandlersForInterrupt = pod.usesSignalHandlersForInterrupt_;
- return args;
-}
-
bool
Module::containsFunctionPC(void* pc) const
{
- return pc >= code() && pc < (code() + pod.functionBytes_);
+ return pc >= code() && pc < (code() + data_->pod.functionBytes);
}
bool
Module::containsCodePC(void* pc) const
{
- return pc >= code() && pc < (code() + pod.codeBytes_);
+ return pc >= code() && pc < (code() + codeBytes());
}
struct CallSiteRetAddrOffset
{
const CallSiteVector& callSites;
explicit CallSiteRetAddrOffset(const CallSiteVector& callSites) : callSites(callSites) {}
uint32_t operator[](size_t index) const {
return callSites[index].returnAddressOffset();
}
};
const CallSite*
Module::lookupCallSite(void* returnAddress) const
{
uint32_t target = ((uint8_t*)returnAddress) - code();
size_t lowerBound = 0;
- size_t upperBound = callSites_.length();
+ size_t upperBound = data_->callSites.length();
size_t match;
- if (!BinarySearch(CallSiteRetAddrOffset(callSites_), lowerBound, upperBound, target, &match))
+ if (!BinarySearch(CallSiteRetAddrOffset(data_->callSites), lowerBound, upperBound, target, &match))
return nullptr;
- return &callSites_[match];
+ return &data_->callSites[match];
}
const CodeRange*
Module::lookupCodeRange(void* pc) const
{
CodeRange::PC target((uint8_t*)pc - code());
size_t lowerBound = 0;
- size_t upperBound = codeRanges_.length();
+ size_t upperBound = data_->codeRanges.length();
size_t match;
- if (!BinarySearch(codeRanges_, lowerBound, upperBound, target, &match))
+ if (!BinarySearch(data_->codeRanges, lowerBound, upperBound, target, &match))
return nullptr;
- return &codeRanges_[match];
+ return &data_->codeRanges[match];
}
struct HeapAccessOffset
{
const HeapAccessVector& accesses;
explicit HeapAccessOffset(const HeapAccessVector& accesses) : accesses(accesses) {}
uintptr_t operator[](size_t index) const {
return accesses[index].insnOffset();
@@ -894,38 +917,38 @@ struct HeapAccessOffset
const HeapAccess*
Module::lookupHeapAccess(void* pc) const
{
MOZ_ASSERT(containsFunctionPC(pc));
uint32_t target = ((uint8_t*)pc) - code();
size_t lowerBound = 0;
- size_t upperBound = heapAccesses_.length();
+ size_t upperBound = data_->heapAccesses.length();
size_t match;
- if (!BinarySearch(HeapAccessOffset(heapAccesses_), lowerBound, upperBound, target, &match))
+ if (!BinarySearch(HeapAccessOffset(data_->heapAccesses), lowerBound, upperBound, target, &match))
return nullptr;
- return &heapAccesses_[match];
+ return &data_->heapAccesses[match];
}
bool
Module::staticallyLink(ExclusiveContext* cx, const StaticLinkData& linkData)
{
MOZ_ASSERT(!dynamicallyLinked_);
MOZ_ASSERT(!staticallyLinked_);
staticallyLinked_ = true;
// Push a JitContext for benefit of IsCompilingAsmJS and delay flushing
// until Module::dynamicallyLink.
JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
MOZ_ASSERT(IsCompilingAsmJS());
AutoFlushICache afc("Module::staticallyLink", /* inhibit = */ true);
- AutoFlushICache::setRange(uintptr_t(code()), pod.codeBytes_);
+ AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
interrupt_ = code() + linkData.pod.interruptOffset;
outOfBounds_ = code() + linkData.pod.outOfBoundsOffset;
for (StaticLinkData::InternalLink link : linkData.internalLinks) {
uint8_t* patchAt = code() + link.patchAtOffset;
void* target = code() + link.targetOffset;
@@ -978,45 +1001,45 @@ Module::staticallyLink(ExclusiveContext*
return false;
}
return true;
}
bool
Module::dynamicallyLink(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> heap,
- const AutoVectorRooter<JSFunction*>& imports)
+ const AutoVectorRooter<JSFunction*>& importArgs)
{
MOZ_ASSERT(staticallyLinked_);
MOZ_ASSERT(!dynamicallyLinked_);
dynamicallyLinked_ = true;
// Push a JitContext for benefit of IsCompilingAsmJS and flush the ICache.
// We've been inhibiting flushing up to this point so flush it all now.
JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
MOZ_ASSERT(IsCompilingAsmJS());
AutoFlushICache afc("Module::dynamicallyLink");
- AutoFlushICache::setRange(uintptr_t(code()), pod.codeBytes_);
+ AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
// Initialize imports with actual imported values.
- MOZ_ASSERT(imports.length() == imports_.length());
- for (size_t i = 0; i < imports_.length(); i++) {
- const Import& import = imports_[i];
+ MOZ_ASSERT(importArgs.length() == imports().length());
+ for (size_t i = 0; i < imports().length(); i++) {
+ const Import& import = imports()[i];
ImportExit& exit = importToExit(import);
exit.code = code() + import.interpExitCodeOffset();
- exit.fun = imports[i];
+ exit.fun = importArgs[i];
exit.baselineScript = nullptr;
}
// Specialize code to the actual heap.
if (usesHeap())
specializeToHeap(heap);
// See AllocateCode comment above.
- if (!ExecutableAllocator::makeExecutable(code(), pod.codeBytes_)) {
+ if (!ExecutableAllocator::makeExecutable(code(), codeBytes())) {
ReportOutOfMemory(cx);
return false;
}
sendCodeRangesToProfiler(cx);
return true;
}
@@ -1038,28 +1061,28 @@ Module::heapLength() const
MOZ_ASSERT(usesHeap());
return heap_->byteLength();
}
void
Module::deoptimizeImportExit(uint32_t importIndex)
{
MOZ_ASSERT(dynamicallyLinked_);
- const Import& import = imports_[importIndex];
+ const Import& import = imports()[importIndex];
ImportExit& exit = importToExit(import);
exit.code = code() + import.interpExitCodeOffset();
exit.baselineScript = nullptr;
}
bool
Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
{
MOZ_ASSERT(dynamicallyLinked_);
- const Export& exp = exports_[exportIndex];
+ const Export& exp = exports()[exportIndex];
// Enable/disable profiling in the Module to match the current global
// profiling state. Don't do this if the Module is already active on the
// stack since this would leave the Module in a state where profiling is
// enabled but the stack isn't unwindable.
if (profilingEnabled() != cx->runtime()->spsProfiler.enabled() && !activation()) {
if (!setProfilingEnabled(cx, cx->runtime()->spsProfiler.enabled()))
return false;
@@ -1185,17 +1208,17 @@ Module::callExport(JSContext* cx, uint32
}
bool
Module::callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const Value* argv,
MutableHandleValue rval)
{
MOZ_ASSERT(dynamicallyLinked_);
- const Import& import = imports_[importIndex];
+ const Import& import = imports()[importIndex];
RootedValue fval(cx, ObjectValue(*importToExit(import).fun));
if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval))
return false;
ImportExit& exit = importToExit(import);
// The exit may already have become optimized.
@@ -1259,216 +1282,96 @@ Module::callImport(JSContext* cx, uint32
const char*
Module::profilingLabel(uint32_t funcIndex) const
{
MOZ_ASSERT(dynamicallyLinked_);
MOZ_ASSERT(profilingEnabled_);
return funcLabels_[funcIndex].get();
}
-size_t
-Module::serializedSize() const
+void
+Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
{
- return sizeof(pod) +
- pod.codeBytes_ +
- SerializedVectorSize(imports_) +
- SerializedVectorSize(exports_) +
- SerializedPodVectorSize(heapAccesses_) +
- SerializedPodVectorSize(codeRanges_) +
- SerializedPodVectorSize(callSites_) +
- SerializedVectorSize(funcNames_) +
- filename_.serializedSize() +
- displayURL_.serializedSize();
-}
-
-uint8_t*
-Module::serialize(uint8_t* cursor) const
-{
- MOZ_ASSERT(!profilingEnabled_, "assumed by Module::deserialize");
-
- cursor = WriteBytes(cursor, &pod, sizeof(pod));
- cursor = WriteBytes(cursor, code(), pod.codeBytes_);
- cursor = SerializeVector(cursor, imports_);
- cursor = SerializeVector(cursor, exports_);
- cursor = SerializePodVector(cursor, heapAccesses_);
- cursor = SerializePodVector(cursor, codeRanges_);
- cursor = SerializePodVector(cursor, callSites_);
- cursor = SerializeVector(cursor, funcNames_);
- cursor = filename_.serialize(cursor);
- cursor = displayURL_.serialize(cursor);
- return cursor;
+ *code += codeBytes();
+ *data += mallocSizeOf(this) +
+ globalBytes() +
+ mallocSizeOf(data_.get()) +
+ data_->sizeOfExcludingThis(mallocSizeOf) +
+ funcPtrTables_.sizeOfExcludingThis(mallocSizeOf) +
+ SizeOfVectorExcludingThis(funcLabels_, mallocSizeOf);
}
-/* static */ const uint8_t*
-Module::deserialize(ExclusiveContext* cx, const uint8_t* cursor, UniqueModule* out)
-{
- CacheablePod pod = zeroPod();
- cursor = ReadBytes(cursor, &pod, sizeof(pod));
- if (!cursor)
- return nullptr;
-
- UniqueCodePtr code = AllocateCode(cx, pod.codeBytes_ + pod.globalBytes_);
- if (!code)
- return nullptr;
-
- cursor = ReadBytes(cursor, code.get(), pod.codeBytes_);
-
- ImportVector imports;
- cursor = DeserializeVector(cx, cursor, &imports);
- if (!cursor)
- return nullptr;
-
- ExportVector exports;
- cursor = DeserializeVector(cx, cursor, &exports);
- if (!cursor)
- return nullptr;
+const Class WasmModuleObject::class_ = {
+ "WasmModuleObject",
+ JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_CALLBACK |
+ JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS),
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ WasmModuleObject::finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ WasmModuleObject::trace
+};
- HeapAccessVector heapAccesses;
- cursor = DeserializePodVector(cx, cursor, &heapAccesses);
- if (!cursor)
- return nullptr;
+bool
+WasmModuleObject::hasModule() const
+{
+ MOZ_ASSERT(is<WasmModuleObject>());
+ return !getReservedSlot(MODULE_SLOT).isUndefined();
+}
- CodeRangeVector codeRanges;
- cursor = DeserializePodVector(cx, cursor, &codeRanges);
- if (!cursor)
- return nullptr;
+/* static */ void
+WasmModuleObject::finalize(FreeOp* fop, JSObject* obj)
+{
+ WasmModuleObject& moduleObj = obj->as<WasmModuleObject>();
+ if (moduleObj.hasModule())
+ fop->delete_(&moduleObj.module());
+}
- CallSiteVector callSites;
- cursor = DeserializePodVector(cx, cursor, &callSites);
- if (!cursor)
- return nullptr;
+/* static */ void
+WasmModuleObject::trace(JSTracer* trc, JSObject* obj)
+{
+ WasmModuleObject& moduleObj = obj->as<WasmModuleObject>();
+ if (moduleObj.hasModule())
+ moduleObj.module().trace(trc);
+}
- CacheableCharsVector funcNames;
- cursor = DeserializeVector(cx, cursor, &funcNames);
- if (!cursor)
- return nullptr;
-
- CacheableChars filename;
- cursor = filename.deserialize(cx, cursor);
- if (!cursor)
- return nullptr;
-
- CacheableTwoByteChars displayURL;
- cursor = displayURL.deserialize(cx, cursor);
- if (!cursor)
+/* static */ WasmModuleObject*
+WasmModuleObject::create(ExclusiveContext* cx)
+{
+ AutoSetNewObjectMetadata metadata(cx);
+ JSObject* obj = NewObjectWithGivenProto(cx, &WasmModuleObject::class_, nullptr);
+ if (!obj)
return nullptr;
- *out = cx->make_unique<Module>(pod,
- Move(code),
- Move(imports),
- Move(exports),
- Move(heapAccesses),
- Move(codeRanges),
- Move(callSites),
- Move(funcNames),
- Move(filename),
- Move(displayURL),
- Module::LoadedFromCache,
- Module::ProfilingDisabled,
- FuncLabelVector());
-
- return cursor;
-}
-
-Module::UniqueModule
-Module::clone(JSContext* cx, const StaticLinkData& linkData) const
-{
- MOZ_ASSERT(dynamicallyLinked_);
-
- UniqueCodePtr code = AllocateCode(cx, totalBytes());
- if (!code)
- return nullptr;
-
- memcpy(code.get(), this->code(), pod.codeBytes_);
-
-#ifdef DEBUG
- // Put the symbolic links back to -1 so PatchDataWithValueCheck assertions
- // in Module::staticallyLink are valid.
- for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
- void* callee = AddressOf(imm, cx);
- const StaticLinkData::OffsetVector& offsets = linkData.symbolicLinks[imm];
- for (uint32_t offset : offsets) {
- jit::Assembler::PatchDataWithValueCheck(jit::CodeLocationLabel(code.get() + offset),
- jit::PatchedImmPtr((void*)-1),
- jit::PatchedImmPtr(callee));
- }
- }
-#endif
-
- ImportVector imports;
- if (!CloneVector(cx, imports_, &imports))
- return nullptr;
-
- ExportVector exports;
- if (!CloneVector(cx, exports_, &exports))
- return nullptr;
-
- HeapAccessVector heapAccesses;
- if (!ClonePodVector(cx, heapAccesses_, &heapAccesses))
- return nullptr;
-
- CodeRangeVector codeRanges;
- if (!ClonePodVector(cx, codeRanges_, &codeRanges))
- return nullptr;
-
- CallSiteVector callSites;
- if (!ClonePodVector(cx, callSites_, &callSites))
- return nullptr;
-
- CacheableCharsVector funcNames;
- if (!CloneVector(cx, funcNames_, &funcNames))
- return nullptr;
-
- CacheableChars filename;
- if (!filename_.clone(cx, &filename))
- return nullptr;
-
- CacheableTwoByteChars displayURL;
- if (!displayURL_.clone(cx, &displayURL))
- return nullptr;
-
- FuncLabelVector funcLabels;
- if (!CloneVector(cx, funcLabels_, &funcLabels))
- return nullptr;
-
- // Must not GC between Module allocation and (successful) return.
- auto out = cx->make_unique<Module>(pod,
- Move(code),
- Move(imports),
- Move(exports),
- Move(heapAccesses),
- Move(codeRanges),
- Move(callSites),
- Move(funcNames),
- Move(filename),
- Move(displayURL),
- CacheBool::NotLoadedFromCache,
- ProfilingBool(profilingEnabled_),
- Move(funcLabels));
- if (!out)
- return nullptr;
-
- // If the copied machine code has been specialized to the heap, it must be
- // unspecialized in the copy.
- if (usesHeap())
- out->despecializeFromHeap(heap_);
-
- if (!out->staticallyLink(cx, linkData))
- return nullptr;
-
- return Move(out);
+ return &obj->as<WasmModuleObject>();
}
void
-Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* asmJSModuleCode, size_t* asmJSModuleData)
+WasmModuleObject::initModule(UniqueModule module)
{
- *asmJSModuleCode += pod.codeBytes_;
- *asmJSModuleData += mallocSizeOf(this) +
- pod.globalBytes_ +
- SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
- SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
- heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
- codeRanges_.sizeOfExcludingThis(mallocSizeOf) +
- callSites_.sizeOfExcludingThis(mallocSizeOf) +
- funcNames_.sizeOfExcludingThis(mallocSizeOf) +
- funcPtrTables_.sizeOfExcludingThis(mallocSizeOf);
+ MOZ_ASSERT(is<WasmModuleObject>());
+ MOZ_ASSERT(!hasModule());
+ MOZ_ASSERT(module);
+ setReservedSlot(MODULE_SLOT, PrivateValue(module.release()));
}
+Module&
+WasmModuleObject::module() const
+{
+ MOZ_ASSERT(is<WasmModuleObject>());
+ MOZ_ASSERT(hasModule());
+ return *(Module*)getReservedSlot(MODULE_SLOT).toPrivate();
+}
+
+void
+WasmModuleObject::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
+{
+ if (hasModule())
+ module().addSizeOfMisc(mallocSizeOf, code, data);
+}
+