| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef jit_AsmJSModule_h |
| #define jit_AsmJSModule_h |
| |
| #ifdef JS_ION |
| |
| #include "gc/Marking.h" |
| #include "jit/RegisterSets.h" |
| |
| #include "jsscript.h" |
| #include "jstypedarrayinlines.h" |
| |
| #include "IonMacroAssembler.h" |
| |
| namespace js { |
| |
| // These EcmaScript-defined coercions form the basis of the asm.js type system. |
| enum AsmJSCoercion |
| { |
| AsmJS_ToInt32, |
| AsmJS_ToNumber |
| }; |
| |
| // The asm.js spec recognizes this set of builtin Math functions. |
| enum AsmJSMathBuiltin |
| { |
| 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 |
| }; |
| |
| // An asm.js module represents the collection of functions nested inside a |
| // single outer "use asm" function. For example, this asm.js module: |
| // function() { "use asm"; function f() {} function g() {} return f } |
| // contains the functions 'f' and 'g'. |
| // |
| // An asm.js module contains both the jit-code produced by compiling all the |
| // functions in the module as well all the data required to perform the |
| // link-time validation step in the asm.js spec. |
| // |
| // NB: this means that AsmJSModule must be GC-safe. |
| class AsmJSModule |
| { |
| public: |
| class Global |
| { |
| public: |
| enum Which { Variable, FFI, ArrayView, MathBuiltin, Constant }; |
| enum VarInitKind { InitConstant, InitImport }; |
| |
| private: |
| Which which_; |
| union { |
| struct { |
| uint32_t index_; |
| VarInitKind initKind_; |
| union { |
| Value constant_; // will only contain int32/double |
| AsmJSCoercion coercion_; |
| } init; |
| } var; |
| uint32_t ffiIndex_; |
| ArrayBufferView::ViewType viewType_; |
| AsmJSMathBuiltin mathBuiltin_; |
| double constantValue_; |
| } u; |
| RelocatablePtr<PropertyName> name_; |
| |
| friend class AsmJSModule; |
| Global(Which which) : which_(which) {} |
| |
| void trace(JSTracer *trc) { |
| if (name_) |
| MarkString(trc, &name_, "asm.js global name"); |
| JS_ASSERT_IF(which_ == Variable && u.var.initKind_ == InitConstant, |
| !u.var.init.constant_.isMarkable()); |
| } |
| |
| public: |
| Which which() const { |
| return which_; |
| } |
| uint32_t varIndex() const { |
| JS_ASSERT(which_ == Variable); |
| return u.var.index_; |
| } |
| VarInitKind varInitKind() const { |
| JS_ASSERT(which_ == Variable); |
| return u.var.initKind_; |
| } |
| const Value &varInitConstant() const { |
| JS_ASSERT(which_ == Variable); |
| JS_ASSERT(u.var.initKind_ == InitConstant); |
| return u.var.init.constant_; |
| } |
| AsmJSCoercion varImportCoercion() const { |
| JS_ASSERT(which_ == Variable); |
| JS_ASSERT(u.var.initKind_ == InitImport); |
| return u.var.init.coercion_; |
| } |
| PropertyName *varImportField() const { |
| JS_ASSERT(which_ == Variable); |
| JS_ASSERT(u.var.initKind_ == InitImport); |
| return name_; |
| } |
| PropertyName *ffiField() const { |
| JS_ASSERT(which_ == FFI); |
| return name_; |
| } |
| uint32_t ffiIndex() const { |
| JS_ASSERT(which_ == FFI); |
| return u.ffiIndex_; |
| } |
| PropertyName *viewName() const { |
| JS_ASSERT(which_ == ArrayView); |
| return name_; |
| } |
| ArrayBufferView::ViewType viewType() const { |
| JS_ASSERT(which_ == ArrayView); |
| return u.viewType_; |
| } |
| PropertyName *mathName() const { |
| JS_ASSERT(which_ == MathBuiltin); |
| return name_; |
| } |
| AsmJSMathBuiltin mathBuiltin() const { |
| JS_ASSERT(which_ == MathBuiltin); |
| return u.mathBuiltin_; |
| } |
| PropertyName *constantName() const { |
| JS_ASSERT(which_ == Constant); |
| return name_; |
| } |
| double constantValue() const { |
| JS_ASSERT(which_ == Constant); |
| return u.constantValue_; |
| } |
| }; |
| |
| class Exit |
| { |
| unsigned ffiIndex_; |
| |
| union { |
| unsigned codeOffset_; |
| uint8_t *code_; |
| } interp; |
| |
| union { |
| unsigned codeOffset_; |
| uint8_t *code_; |
| } ion; |
| |
| public: |
| Exit(unsigned ffiIndex) |
| : ffiIndex_(ffiIndex) |
| { |
| interp.codeOffset_ = 0; |
| ion.codeOffset_ = 0; |
| } |
| unsigned ffiIndex() const { |
| return ffiIndex_; |
| } |
| void initInterpOffset(unsigned off) { |
| JS_ASSERT(!interp.codeOffset_); |
| interp.codeOffset_ = off; |
| } |
| void initIonOffset(unsigned off) { |
| JS_ASSERT(!ion.codeOffset_); |
| ion.codeOffset_ = off; |
| } |
| void patch(uint8_t *baseAddress) { |
| interp.code_ = baseAddress + interp.codeOffset_; |
| ion.code_ = baseAddress + ion.codeOffset_; |
| } |
| uint8_t *interpCode() const { |
| return interp.code_; |
| } |
| uint8_t *ionCode() const { |
| return ion.code_; |
| } |
| }; |
| #ifdef JS_CPU_ARM |
| typedef int32_t (*CodePtr)(uint64_t *args, uint8_t *global); |
| #else |
| typedef int32_t (*CodePtr)(uint64_t *args); |
| #endif |
| |
| typedef Vector<AsmJSCoercion, 0, SystemAllocPolicy> ArgCoercionVector; |
| |
| enum ReturnType { Return_Int32, Return_Double, Return_Void }; |
| |
| class ExportedFunction |
| { |
| public: |
| |
| private: |
| |
| RelocatablePtr<JSFunction> fun_; |
| RelocatablePtr<PropertyName> maybeFieldName_; |
| ArgCoercionVector argCoercions_; |
| ReturnType returnType_; |
| bool hasCodePtr_; |
| union { |
| unsigned codeOffset_; |
| CodePtr code_; |
| } u; |
| |
| friend class AsmJSModule; |
| |
| ExportedFunction(JSFunction *fun, |
| PropertyName *maybeFieldName, |
| MoveRef<ArgCoercionVector> argCoercions, |
| ReturnType returnType) |
| : fun_(fun), |
| maybeFieldName_(maybeFieldName), |
| argCoercions_(argCoercions), |
| returnType_(returnType), |
| hasCodePtr_(false) |
| { |
| u.codeOffset_ = 0; |
| } |
| |
| void trace(JSTracer *trc) { |
| MarkObject(trc, &fun_, "asm.js export name"); |
| if (maybeFieldName_) |
| MarkString(trc, &maybeFieldName_, "asm.js export field"); |
| } |
| |
| public: |
| ExportedFunction(MoveRef<ExportedFunction> rhs) |
| : fun_(rhs->fun_), |
| maybeFieldName_(rhs->maybeFieldName_), |
| argCoercions_(Move(rhs->argCoercions_)), |
| returnType_(rhs->returnType_), |
| hasCodePtr_(rhs->hasCodePtr_), |
| u(rhs->u) |
| {} |
| |
| void initCodeOffset(unsigned off) { |
| JS_ASSERT(!hasCodePtr_); |
| JS_ASSERT(!u.codeOffset_); |
| u.codeOffset_ = off; |
| } |
| void patch(uint8_t *baseAddress) { |
| JS_ASSERT(!hasCodePtr_); |
| JS_ASSERT(u.codeOffset_); |
| hasCodePtr_ = true; |
| u.code_ = JS_DATA_TO_FUNC_PTR(CodePtr, baseAddress + u.codeOffset_); |
| } |
| |
| PropertyName *name() const { |
| return fun_->name(); |
| } |
| JSFunction *unclonedFunObj() const { |
| return fun_; |
| } |
| PropertyName *maybeFieldName() const { |
| return maybeFieldName_; |
| } |
| unsigned numArgs() const { |
| return argCoercions_.length(); |
| } |
| AsmJSCoercion argCoercion(unsigned i) const { |
| return argCoercions_[i]; |
| } |
| ReturnType returnType() const { |
| return returnType_; |
| } |
| CodePtr code() const { |
| JS_ASSERT(hasCodePtr_); |
| return u.code_; |
| } |
| }; |
| |
| #if defined(MOZ_VTUNE) |
| // Function information to add to the VTune JIT profiler following linking. |
| struct ProfiledFunction |
| { |
| JSAtom *name; |
| unsigned startCodeOffset; |
| unsigned endCodeOffset; |
| |
| ProfiledFunction(JSAtom *name, unsigned start, unsigned end) |
| : name(name), startCodeOffset(start), endCodeOffset(end) |
| { } |
| }; |
| #endif |
| |
| // If linking fails, we recompile the function as if it's ordinary JS. |
| // This struct holds the data required to do this. |
| struct PostLinkFailureInfo |
| { |
| CompileOptions options_; |
| ScriptSource * scriptSource_; |
| uint32_t bufStart_; // offset of the function body's start |
| uint32_t bufEnd_; // offset of the function body's end |
| |
| PostLinkFailureInfo(JSContext *cx) |
| : options_(cx), |
| scriptSource_(), |
| bufStart_(), |
| bufEnd_() |
| { } |
| |
| void init(CompileOptions options, ScriptSource *scriptSource, |
| uint32_t bufStart, uint32_t bufEnd) |
| { |
| options_ = options; |
| scriptSource_ = scriptSource; |
| bufStart_ = bufStart; |
| bufEnd_ = bufEnd; |
| |
| scriptSource_->incref(); |
| } |
| |
| ~PostLinkFailureInfo() { |
| if (scriptSource_) |
| scriptSource_->decref(); |
| } |
| }; |
| |
| private: |
| typedef Vector<ExportedFunction, 0, SystemAllocPolicy> ExportedFunctionVector; |
| typedef Vector<Global, 0, SystemAllocPolicy> GlobalVector; |
| typedef Vector<Exit, 0, SystemAllocPolicy> ExitVector; |
| typedef Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> HeapAccessVector; |
| #if defined(JS_CPU_ARM) |
| typedef Vector<jit::AsmJSBoundsCheck, 0, SystemAllocPolicy> BoundsCheckVector; |
| #endif |
| typedef Vector<jit::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector; |
| #if defined(MOZ_VTUNE) |
| typedef Vector<ProfiledFunction, 0, SystemAllocPolicy> ProfiledFunctionVector; |
| #endif |
| |
| GlobalVector globals_; |
| ExitVector exits_; |
| ExportedFunctionVector exports_; |
| HeapAccessVector heapAccesses_; |
| #if defined(JS_CPU_ARM) |
| BoundsCheckVector boundsChecks_; |
| #endif |
| #if defined(MOZ_VTUNE) |
| ProfiledFunctionVector profiledFunctions_; |
| #endif |
| |
| uint32_t numGlobalVars_; |
| uint32_t numFFIs_; |
| uint32_t numFuncPtrTableElems_; |
| bool hasArrayView_; |
| |
| ScopedReleasePtr<JSC::ExecutablePool> codePool_; |
| uint8_t * code_; |
| uint8_t * operationCallbackExit_; |
| size_t functionBytes_; |
| size_t codeBytes_; |
| size_t totalBytes_; |
| |
| bool linked_; |
| HeapPtr<ArrayBufferObject> maybeHeap_; |
| |
| HeapPtrPropertyName globalArgumentName_; |
| HeapPtrPropertyName importArgumentName_; |
| HeapPtrPropertyName bufferArgumentName_; |
| |
| PostLinkFailureInfo postLinkFailureInfo_; |
| |
| FunctionCountsVector functionCounts_; |
| |
| public: |
| explicit AsmJSModule(JSContext *cx) |
| : numGlobalVars_(0), |
| numFFIs_(0), |
| numFuncPtrTableElems_(0), |
| hasArrayView_(false), |
| code_(NULL), |
| operationCallbackExit_(NULL), |
| functionBytes_(0), |
| codeBytes_(0), |
| totalBytes_(0), |
| linked_(false), |
| maybeHeap_(), |
| postLinkFailureInfo_(cx) |
| {} |
| |
| ~AsmJSModule(); |
| |
| void trace(JSTracer *trc) { |
| for (unsigned i = 0; i < globals_.length(); i++) |
| globals_[i].trace(trc); |
| for (unsigned i = 0; i < exports_.length(); i++) |
| exports_[i].trace(trc); |
| for (unsigned i = 0; i < exits_.length(); i++) { |
| if (exitIndexToGlobalDatum(i).fun) |
| MarkObject(trc, &exitIndexToGlobalDatum(i).fun, "asm.js imported function"); |
| } |
| if (maybeHeap_) |
| MarkObject(trc, &maybeHeap_, "asm.js heap"); |
| |
| if (globalArgumentName_) |
| MarkString(trc, &globalArgumentName_, "asm.js global argument name"); |
| if (importArgumentName_) |
| MarkString(trc, &importArgumentName_, "asm.js import argument name"); |
| if (bufferArgumentName_) |
| MarkString(trc, &bufferArgumentName_, "asm.js buffer argument name"); |
| } |
| |
| bool addGlobalVarInitConstant(const Value &v, uint32_t *globalIndex) { |
| JS_ASSERT(!v.isMarkable()); |
| if (numGlobalVars_ == UINT32_MAX) |
| return false; |
| Global g(Global::Variable); |
| g.u.var.initKind_ = Global::InitConstant; |
| g.u.var.init.constant_ = v; |
| g.u.var.index_ = *globalIndex = numGlobalVars_++; |
| return globals_.append(g); |
| } |
| bool addGlobalVarImport(PropertyName *fieldName, AsmJSCoercion coercion, uint32_t *globalIndex) { |
| Global g(Global::Variable); |
| g.u.var.initKind_ = Global::InitImport; |
| g.u.var.init.coercion_ = coercion; |
| g.u.var.index_ = *globalIndex = numGlobalVars_++; |
| g.name_ = fieldName; |
| return globals_.append(g); |
| } |
| bool incrementNumFuncPtrTableElems(uint32_t numElems) { |
| if (UINT32_MAX - numFuncPtrTableElems_ < numElems) |
| return false; |
| numFuncPtrTableElems_ += numElems; |
| return true; |
| } |
| bool addFFI(PropertyName *field, uint32_t *ffiIndex) { |
| if (numFFIs_ == UINT32_MAX) |
| return false; |
| Global g(Global::FFI); |
| g.u.ffiIndex_ = *ffiIndex = numFFIs_++; |
| g.name_ = field; |
| return globals_.append(g); |
| } |
| bool addArrayView(ArrayBufferView::ViewType vt, PropertyName *field) { |
| hasArrayView_ = true; |
| Global g(Global::ArrayView); |
| g.u.viewType_ = vt; |
| g.name_ = field; |
| return globals_.append(g); |
| } |
| bool addMathBuiltin(AsmJSMathBuiltin mathBuiltin, PropertyName *field) { |
| Global g(Global::MathBuiltin); |
| g.u.mathBuiltin_ = mathBuiltin; |
| g.name_ = field; |
| return globals_.append(g); |
| } |
| bool addGlobalConstant(double value, PropertyName *fieldName) { |
| Global g(Global::Constant); |
| g.u.constantValue_ = value; |
| g.name_ = fieldName; |
| return globals_.append(g); |
| } |
| bool addExit(unsigned ffiIndex, unsigned *exitIndex) { |
| *exitIndex = unsigned(exits_.length()); |
| return exits_.append(Exit(ffiIndex)); |
| } |
| bool addFunctionCounts(jit::IonScriptCounts *counts) { |
| return functionCounts_.append(counts); |
| } |
| |
| bool addExportedFunction(JSFunction *fun, PropertyName *maybeFieldName, |
| MoveRef<ArgCoercionVector> argCoercions, ReturnType returnType) |
| { |
| ExportedFunction func(fun, maybeFieldName, argCoercions, returnType); |
| return exports_.append(Move(func)); |
| } |
| unsigned numExportedFunctions() const { |
| return exports_.length(); |
| } |
| const ExportedFunction &exportedFunction(unsigned i) const { |
| return exports_[i]; |
| } |
| ExportedFunction &exportedFunction(unsigned i) { |
| return exports_[i]; |
| } |
| #ifdef MOZ_VTUNE |
| bool trackProfiledFunction(JSAtom *name, unsigned startCodeOffset, unsigned endCodeOffset) { |
| ProfiledFunction func(name, startCodeOffset, endCodeOffset); |
| return profiledFunctions_.append(func); |
| } |
| unsigned numProfiledFunctions() const { |
| return profiledFunctions_.length(); |
| } |
| const ProfiledFunction &profiledFunction(unsigned i) const { |
| return profiledFunctions_[i]; |
| } |
| #endif |
| bool hasArrayView() const { |
| return hasArrayView_; |
| } |
| unsigned numFFIs() const { |
| return numFFIs_; |
| } |
| unsigned numGlobalVars() const { |
| return numGlobalVars_; |
| } |
| unsigned numGlobals() const { |
| return globals_.length(); |
| } |
| Global &global(unsigned i) { |
| return globals_[i]; |
| } |
| unsigned numFuncPtrTableElems() const { |
| return numFuncPtrTableElems_; |
| } |
| unsigned numExits() const { |
| return exits_.length(); |
| } |
| Exit &exit(unsigned i) { |
| return exits_[i]; |
| } |
| const Exit &exit(unsigned i) const { |
| return exits_[i]; |
| } |
| unsigned numFunctionCounts() const { |
| return functionCounts_.length(); |
| } |
| jit::IonScriptCounts *functionCounts(unsigned i) { |
| return functionCounts_[i]; |
| } |
| |
| // An Exit holds bookkeeping information about an exit; the ExitDatum |
| // struct overlays the actual runtime data stored in the global data |
| // section. |
| struct ExitDatum |
| { |
| uint8_t *exit; |
| HeapPtrFunction fun; |
| }; |
| |
| // Global data section |
| // |
| // The global data section is placed after the executable code (i.e., at |
| // offset codeBytes_) in the module's linear allocation. The global data |
| // are laid out in this order: |
| // 0. a pointer/descriptor for the heap that was linked to the module |
| // 1. global variable state (elements are sizeof(uint64_t)) |
| // 2. function-pointer table elements (elements are sizeof(void*)) |
| // 3. exits (elements are sizeof(ExitDatum)) |
| // |
| // NB: The list of exits is extended while emitting function bodies and |
| // thus exits must be at the end of the list to avoid invalidating indices. |
| uint8_t *globalData() const { |
| JS_ASSERT(code_); |
| return code_ + codeBytes_; |
| } |
| |
| size_t globalDataBytes() const { |
| return sizeof(void*) + |
| numGlobalVars_ * sizeof(uint64_t) + |
| numFuncPtrTableElems_ * sizeof(void*) + |
| exits_.length() * sizeof(ExitDatum); |
| } |
| unsigned heapOffset() const { |
| return 0; |
| } |
| uint8_t *&heapDatum() const { |
| return *(uint8_t**)(globalData() + heapOffset()); |
| } |
| unsigned globalVarIndexToGlobalDataOffset(unsigned i) const { |
| JS_ASSERT(i < numGlobalVars_); |
| return sizeof(void*) + |
| i * sizeof(uint64_t); |
| } |
| void *globalVarIndexToGlobalDatum(unsigned i) const { |
| return (void *)(globalData() + globalVarIndexToGlobalDataOffset(i)); |
| } |
| unsigned funcPtrIndexToGlobalDataOffset(unsigned i) const { |
| return sizeof(void*) + |
| numGlobalVars_ * sizeof(uint64_t) + |
| i * sizeof(void*); |
| } |
| void *&funcPtrIndexToGlobalDatum(unsigned i) const { |
| return *(void **)(globalData() + funcPtrIndexToGlobalDataOffset(i)); |
| } |
| unsigned exitIndexToGlobalDataOffset(unsigned exitIndex) const { |
| JS_ASSERT(exitIndex < exits_.length()); |
| return sizeof(void*) + |
| numGlobalVars_ * sizeof(uint64_t) + |
| numFuncPtrTableElems_ * sizeof(void*) + |
| exitIndex * sizeof(ExitDatum); |
| } |
| ExitDatum &exitIndexToGlobalDatum(unsigned exitIndex) const { |
| return *(ExitDatum *)(globalData() + exitIndexToGlobalDataOffset(exitIndex)); |
| } |
| |
| void setFunctionBytes(size_t functionBytes) { |
| JS_ASSERT(functionBytes % AsmJSPageSize == 0); |
| functionBytes_ = functionBytes; |
| } |
| size_t functionBytes() const { |
| JS_ASSERT(functionBytes_); |
| JS_ASSERT(functionBytes_ % AsmJSPageSize == 0); |
| return functionBytes_; |
| } |
| bool containsPC(void *pc) const { |
| uint8_t *code = functionCode(); |
| return pc >= code && pc < (code + functionBytes()); |
| } |
| |
| bool addHeapAccesses(const jit::AsmJSHeapAccessVector &accesses) { |
| return heapAccesses_.append(accesses); |
| } |
| unsigned numHeapAccesses() const { |
| return heapAccesses_.length(); |
| } |
| jit::AsmJSHeapAccess &heapAccess(unsigned i) { |
| return heapAccesses_[i]; |
| } |
| const jit::AsmJSHeapAccess &heapAccess(unsigned i) const { |
| return heapAccesses_[i]; |
| } |
| #if defined(JS_CPU_ARM) |
| bool addBoundsChecks(const jit::AsmJSBoundsCheckVector &checks) { |
| return boundsChecks_.append(checks); |
| } |
| void convertBoundsChecksToActualOffset(jit::MacroAssembler &masm) { |
| for (unsigned i = 0; i < boundsChecks_.length(); i++) |
| boundsChecks_[i].setOffset(masm.actualOffset(boundsChecks_[i].offset())); |
| } |
| |
| void patchBoundsChecks(unsigned heapSize) { |
| jit::AutoFlushCache afc("patchBoundsCheck"); |
| int bits = -1; |
| JS_CEILING_LOG2(bits, heapSize); |
| if (bits == -1) { |
| // tried to size the array to 0, that is bad, but not horrible |
| return; |
| } |
| |
| for (unsigned i = 0; i < boundsChecks_.length(); i++) |
| jit::Assembler::updateBoundsCheck(bits, (jit::Instruction*)(boundsChecks_[i].offset() + code_)); |
| |
| } |
| unsigned numBoundsChecks() const { |
| return boundsChecks_.length(); |
| } |
| const jit::AsmJSBoundsCheck &boundsCheck(unsigned i) const { |
| return boundsChecks_[i]; |
| } |
| #endif |
| |
| |
| |
| void takeOwnership(JSC::ExecutablePool *pool, uint8_t *code, size_t codeBytes, size_t totalBytes) { |
| JS_ASSERT(uintptr_t(code) % AsmJSPageSize == 0); |
| codePool_ = pool; |
| code_ = code; |
| codeBytes_ = codeBytes; |
| totalBytes_ = totalBytes; |
| } |
| uint8_t *functionCode() const { |
| JS_ASSERT(code_); |
| JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0); |
| return code_; |
| } |
| |
| void setOperationCallbackExit(uint8_t *ptr) { |
| operationCallbackExit_ = ptr; |
| } |
| uint8_t *operationCallbackExit() const { |
| return operationCallbackExit_; |
| } |
| |
| void setIsLinked(Handle<ArrayBufferObject*> maybeHeap) { |
| JS_ASSERT(!linked_); |
| linked_ = true; |
| maybeHeap_ = maybeHeap; |
| heapDatum() = maybeHeap_ ? maybeHeap_->dataPointer() : NULL; |
| } |
| bool isLinked() const { |
| return linked_; |
| } |
| uint8_t *maybeHeap() const { |
| JS_ASSERT(linked_); |
| return heapDatum(); |
| } |
| size_t heapLength() const { |
| JS_ASSERT(linked_); |
| return maybeHeap_ ? maybeHeap_->byteLength() : 0; |
| } |
| |
| void initGlobalArgumentName(PropertyName *n) { globalArgumentName_ = n; } |
| void initImportArgumentName(PropertyName *n) { importArgumentName_ = n; } |
| void initBufferArgumentName(PropertyName *n) { bufferArgumentName_ = n; } |
| |
| PropertyName *globalArgumentName() const { return globalArgumentName_; } |
| PropertyName *importArgumentName() const { return importArgumentName_; } |
| PropertyName *bufferArgumentName() const { return bufferArgumentName_; } |
| |
| void initPostLinkFailureInfo(CompileOptions options, |
| ScriptSource *scriptSource, uint32_t bufStart, uint32_t bufEnd) { |
| options.filename = scriptSource->filename(); |
| postLinkFailureInfo_.init(options, scriptSource, bufStart, bufEnd); |
| } |
| |
| const PostLinkFailureInfo &postLinkFailureInfo() const { |
| return postLinkFailureInfo_; |
| } |
| |
| size_t exitDatumToExitIndex(ExitDatum *exit) const { |
| ExitDatum *first = &exitIndexToGlobalDatum(0); |
| JS_ASSERT(exit >= first && exit < first + numExits()); |
| return exit - first; |
| } |
| |
| void detachIonCompilation(size_t exitIndex) const { |
| ExitDatum &exitDatum = exitIndexToGlobalDatum(exitIndex); |
| exitDatum.exit = exit(exitIndex).interpCode(); |
| } |
| }; |
| |
| |
| // The AsmJSModule C++ object is held by a JSObject that takes care of calling |
| // 'trace' and the destructor on finalization. |
| extern AsmJSModule & |
| AsmJSModuleObjectToModule(JSObject *obj); |
| |
| extern bool |
| IsAsmJSModuleObject(JSObject *obj); |
| |
| extern JSObject & |
| AsmJSModuleObject(JSFunction *moduleFun); |
| |
| extern void |
| SetAsmJSModuleObject(JSFunction *moduleFun, JSObject *moduleObj); |
| |
| } // namespace js |
| |
| #endif // JS_ION |
| |
| #endif /* jit_AsmJSModule_h */ |