diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 6f059b5fe0f..d469f9e090e 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -925,6 +925,22 @@ js::IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *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[] = { @@ -1071,6 +1087,16 @@ static JSFunctionSpecWithHelp TestingFunctions[] = { " Returns whether asm.js compilation is currently available or whether it is disabled\n" " (e.g., by the debugger)."), + JS_FN_HELP("isAsmJSModule", IsAsmJSModule, 1, 0, +"isAsmJSModule(fn)", +" Returns whether the given value is a function containing \"use asm\" that has been\n" +" validated according to the asm.js spec."), + + JS_FN_HELP("isAsmJSFunction", IsAsmJSFunction, 1, 0, +"isAsmJSModule(fn)", +" Returns whether the given value is a nested function in an asm.js module that has been\n" +" both compile- and link-time validated."), + JS_FN_HELP("inParallelSection", testingFunc_inParallelSection, 0, 0, "inParallelSection()", " True if this code is executing within a parallel section."), diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index f31d5b79e1d..240bed25187 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -5614,6 +5614,37 @@ js::IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp) 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->isFunction() && obj->toFunction()->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() { for (size_t i = 0; i < numFunctionCounts(); i++) diff --git a/js/src/ion/AsmJS.h b/js/src/ion/AsmJS.h index 98b297edcbc..a3fad37ac76 100644 --- a/js/src/ion/AsmJS.h +++ b/js/src/ion/AsmJS.h @@ -24,11 +24,6 @@ class AsmJSModule; namespace frontend { struct TokenStream; struct ParseNode; } namespace ion { class MIRGenerator; class LIRGraph; } -// Return whether asm.js optimization is inhibitted by the platform or -// dynamically disabled. (Exposed as JSNative for shell testing.) -extern JSBool -IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp); - // Called after parsing a function 'fn' which contains the "use asm" directive. // This function performs type-checking and code-generation. If type-checking // succeeds, the generated native function is assigned to |moduleFun|. @@ -51,6 +46,11 @@ CompileAsmJS(JSContext *cx, frontend::TokenStream &ts, frontend::ParseNode *fn, extern JSBool LinkAsmJS(JSContext *cx, unsigned argc, JS::Value *vp); +// The js::Native 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 @@ -157,6 +157,23 @@ IsAsmJSModuleNative(js::Native native) } #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, 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, 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, Value *vp); + } // namespace js #endif // jsion_asmjs_h__ diff --git a/js/src/ion/AsmJSLink.cpp b/js/src/ion/AsmJSLink.cpp index a7f18ca9014..bbbcea8083d 100644 --- a/js/src/ion/AsmJSLink.cpp +++ b/js/src/ion/AsmJSLink.cpp @@ -281,8 +281,8 @@ AsmJSActivation::~AsmJSActivation() static const unsigned ASM_MODULE_SLOT = 0; static const unsigned ASM_EXPORT_INDEX_SLOT = 1; -static JSBool -CallAsmJS(JSContext *cx, unsigned argc, Value *vp) +extern JSBool +js::CallAsmJS(JSContext *cx, unsigned argc, Value *vp) { CallArgs callArgs = CallArgsFromVp(argc, vp); RootedFunction callee(cx, callArgs.callee().toFunction()); diff --git a/js/src/jit-test/lib/asm.js b/js/src/jit-test/lib/asm.js index 9eb30ab41e2..ee2f998d84d 100644 --- a/js/src/jit-test/lib/asm.js +++ b/js/src/jit-test/lib/asm.js @@ -14,32 +14,9 @@ const BUF_64KB = new ArrayBuffer(64 * 1024); function asmCompile() { - if (!isAsmJSCompilationAvailable()) - return Function.apply(null, arguments); - - // asm.js emits a warning on successful compilation - - // Turn on warnings-as-errors - var oldOpts = options("werror"); - assertEq(oldOpts.indexOf("werror"), -1); - - // Verify that the code is succesfully compiled - var caught = false; - try { - Function.apply(null, arguments); - } catch (e) { - if ((''+e).indexOf(ASM_OK_STRING) == -1) - throw new Error("Didn't catch the expected success error; instead caught: " + e); - caught = true; - } - if (!caught) - throw new Error("Didn't catch the success error"); - - // Turn warnings-as-errors back off - options("werror"); - - // Compile for real - return Function.apply(null, arguments); + var f = Function.apply(null, arguments); + assertEq(!isAsmJSCompilationAvailable() || isAsmJSModule(f), true); + return f; } function assertAsmTypeFail() diff --git a/js/xpconnect/tests/mochitest/Makefile.in b/js/xpconnect/tests/mochitest/Makefile.in index 0a68a918a37..187221e95e1 100644 --- a/js/xpconnect/tests/mochitest/Makefile.in +++ b/js/xpconnect/tests/mochitest/Makefile.in @@ -95,6 +95,8 @@ MOCHITEST_FILES = chrome_wrappers_helper.html \ test_bug865260.html \ file_crosscompartment_weakmap.html \ test_crosscompartment_weakmap.html \ + test_asmjs.html \ + file_asmjs.js \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/js/xpconnect/tests/mochitest/file_asmjs.js b/js/xpconnect/tests/mochitest/file_asmjs.js new file mode 100644 index 00000000000..c51c5d78fb2 --- /dev/null +++ b/js/xpconnect/tests/mochitest/file_asmjs.js @@ -0,0 +1,26 @@ +function f(stdlib, foreign, buffer) { + "use asm"; + var i32 = new stdlib.Int32Array(buffer); + function main(n) { + n = n|0; + var i = 0, sum = 0; + for (; (i|0) < (n|0); i=(i+1)|0) + sum = (sum + (i32[(i<<2)>>2]|0))|0; + return sum|0; + } + return main; +} + +var i32 = new Int32Array(4096/4); +for (var i = 0; i < 100; i++) + i32[i] = i; + +var fMain = f(this, null, i32.buffer); +if (fMain(4) !== 6) + throw "f.main(4)"; +if (fMain(100) !== 4950) + throw "f.main(100)"; +if (fMain(3000000) !== 4950) + throw "f.main(3000000)"; + +postMessage("ok"); diff --git a/js/xpconnect/tests/mochitest/test_asmjs.html b/js/xpconnect/tests/mochitest/test_asmjs.html new file mode 100644 index 00000000000..b7a8d5c42af --- /dev/null +++ b/js/xpconnect/tests/mochitest/test_asmjs.html @@ -0,0 +1,61 @@ + + + + + + asm.js browser tests + + + + +asm.js browser tests +

+ +
+
+
+ +