diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 1eb401b6eaf..b98763c03ab 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -15,6 +15,7 @@ #include "jswrapper.h" #include "ion/AsmJS.h" +#include "ion/AsmJSLink.h" #include "vm/ForkJoin.h" #include "vm/Interpreter.h" @@ -984,32 +985,6 @@ GetObjectMetadata(JSContext *cx, unsigned argc, jsval *vp) return true; } -#ifndef JS_ION -JSBool -js::IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - args.rval().set(BooleanValue(false)); - return true; -} - -JSBool -js::IsAsmJSModule(JSContext *cx, unsigned argc, Value *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - args.rval().set(BooleanValue(false)); - return true; -} - -JSBool -js::IsAsmJSFunction(JSContext *cx, unsigned argc, Value *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - args.rval().set(BooleanValue(false)); - return true; -} -#endif - static JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'compartment')", diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index a1d82f0429d..fc1cc15b9b8 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -12,7 +12,7 @@ #include "frontend/FoldConstants.h" #include "frontend/NameFunctions.h" #include "frontend/Parser.h" -#include "ion/AsmJS.h" +#include "ion/AsmJSLink.h" #include "vm/GlobalObject.h" #include "jsobjinlines.h" diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 352fc9a077b..2d577d6e53b 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -28,7 +28,7 @@ #include "frontend/Parser.h" #include "frontend/TokenStream.h" -#include "ion/AsmJS.h" +#include "ion/AsmJSLink.h" #include "vm/Debugger.h" #include "jsatominlines.h" diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index b5c88c81741..5be2c775254 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -33,6 +33,7 @@ #include "frontend/FoldConstants.h" #include "frontend/ParseMaps.h" #include "frontend/TokenStream.h" +#include "ion/AsmJS.h" #include "vm/NumericConversions.h" #include "vm/RegExpStatics.h" #include "vm/Shape.h" diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index eb43a8258f0..90aeb03471d 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -14,7 +14,6 @@ #include "jsmath.h" #include "jsworkers.h" -#include "jswrapper.h" #include "prmjtime.h" #include "frontend/Parser.h" @@ -2531,88 +2530,6 @@ class FunctionCompiler } }; -/*****************************************************************************/ -// An AsmJSModule contains the persistent results of asm.js module compilation, -// viz., the jit code and dynamic link information. -// -// An AsmJSModule object is created at the end of module compilation and -// subsequently owned by an AsmJSModuleClass JSObject. - -static void AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj); -static void AsmJSModuleObject_trace(JSTracer *trc, JSObject *obj); - -static const unsigned ASM_CODE_RESERVED_SLOT = 0; -static const unsigned ASM_CODE_NUM_RESERVED_SLOTS = 1; - -static Class AsmJSModuleClass = { - "AsmJSModuleObject", - JSCLASS_IS_ANONYMOUS | JSCLASS_IMPLEMENTS_BARRIERS | - JSCLASS_HAS_RESERVED_SLOTS(ASM_CODE_NUM_RESERVED_SLOTS), - JS_PropertyStub, /* addProperty */ - JS_DeletePropertyStub, /* delProperty */ - JS_PropertyStub, /* getProperty */ - JS_StrictPropertyStub, /* setProperty */ - JS_EnumerateStub, - JS_ResolveStub, - NULL, /* convert */ - AsmJSModuleObject_finalize, - NULL, /* checkAccess */ - NULL, /* call */ - NULL, /* hasInstance */ - NULL, /* construct */ - AsmJSModuleObject_trace -}; - -AsmJSModule & -js::AsmJSModuleObjectToModule(JSObject *obj) -{ - JS_ASSERT(obj->getClass() == &AsmJSModuleClass); - return *(AsmJSModule *)obj->getReservedSlot(ASM_CODE_RESERVED_SLOT).toPrivate(); -} - -bool -js::IsAsmJSModuleObject(JSObject *obj) -{ - return obj->getClass() == &AsmJSModuleClass; -} - -static const unsigned ASM_MODULE_FUNCTION_MODULE_OBJECT_SLOT = 0; - -JSObject & -js::AsmJSModuleObject(JSFunction *moduleFun) -{ - return moduleFun->getExtendedSlot(ASM_MODULE_FUNCTION_MODULE_OBJECT_SLOT).toObject(); -} - -void -js::SetAsmJSModuleObject(JSFunction *moduleFun, JSObject *moduleObj) -{ - moduleFun->setExtendedSlot(ASM_MODULE_FUNCTION_MODULE_OBJECT_SLOT, OBJECT_TO_JSVAL(moduleObj)); -} - -static void -AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj) -{ - fop->delete_(&AsmJSModuleObjectToModule(obj)); -} - -static void -AsmJSModuleObject_trace(JSTracer *trc, JSObject *obj) -{ - AsmJSModuleObjectToModule(obj).trace(trc); -} - -static JSObject * -NewAsmJSModuleObject(JSContext *cx, ScopedJSDeletePtr *module) -{ - JSObject *obj = NewObjectWithGivenProto(cx, &AsmJSModuleClass, NULL, NULL); - if (!obj) - return NULL; - - obj->setReservedSlot(ASM_CODE_RESERVED_SLOT, PrivateValue(module->forget())); - return obj; -} - /*****************************************************************************/ // asm.js type-checking and code-generation algorithm @@ -6391,24 +6308,13 @@ js::CompileAsmJS(JSContext *cx, AsmJSParser &parser, ParseNode *stmtList, bool * if (!moduleObj) return false; - ParseNode *fn = parser.pc->maybeFunction; - RootedFunction origFun(cx, fn->pn_funbox->function()); - RootedPropertyName name(cx, origFun->name()); - RootedFunction moduleFun(cx, NewFunction(cx, NullPtr(), LinkAsmJS, origFun->nargs, - JSFunction::NATIVE_FUN, NullPtr(), name, - JSFunction::ExtendedFinalizeKind, TenuredObject)); + FunctionBox *funbox = parser.pc->maybeFunction->pn_funbox; + RootedFunction moduleFun(cx, NewAsmJSModuleFunction(cx, funbox->function(), moduleObj)); if (!moduleFun) return false; - SetAsmJSModuleObject(moduleFun, moduleObj); - - // Replace the old interpreted function (which will now become garbage) - // with the new LinkAsmJS native function. This allows us to avoid creating - // bytecode for the entire asm.js module (which can be quite large). If - // link-time validation fails, LinkAsmJS will re-parse the whole module. - JS_ASSERT(fn->pn_funbox->function()->isInterpreted()); - fn->pn_funbox->object = moduleFun; - JS_ASSERT(IsAsmJSModuleNative(fn->pn_funbox->function()->native())); + JS_ASSERT(funbox->function()->isInterpreted()); + funbox->object = moduleFun; *validated = true; return Warn(cx, JSMSG_USE_ASM_TYPE_OK, compilationTimeReport); @@ -6426,58 +6332,3 @@ js::IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp) args.rval().set(BooleanValue(available)); return true; } - -static bool -IsMaybeWrappedNativeFunction(const Value &v, Native native) -{ - if (!v.isObject()) - return false; - - JSObject *obj = CheckedUnwrap(&v.toObject()); - if (!obj) - return false; - - return obj->is() && obj->as().maybeNative() == native; -} - -JSBool -js::IsAsmJSModule(JSContext *cx, unsigned argc, Value *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - bool rval = args.hasDefined(0) && IsMaybeWrappedNativeFunction(args[0], LinkAsmJS); - args.rval().set(BooleanValue(rval)); - return true; -} - -JSBool -js::IsAsmJSFunction(JSContext *cx, unsigned argc, Value *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - bool rval = args.hasDefined(0) && IsMaybeWrappedNativeFunction(args[0], CallAsmJS); - args.rval().set(BooleanValue(rval)); - return true; -} - -AsmJSModule::~AsmJSModule() -{ - if (code_) { - for (unsigned i = 0; i < numExits(); i++) { - AsmJSModule::ExitDatum &exitDatum = exitIndexToGlobalDatum(i); - if (!exitDatum.fun) - continue; - - if (!exitDatum.fun->hasScript()) - continue; - - JSScript *script = exitDatum.fun->nonLazyScript(); - if (!script->hasIonScript()) - continue; - - DependentAsmJSModuleExit exit(this, i); - script->ionScript()->removeDependentAsmJSModule(exit); - } - } - - for (size_t i = 0; i < numFunctionCounts(); i++) - js_delete(functionCounts(i)); -} diff --git a/js/src/ion/AsmJS.h b/js/src/ion/AsmJS.h index df869d73810..1a516e07215 100644 --- a/js/src/ion/AsmJS.h +++ b/js/src/ion/AsmJS.h @@ -7,34 +7,18 @@ #ifndef ion_AsmJS_h #define ion_AsmJS_h -#ifdef XP_MACOSX -# include -# include -#endif - -#include "jstypes.h" - -#include "ds/LifoAlloc.h" -#include "js/CallArgs.h" - -struct JSContext; -struct JSRuntime; +#include "jsapi.h" namespace js { -class ScriptSource; -class SPSProfiler; class AsmJSModule; +class SPSProfiler; namespace frontend { template struct Parser; template struct ParseContext; class FullParseHandler; struct ParseNode; } -namespace ion { - class MIRGenerator; - class LIRGraph; -} typedef frontend::Parser AsmJSParser; typedef frontend::ParseContext AsmJSParseContext; @@ -47,25 +31,6 @@ typedef frontend::ParseContext AsmJSParseContext; extern bool CompileAsmJS(JSContext *cx, AsmJSParser &parser, frontend::ParseNode *stmtList, bool *validated); -// Implements the semantics of an asm.js module function that has been successfully validated. -// A successfully validated asm.js module does not have bytecode emitted, but rather a list of -// dynamic constraints that must be satisfied by the arguments passed by the caller. If these -// constraints are satisfied, then LinkAsmJS can return CallAsmJS native functions that trampoline -// into compiled code. If any of the constraints fails, LinkAsmJS reparses the entire asm.js module -// from source so that it can be run as plain bytecode. -extern JSBool -LinkAsmJS(JSContext *cx, unsigned argc, JS::Value *vp); - -// The JSNative for the functions nested in an asm.js module. Calling this -// native will trampoline into generated code. -extern JSBool -CallAsmJS(JSContext *cx, unsigned argc, JS::Value *vp); - -// Force any currently-executing asm.js code to call -// js_HandleExecutionInterrupt. -void -TriggerOperationCallbackForAsmJSCode(JSRuntime *rt); - // The JSRuntime maintains a stack of AsmJSModule activations. An "activation" // of module A is an initial call from outside A into a function inside A, // followed by a sequence of calls inside A, and terminated by a call that @@ -116,89 +81,25 @@ static const size_t AsmJSAllocationGranularity = 4096; static const size_t AsmJSBufferProtectedSize = 4 * 1024ULL * 1024ULL * 1024ULL; #endif -#ifdef XP_MACOSX -class AsmJSMachExceptionHandler -{ - bool installed_; - pthread_t thread_; - mach_port_t port_; - - void release(); - - public: - AsmJSMachExceptionHandler(); - ~AsmJSMachExceptionHandler() { release(); } - mach_port_t port() const { return port_; } - bool installed() const { return installed_; } - bool install(JSRuntime *rt); - void clearCurrentThread(); - void setCurrentThread(); -}; -#endif - -struct DependentAsmJSModuleExit -{ - const AsmJSModule *module; - size_t exitIndex; - - DependentAsmJSModuleExit(const AsmJSModule *module, size_t exitIndex) - : module(module), - exitIndex(exitIndex) - { } -}; - -// Struct type for passing parallel compilation data between the main thread -// and compilation workers. -struct AsmJSParallelTask -{ - LifoAlloc lifo; // Provider of all heap memory used for compilation. - - void *func; // Really, a ModuleCompiler::Func* - ion::MIRGenerator *mir; // Passed from main thread to worker. - ion::LIRGraph *lir; // Passed from worker to main thread. - unsigned compileTime; - - AsmJSParallelTask(size_t defaultChunkSize) - : lifo(defaultChunkSize), func(NULL), mir(NULL), lir(NULL), compileTime(0) - { } - - void init(void *func, ion::MIRGenerator *mir) { - this->func = func; - this->mir = mir; - this->lir = NULL; - } -}; - -// Returns true if the given native is the one that is used to implement asm.js -// module functions. #ifdef JS_ION -extern bool -IsAsmJSModuleNative(JSNative native); -#else -inline bool -IsAsmJSModuleNative(JSNative native) -{ - return false; -} -#endif - -// Exposed for shell testing: // Return whether asm.js optimization is inhibitted by the platform or // dynamically disabled: extern JSBool IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, JS::Value *vp); -// Return whether the given value is a function containing "use asm" that has -// been validated according to the asm.js spec. -extern JSBool -IsAsmJSModule(JSContext *cx, unsigned argc, JS::Value *vp); +#else // JS_ION -// Return whether the given value is a nested function in an asm.js module that -// has been both compile- and link-time validated. -extern JSBool -IsAsmJSFunction(JSContext *cx, unsigned argc, JS::Value *vp); +inline JSBool +IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + args.rval().set(BooleanValue(false)); + return true; +} + +#endif // JS_ION } // namespace js -#endif /* ion_AsmJS_h */ +#endif // ion_AsmJS_h diff --git a/js/src/ion/AsmJSLink.cpp b/js/src/ion/AsmJSLink.cpp index 3a1ef768d57..e0de2367dfb 100644 --- a/js/src/ion/AsmJSLink.cpp +++ b/js/src/ion/AsmJSLink.cpp @@ -4,15 +4,16 @@ * 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/. */ +#include "ion/AsmJSLink.h" + #ifdef MOZ_VTUNE # include "jitprofiling.h" #endif - #include "jscntxt.h" #include "jsmath.h" +#include "jswrapper.h" #include "frontend/BytecodeCompiler.h" -#include "ion/AsmJS.h" #include "ion/AsmJSModule.h" #include "ion/Ion.h" #ifdef JS_ION_PERF @@ -23,7 +24,10 @@ using namespace js; using namespace js::ion; -using namespace mozilla; + +using mozilla::IsNaN; + +static const unsigned MODULE_FUN_SLOT = 0; static bool LinkFail(JSContext *cx, const char *str) @@ -309,8 +313,10 @@ AsmJSActivation::~AsmJSActivation() static const unsigned ASM_MODULE_SLOT = 0; static const unsigned ASM_EXPORT_INDEX_SLOT = 1; -extern JSBool -js::CallAsmJS(JSContext *cx, unsigned argc, Value *vp) +// The JSNative for the functions nested in an asm.js module. Calling this +// native will trampoline into generated code. +static JSBool +CallAsmJS(JSContext *cx, unsigned argc, Value *vp) { CallArgs callArgs = CallArgsFromVp(argc, vp); RootedFunction callee(cx, &callArgs.callee().as()); @@ -563,12 +569,18 @@ SendBlocksToPerf(JSContext *cx, AsmJSModule &module) } #endif -JSBool -js::LinkAsmJS(JSContext *cx, unsigned argc, JS::Value *vp) +// Implements the semantics of an asm.js module function that has been successfully validated. +// A successfully validated asm.js module does not have bytecode emitted, but rather a list of +// dynamic constraints that must be satisfied by the arguments passed by the caller. If these +// constraints are satisfied, then LinkAsmJS can return CallAsmJS native functions that trampoline +// into compiled code. If any of the constraints fails, LinkAsmJS reparses the entire asm.js module +// from source so that it can be run as plain bytecode. +static JSBool +LinkAsmJS(JSContext *cx, unsigned argc, JS::Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedFunction fun(cx, &args.callee().as()); - RootedObject moduleObj(cx, &AsmJSModuleObject(fun)); + RootedObject moduleObj(cx, &fun->getExtendedSlot(MODULE_FUN_SLOT).toObject()); AsmJSModule &module = AsmJSModuleObjectToModule(moduleObj); // If linking fails, recompile the function (including emitting bytecode) @@ -625,8 +637,53 @@ js::LinkAsmJS(JSContext *cx, unsigned argc, JS::Value *vp) return true; } +JSFunction * +js::NewAsmJSModuleFunction(JSContext *cx, JSFunction *origFun, HandleObject moduleObj) +{ + RootedPropertyName name(cx, origFun->name()); + JSFunction *moduleFun = NewFunction(cx, NullPtr(), LinkAsmJS, origFun->nargs, + JSFunction::NATIVE_FUN, NullPtr(), name, + JSFunction::ExtendedFinalizeKind, TenuredObject); + if (!moduleFun) + return NULL; + + moduleFun->setExtendedSlot(MODULE_FUN_SLOT, ObjectValue(*moduleObj)); + return moduleFun; +} + bool js::IsAsmJSModuleNative(js::Native native) { return native == LinkAsmJS; } + +static bool +IsMaybeWrappedNativeFunction(const Value &v, Native native) +{ + if (!v.isObject()) + return false; + + JSObject *obj = CheckedUnwrap(&v.toObject()); + if (!obj) + return false; + + return obj->is() && obj->as().maybeNative() == native; +} + +JSBool +js::IsAsmJSModule(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + bool rval = args.hasDefined(0) && IsMaybeWrappedNativeFunction(args[0], LinkAsmJS); + args.rval().set(BooleanValue(rval)); + return true; +} + +JSBool +js::IsAsmJSFunction(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + bool rval = args.hasDefined(0) && IsMaybeWrappedNativeFunction(args[0], CallAsmJS); + args.rval().set(BooleanValue(rval)); + return true; +} diff --git a/js/src/ion/AsmJSLink.h b/js/src/ion/AsmJSLink.h new file mode 100644 index 00000000000..232ee7e4a32 --- /dev/null +++ b/js/src/ion/AsmJSLink.h @@ -0,0 +1,63 @@ +/* -*- 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 ion_AsmJSLink_h +#define ion_AsmJSLink_h + +#include "jsapi.h" + +namespace js { + +#ifdef JS_ION + +// Create a new JSFunction to replace originalFun as the representation of the +// function defining the succesfully-validated module 'moduleObj'. +extern JSFunction * +NewAsmJSModuleFunction(JSContext *cx, JSFunction *originalFun, HandleObject moduleObj); + +// Return whether this is the js::Native returned by NewAsmJSModuleFunction. +extern bool +IsAsmJSModuleNative(JSNative native); + +// Return whether the given value is a function containing "use asm" that has +// been validated according to the asm.js spec. +extern JSBool +IsAsmJSModule(JSContext *cx, unsigned argc, JS::Value *vp); + +// Return whether the given value is a nested function in an asm.js module that +// has been both compile- and link-time validated. +extern JSBool +IsAsmJSFunction(JSContext *cx, unsigned argc, JS::Value *vp); + +#else // JS_ION + +inline bool +IsAsmJSModuleNative(JSNative native) +{ + return false; +} + +inline JSBool +IsAsmJSFunction(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + args.rval().set(BooleanValue(false)); + return true; +} + +inline JSBool +IsAsmJSModule(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + args.rval().set(BooleanValue(false)); + return true; +} + +#endif // JS_ION + +} // namespace js + +#endif // ion_AsmJS_h diff --git a/js/src/ion/AsmJSModule.cpp b/js/src/ion/AsmJSModule.cpp new file mode 100644 index 00000000000..6dfe283eaba --- /dev/null +++ b/js/src/ion/AsmJSModule.cpp @@ -0,0 +1,97 @@ +/* -*- 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/. */ + +#include "ion/AsmJSModule.h" +#include "ion/IonCode.h" + +#include "jsobjinlines.h" + +using namespace js; + +static void AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj); +static void AsmJSModuleObject_trace(JSTracer *trc, JSObject *obj); + +static const unsigned ASM_CODE_RESERVED_SLOT = 0; +static const unsigned ASM_CODE_NUM_RESERVED_SLOTS = 1; + +static Class AsmJSModuleClass = { + "AsmJSModuleObject", + JSCLASS_IS_ANONYMOUS | JSCLASS_IMPLEMENTS_BARRIERS | + JSCLASS_HAS_RESERVED_SLOTS(ASM_CODE_NUM_RESERVED_SLOTS), + JS_PropertyStub, /* addProperty */ + JS_DeletePropertyStub, /* delProperty */ + JS_PropertyStub, /* getProperty */ + JS_StrictPropertyStub, /* setProperty */ + JS_EnumerateStub, + JS_ResolveStub, + NULL, /* convert */ + AsmJSModuleObject_finalize, + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* hasInstance */ + NULL, /* construct */ + AsmJSModuleObject_trace +}; + +bool +js::IsAsmJSModuleObject(JSObject *obj) +{ + return obj->getClass() == &AsmJSModuleClass; +} + +AsmJSModule & +js::AsmJSModuleObjectToModule(JSObject *obj) +{ + JS_ASSERT(IsAsmJSModuleObject(obj)); + return *(AsmJSModule *)obj->getReservedSlot(ASM_CODE_RESERVED_SLOT).toPrivate(); +} + +static void +AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj) +{ + fop->delete_(&AsmJSModuleObjectToModule(obj)); +} + +static void +AsmJSModuleObject_trace(JSTracer *trc, JSObject *obj) +{ + AsmJSModuleObjectToModule(obj).trace(trc); +} + +JSObject * +js::NewAsmJSModuleObject(JSContext *cx, ScopedJSDeletePtr *module) +{ + JSObject *obj = NewObjectWithGivenProto(cx, &AsmJSModuleClass, NULL, NULL); + if (!obj) + return NULL; + + obj->setReservedSlot(ASM_CODE_RESERVED_SLOT, PrivateValue(module->forget())); + return obj; +} + +AsmJSModule::~AsmJSModule() +{ + if (code_) { + for (unsigned i = 0; i < numExits(); i++) { + AsmJSModule::ExitDatum &exitDatum = exitIndexToGlobalDatum(i); + if (!exitDatum.fun) + continue; + + if (!exitDatum.fun->hasScript()) + continue; + + JSScript *script = exitDatum.fun->nonLazyScript(); + if (!script->hasIonScript()) + continue; + + ion::DependentAsmJSModuleExit exit(this, i); + script->ionScript()->removeDependentAsmJSModule(exit); + } + } + + for (size_t i = 0; i < numFunctionCounts(); i++) + js_delete(functionCounts(i)); +} diff --git a/js/src/ion/AsmJSModule.h b/js/src/ion/AsmJSModule.h index dbc6e223619..273326dbd08 100644 --- a/js/src/ion/AsmJSModule.h +++ b/js/src/ion/AsmJSModule.h @@ -14,6 +14,7 @@ #include "jsscript.h" #include "gc/Marking.h" +#include "ion/AsmJS.h" #include "ion/IonMacroAssembler.h" #if defined(JS_ION_PERF) # include "ion/PerfSpewer.h" @@ -765,21 +766,20 @@ class AsmJSModule } }; +// On success, return an AsmJSModuleClass JSObject that has taken ownership +// (and release()ed) the given module. +extern JSObject * +NewAsmJSModuleObject(JSContext *cx, ScopedJSDeletePtr *module); + +// Return whether the given object was created by NewAsmJSModuleObject. +extern bool +IsAsmJSModuleObject(JSObject *obj); // 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 diff --git a/js/src/ion/AsmJSSignalHandlers.cpp b/js/src/ion/AsmJSSignalHandlers.cpp index c6105b6372e..eac715a9b15 100644 --- a/js/src/ion/AsmJSSignalHandlers.cpp +++ b/js/src/ion/AsmJSSignalHandlers.cpp @@ -4,10 +4,11 @@ * 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/. */ +#include "ion/AsmJSSignalHandlers.h" + #include "jscntxt.h" #include "assembler/assembler/MacroAssembler.h" -#include "ion/AsmJS.h" #include "ion/AsmJSModule.h" #include "vm/ObjectImpl-inl.h" diff --git a/js/src/ion/AsmJSSignalHandlers.h b/js/src/ion/AsmJSSignalHandlers.h new file mode 100644 index 00000000000..0c3b9608dd1 --- /dev/null +++ b/js/src/ion/AsmJSSignalHandlers.h @@ -0,0 +1,52 @@ +/* -*- 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 ion_AsmJSSignalHandlers_h +#define ion_AsmJSSignalHandlers_h + +struct JSRuntime; + +#ifdef XP_MACOSX +# include +# include +#endif + +namespace js { + +// Force any currently-executing asm.js code to call +// js_HandleExecutionInterrupt. +extern void +TriggerOperationCallbackForAsmJSCode(JSRuntime *rt); + +// On OSX we are forced to use the lower-level Mach exception mechanism instead +// of Unix signals. Mach exceptions are not handled on the victim's stack but +// rather require an extra thread. For simplicity, we create one such thread +// per JSRuntime (upon the first use of asm.js in the JSRuntime). This thread +// and related resources are owned by AsmJSMachExceptionHandler which is owned +// by JSRuntime. +#ifdef XP_MACOSX +class AsmJSMachExceptionHandler +{ + bool installed_; + pthread_t thread_; + mach_port_t port_; + + void release(); + + public: + AsmJSMachExceptionHandler(); + ~AsmJSMachExceptionHandler() { release(); } + mach_port_t port() const { return port_; } + bool installed() const { return installed_; } + bool install(JSRuntime *rt); + void clearCurrentThread(); + void setCurrentThread(); +}; +#endif + +} // namespace js + +#endif // ion_AsmJSSignalHandlers_h diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp index 4616bfc534b..72f6f595cf7 100644 --- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -15,9 +15,8 @@ #endif #include "gc/Marking.h" -#include "ion/AliasAnalysis.h" -#include "ion/AsmJS.h" #include "ion/AsmJSModule.h" +#include "ion/AliasAnalysis.h" #include "ion/BacktrackingAllocator.h" #include "ion/BaselineCompiler.h" #include "ion/BaselineInspector.h" diff --git a/js/src/ion/IonCode.h b/js/src/ion/IonCode.h index 92256c5b3c0..0e8db528b41 100644 --- a/js/src/ion/IonCode.h +++ b/js/src/ion/IonCode.h @@ -13,7 +13,6 @@ #include "jsinfer.h" #include "gc/Heap.h" -#include "ion/AsmJS.h" #include "ion/IonTypes.h" namespace JSC { @@ -23,6 +22,9 @@ namespace JSC { class JSScript; namespace js { + +class AsmJSModule; + namespace ion { // The maximum size of any buffer associated with an assembler or code object. @@ -145,6 +147,19 @@ class SafepointIndex; class OsiIndex; class IonCache; +// Describes a single AsmJSModule which jumps (via an FFI exit with the given +// index) directly into an IonScript. +struct DependentAsmJSModuleExit +{ + const AsmJSModule *module; + size_t exitIndex; + + DependentAsmJSModuleExit(const AsmJSModule *module, size_t exitIndex) + : module(module), + exitIndex(exitIndex) + { } +}; + // An IonScript attaches Ion-generated information to a JSScript. struct IonScript { diff --git a/js/src/ion/IonMacroAssembler.cpp b/js/src/ion/IonMacroAssembler.cpp index 62fe22b9a26..cb6553efb16 100644 --- a/js/src/ion/IonMacroAssembler.cpp +++ b/js/src/ion/IonMacroAssembler.cpp @@ -8,7 +8,6 @@ #include "jsinfer.h" -#include "ion/AsmJS.h" #include "ion/Bailouts.h" #include "ion/BaselineFrame.h" #include "ion/BaselineIC.h" diff --git a/js/src/ion/IonMacroAssembler.h b/js/src/ion/IonMacroAssembler.h index 28affcb2d04..152ddd61579 100644 --- a/js/src/ion/IonMacroAssembler.h +++ b/js/src/ion/IonMacroAssembler.h @@ -18,7 +18,6 @@ #elif defined(JS_CPU_ARM) # include "ion/arm/MacroAssembler-arm.h" #endif -#include "ion/AsmJS.h" #include "ion/IonCompartment.h" #include "ion/IonInstrumentation.h" #include "ion/ParallelFunctions.h" diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index df18c000613..8e298503931 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -61,7 +61,7 @@ #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit #include "gc/Marking.h" #include "gc/Memory.h" -#include "ion/AsmJS.h" +#include "ion/AsmJSLink.h" #include "js/CharacterEncoding.h" #if ENABLE_INTL_API #include "unicode/uclean.h" diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 21459091e5d..67580e7a370 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -25,10 +25,7 @@ #include "jswatchpoint.h" #include "frontend/SourceNotes.h" -#include "ion/AsmJS.h" -#ifdef JS_ION #include "ion/AsmJSModule.h" -#endif #include "vm/Debugger.h" #include "vm/Interpreter.h" #include "vm/Shape.h" diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index d17778e1971..44fb83041a2 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -14,7 +14,7 @@ #include "jsfun.h" #include "jsopcode.h" -#include "ion/AsmJS.h" +#include "ion/AsmJSLink.h" #include "vm/GlobalObject.h" #include "vm/RegExpObject.h" #include "vm/Shape.h" diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index b8776addd87..4bd467122dc 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -13,7 +13,6 @@ #include "frontend/BytecodeCompiler.h" #ifdef JS_WORKER_THREADS -# include "ion/AsmJS.h" # include "ion/ExecutionModeInlines.h" # include "ion/IonBuilder.h" #endif diff --git a/js/src/jsworkers.h b/js/src/jsworkers.h index bbcaa1c6637..fcab0a96089 100644 --- a/js/src/jsworkers.h +++ b/js/src/jsworkers.h @@ -23,8 +23,9 @@ namespace js { +struct WorkerThread; struct AsmJSParallelTask; - +struct ParseTask; namespace ion { class IonBuilder; } @@ -32,10 +33,6 @@ namespace ion { #if defined(JS_THREADSAFE) && defined(JS_ION) # define JS_WORKER_THREADS -struct WorkerThread; -struct AsmJSParallelTask; -struct ParseTask; - /* Per-runtime state for off thread work items. */ class WorkerThreadState { @@ -309,6 +306,27 @@ PauseOffThreadParsing(); void ResumeOffThreadParsing(); +#ifdef JS_ION +struct AsmJSParallelTask +{ + LifoAlloc lifo; // Provider of all heap memory used for compilation. + void *func; // Really, a ModuleCompiler::Func* + ion::MIRGenerator *mir; // Passed from main thread to worker. + ion::LIRGraph *lir; // Passed from worker to main thread. + unsigned compileTime; + + AsmJSParallelTask(size_t defaultChunkSize) + : lifo(defaultChunkSize), func(NULL), mir(NULL), lir(NULL), compileTime(0) + { } + + void init(void *func, ion::MIRGenerator *mir) { + this->func = func; + this->mir = mir; + this->lir = NULL; + } +}; +#endif + struct ParseTask { JSRuntime *runtime; diff --git a/js/src/moz.build b/js/src/moz.build index b411206e74d..94f0b8b37e1 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -197,6 +197,7 @@ if CONFIG['ENABLE_ION']: 'AliasAnalysis.cpp', 'AsmJS.cpp', 'AsmJSLink.cpp', + 'AsmJSModule.cpp', 'AsmJSSignalHandlers.cpp', 'BacktrackingAllocator.cpp', 'Bailouts.cpp', diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index f14e86dbac0..de901133ed9 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -25,6 +25,7 @@ #include "jswrapper.h" #include "js/MemoryMetrics.h" +#include "ion/AsmJSSignalHandlers.h" #include "ion/IonCompartment.h" #include "ion/PcScriptCache.h" #include "yarr/BumpPointerAllocator.h" diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 2506f052308..7f7b75774e9 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -30,6 +30,7 @@ #include "gc/Nursery.h" #include "gc/Statistics.h" #include "gc/StoreBuffer.h" +#include "ion/AsmJSSignalHandlers.h" #include "js/HashTable.h" #include "js/Vector.h" #include "vm/DateTime.h" diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 9263278fca5..b0343ded422 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -31,6 +31,7 @@ #include "gc/Barrier.h" #include "gc/Marking.h" +#include "ion/AsmJS.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" #include "vm/NumericConversions.h"