зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1516697 - Remove the implementation of the asm.js caching mechanism. (APIs to invoke it still remain in place; they just don't do anything.) r=luke
This commit is contained in:
Родитель
bdfbf55e8a
Коммит
6796de0f32
|
@ -44,7 +44,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=929236
|
|||
evalAsync(code);
|
||||
break;
|
||||
case 1:
|
||||
ok(jsFuns.isAsmJSModuleLoadedFromCache(module), "module loaded from cache");
|
||||
ok(jsFuns.isAsmJSModule(module), "module");
|
||||
SimpleTest.finish();
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -18,8 +18,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=944821
|
|||
<script>
|
||||
var jsFuns = SpecialPowers.Cu.getJSTestingFunctions();
|
||||
|
||||
var assertCacheHit = false;
|
||||
|
||||
// generate four slightly different big asm.js modules and compile them async
|
||||
// so that we can hit the asm.js cache.
|
||||
|
||||
|
@ -36,7 +34,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=944821
|
|||
code2 += "return g" + i + ";\n";
|
||||
code2 += "}\n";
|
||||
code2 += "ok(jsFuns.isAsmJSModule(f), 'f is an asm.js module')\n";
|
||||
code2 += "if (assertCacheHit) ok(jsFuns.isAsmJSModuleLoadedFromCache(f), 'cache hit');\n";
|
||||
code2 += "var gX = f();\n";
|
||||
code2 += "ok(jsFuns.isAsmJSFunction(gX), 'gX is an asm.js function')\n";
|
||||
code2 += "ok(gX() === " + i + ", 'gX returns the correct result')\n";
|
||||
|
@ -58,7 +55,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=944821
|
|||
if (finishedCount < 1 || finishedCount > 2 * N) {
|
||||
throw "Huh?!";
|
||||
} else if (finishedCount == N) {
|
||||
assertCacheHit = true;
|
||||
for (let i = 0; i < N; i++)
|
||||
evalAsync(codes[i]);
|
||||
} else if (finishedCount == 2 * N) {
|
||||
|
|
|
@ -31,7 +31,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=941830
|
|||
var workerBlob = new Blob([workerCode], {type: "application/javascript"});
|
||||
|
||||
var mainCode = asmjsCode;
|
||||
mainCode += "ok(jsFuns.isAsmJSModuleLoadedFromCache(f), 'f is a cache hit')\n";
|
||||
mainCode += "ok(jsFuns.isAsmJSModule(f), 'f is a module')\n";
|
||||
mainCode += "var g42 = f();\n";
|
||||
mainCode += "ok(jsFuns.isAsmJSFunction(g42), 'g42 is an asm.js function');\n";
|
||||
mainCode += "ok(g42() === 42, 'g42 returns the correct result');\n";
|
||||
|
|
|
@ -5923,12 +5923,6 @@ gc::ZealModeHelpText),
|
|||
" 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("isAsmJSModuleLoadedFromCache", IsAsmJSModuleLoadedFromCache, 1, 0,
|
||||
"isAsmJSModuleLoadedFromCache(fn)",
|
||||
" Return whether the given asm.js module function has been loaded directly\n"
|
||||
" from the cache. This function throws an error if fn is not a validated asm.js\n"
|
||||
" module."),
|
||||
|
||||
JS_FN_HELP("isAsmJSFunction", IsAsmJSFunction, 1, 0,
|
||||
"isAsmJSFunction(fn)",
|
||||
" Returns whether the given value is a nested function in an asm.js module that has been\n"
|
||||
|
|
|
@ -26,20 +26,8 @@ function asmCompileCached()
|
|||
if (!isAsmJSCompilationAvailable())
|
||||
return Function.apply(null, arguments);
|
||||
|
||||
if (!isCachingEnabled()) {
|
||||
var f = Function.apply(null, arguments);
|
||||
assertEq(isAsmJSModule(f), true);
|
||||
return f;
|
||||
}
|
||||
|
||||
var quotedArgs = [];
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
quotedArgs.push("'" + arguments[i] + "'");
|
||||
var code = "setCachingEnabled(true); var f = new Function(" + quotedArgs.join(',') + ");assertEq(isAsmJSModule(f), true);";
|
||||
nestedShell("--js-cache", "--no-js-cache-per-process", "--execute=" + code);
|
||||
|
||||
var f = Function.apply(null, arguments);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(f), true);
|
||||
assertEq(isAsmJSModule(f), true);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
|
|
@ -56007,6 +56007,5 @@ function runBullet() {
|
|||
// Let the caller decide what should have happened.
|
||||
return {
|
||||
asmJSValidated: isAsmJSModule(asmModule) && isAsmJSFunction(asm._main),
|
||||
loadedFromCache: isAsmJSModule(asmModule) && isAsmJSModuleLoadedFromCache(asmModule)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
load(libdir + "asm.js");
|
||||
|
||||
setIonCheckGraphCoherency(false);
|
||||
setCachingEnabled(false);
|
||||
|
||||
// constants
|
||||
var buf = new ArrayBuffer(BUF_MIN);
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
// |jit-test| skip-if: !isAsmJSCompilationAvailable()
|
||||
|
||||
// Test a big fat asm.js module. First load/compile/cache bullet.js in a
|
||||
// separate process and then load it again in this process, which should be a
|
||||
// cache hit.
|
||||
|
||||
setCachingEnabled(true);
|
||||
// separate process and then load it again in this process.
|
||||
|
||||
// Note: if you get some failure in this test, it probably has to do with
|
||||
// bullet.js and not the nestedShell() call, so try first commenting out
|
||||
// nestedShell() (and the loadedFromCache assertion) to see if the error
|
||||
// reproduces.
|
||||
var code = "setIonCheckGraphCoherency(false); setCachingEnabled(true); load('" + libdir + "bullet.js'); runBullet()";
|
||||
// nestedShell() to see if the error reproduces.
|
||||
var code = "setIonCheckGraphCoherency(false); load('" + libdir + "bullet.js'); runBullet()";
|
||||
nestedShell("--js-cache", "--no-js-cache-per-process", "--execute=" + code);
|
||||
setIonCheckGraphCoherency(false);
|
||||
load(libdir + 'bullet.js');
|
||||
var results = runBullet();
|
||||
assertEq(results.asmJSValidated, true);
|
||||
assertEq(results.loadedFromCache, true);
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
// |jit-test| skip-if: !isAsmJSCompilationAvailable()
|
||||
|
||||
load(libdir + "asm.js");
|
||||
|
||||
setCachingEnabled(true);
|
||||
if (!isCachingEnabled())
|
||||
quit();
|
||||
|
||||
var body1 = "'use asm'; function f() { return 42 } function ff() { return 43 } return f";
|
||||
var m = new Function(body1);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
assertEq(m()(), 42);
|
||||
var m = new Function(body1);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m()(), 42);
|
||||
var body2 = body1 + "f";
|
||||
var m = new Function(body2);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
assertEq(m()(), 43);
|
||||
var evalStr1 = "(function() { " + body1 + "})";
|
||||
var m = eval(evalStr1);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
assertEq(m()(), 42);
|
||||
var m = eval(evalStr1);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m()(), 42);
|
||||
var evalStr2 = "(function() { " + body2 + "})";
|
||||
var m = eval(evalStr2);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
assertEq(m()(), 43);
|
||||
var m = eval(evalStr2);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m()(), 43);
|
||||
|
||||
var evalStr3 = "(function(global) { 'use asm'; var sin=global.Math.sin; function g(d) { d=+d; return +sin(d) } return g })";
|
||||
var m = eval(evalStr3);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
assertEq(m(this)(.3), Math.sin(.3));
|
||||
var m = eval(evalStr3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m(this)(.3), Math.sin(.3));
|
||||
var evalStr4 = "(function(gobal) { 'use asm'; var sin=global.Math.sin; function g(d) { d=+d; return +sin(d) } return g })";
|
||||
var m = eval(evalStr4);
|
||||
assertEq(isAsmJSModule(m), false);
|
||||
var m = eval(evalStr3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
var evalStr5 = "(function(global,foreign) { 'use asm'; var sin=global.Math.sin; function g(d) { d=+d; return +sin(d) } return g })";
|
||||
var m = eval(evalStr5);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
|
||||
var m = new Function(body1);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
var body3 = "'use asm'; var sin=global.Math.sin; function g(d) { d=+d; return +sin(d) } return g";
|
||||
var m = new Function('global', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
assertEq(m(this)(.2), Math.sin(.2));
|
||||
var m = new Function('gobal', body3);
|
||||
assertEq(isAsmJSModule(m), false);
|
||||
var m = new Function('global', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
var m = new Function('global','foreign', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
var m = new Function('global','foreign', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
var m = new Function('gobal','foreign', body3);
|
||||
assertEq(isAsmJSModule(m), false);
|
||||
var m = new Function('global','foreign', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
var m = new Function('global','foregn', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
var m = new Function('global','foreign', 'buffer', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
var m = new Function('global','foreign', 'buffer', 'foopy', body3);
|
||||
assertEq(isAsmJSModule(m), false);
|
||||
var m = new Function('global','foreign', 'buffer', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
var m = new Function('global','foreign', 'bffer', body3);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), false);
|
||||
var m = new Function('global','foreign', 'foreign', body3);
|
||||
assertEq(isAsmJSModule(m), false);
|
||||
|
||||
var body = "f() { 'use asm'; function g() {} return g }";
|
||||
var evalStr6 = "(function " + body + ")";
|
||||
var evalStr7 = "(function* " + body + ")";
|
||||
var m = eval(evalStr6);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
var m = eval(evalStr6);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
var m = eval(evalStr7);
|
||||
assertEq(isAsmJSModule(m), false);
|
||||
|
||||
// Test caching using a separate process (which, with ASLR, should mean a
|
||||
// separate address space) to compile/cache the code. Ideally, every asmCompile
|
||||
// would do this, but that makes jit-tests run 100x slower. Do it here, for one
|
||||
// of each feature. asm.js/testBullet.js should pound on everything.
|
||||
assertEq(asmLink(asmCompileCached(USE_ASM + "function f(i) { i=i|0; return +((i+1)|0) } function g(d) { d=+d; return +(d + +f(42) + 1.5) } return g"))(.2), .2+43+1.5);
|
||||
assertEq(asmLink(asmCompileCached(USE_ASM + "function f1() { return 1 } function f2() { return 2 } function f(i) { i=i|0; return T[i&1]()|0 } var T=[f1,f2]; return f"))(1), 2);
|
||||
assertEq(asmLink(asmCompileCached("g", USE_ASM + "var s=g.Math.sin; function f(d) { d=+d; return +s(d) } return f"), this)(.3), Math.sin(.3));
|
||||
assertEq(asmLink(asmCompileCached("g","ffis", USE_ASM + "var ffi=ffis.ffi; function f(i) { i=i|0; return ffi(i|0)|0 } return f"), null, {ffi:function(i){return i+2}})(1), 3);
|
||||
assertEq(asmLink(asmCompileCached("g","ffis", USE_ASM + "var x=ffis.x|0; function f() { return x|0 } return f"), null, {x:43})(), 43);
|
||||
var i32 = new Int32Array(BUF_MIN/4);
|
||||
i32[4] = 42;
|
||||
assertEq(asmLink(asmCompileCached("g","ffis","buf", USE_ASM + "var i32=new g.Int32Array(buf); function f(i) { i=i|0; return i32[i>>2]|0 } return f"), this, null, i32.buffer)(4*4), 42);
|
||||
assertEq(asmLink(asmCompileCached('glob', USE_ASM + 'var x=glob.Math.PI; function f() { return +x } return f'), this)(), Math.PI);
|
|
@ -1,7 +1,5 @@
|
|||
load(libdir + "asm.js");
|
||||
|
||||
setCachingEnabled(true);
|
||||
|
||||
var code = asmCompile(USE_ASM + "function g() { return 42 } return g");
|
||||
assertEq(asmLink(code)(), 42);
|
||||
assertEq(asmLink(code)(), 42);
|
||||
|
|
|
@ -15,8 +15,6 @@ var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i
|
|||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
assertEq(f(0), 0);
|
||||
|
||||
setCachingEnabled(true);
|
||||
|
||||
// In order to allow following tests work on both big-endian and little-
|
||||
// endian architectures we need to define least significant byte (lsb) and
|
||||
// least significant word (lsw).
|
||||
|
@ -49,8 +47,6 @@ assertEq(f(0x100),0);
|
|||
assertEq(asmLink(asmCompile('stdlib', 'foreign', 'heap', USE_ASM + 'var i32=new stdlib.Int32Array(heap); function f(i) {i=i|0;var j=0x10000;return (i32[j>>2] = i)|0 } return f'), this, null, buf)(1), 1);
|
||||
}
|
||||
|
||||
setCachingEnabled(false);
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return u8[' + lsb + ']|0}; return f');
|
||||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
assertEq(f(0),0);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
setCachingEnabled(true);
|
||||
|
||||
(function() {
|
||||
/*
|
||||
* NO ARGUMENT
|
||||
|
@ -51,9 +49,9 @@ f0 = new Function(bodyOnly);
|
|||
assertEq(f0.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f0.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})");
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var m = new Function(bodyOnly);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
assertEq(m.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})");
|
||||
}
|
||||
|
@ -110,9 +108,9 @@ f1 = new Function('glob', bodyOnly);
|
|||
assertEq(f1.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f1.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})");
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var m = new Function('glob', bodyOnly);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
assertEq(m.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})");
|
||||
}
|
||||
|
@ -170,9 +168,9 @@ f2 = new Function('glob', 'ffi', bodyOnly);
|
|||
assertEq(f2.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f2.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})");
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var m = new Function('glob', 'ffi', bodyOnly);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
assertEq(m.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})");
|
||||
}
|
||||
|
@ -230,9 +228,9 @@ f3 = new Function('glob', 'ffi', 'heap', bodyOnly);
|
|||
assertEq(f3.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(f3.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})");
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var m = new Function('glob', 'ffi', 'heap', bodyOnly);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
assertEq(m.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}");
|
||||
assertEq(m.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})");
|
||||
}
|
||||
|
@ -257,9 +255,9 @@ var expectedToSource = '(' + expectedToString + ')';
|
|||
assertEq(f4.toString(), expectedToString);
|
||||
assertEq(f4.toSource(), expectedToSource);
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var f5 = eval("\"use strict\";\n(" + funcSource + ")");
|
||||
assertEq(isAsmJSModuleLoadedFromCache(f5), true);
|
||||
assertEq(isAsmJSModule(f5), true);
|
||||
assertEq(f5.toString(), expectedToString);
|
||||
assertEq(f5.toSource(), expectedToSource);
|
||||
}
|
||||
|
@ -318,21 +316,21 @@ function checkFuncSrc(m) {
|
|||
}
|
||||
checkFuncSrc(moduleG);
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var g2 = new Function(funcBody);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(g2), true);
|
||||
assertEq(isAsmJSModule(g2), true);
|
||||
m = g2();
|
||||
checkFuncSrc(m);
|
||||
|
||||
var moduleDecl = 'function g3() {' + funcBody + '}';
|
||||
eval(moduleDecl);
|
||||
m = g3();
|
||||
assertEq(isAsmJSModuleLoadedFromCache(g3), false);
|
||||
assertEq(isAsmJSModule(g3), true);
|
||||
checkFuncSrc(m);
|
||||
|
||||
eval('var x = 42;' + moduleDecl);
|
||||
m = g3();
|
||||
assertEq(isAsmJSModuleLoadedFromCache(g3), true);
|
||||
assertEq(isAsmJSModule(g3), true);
|
||||
checkFuncSrc(m);
|
||||
}
|
||||
|
||||
|
@ -358,9 +356,9 @@ var expectedToSource = expectedToString
|
|||
assertEq(f5.toString(), expectedToString);
|
||||
assertEq(f5.toSource(), expectedToSource);
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var mf5 = eval("\"use strict\";\n(" + moduleCode + ")");
|
||||
assertEq(isAsmJSModuleLoadedFromCache(mf5), true);
|
||||
assertEq(isAsmJSModule(mf5), true);
|
||||
var f5 = mf5();
|
||||
assertEq(f5.toString(), expectedToString);
|
||||
assertEq(f5.toSource(), expectedToSource);
|
||||
|
@ -387,9 +385,9 @@ var f6 = eval(useStrict + ";\n(" + moduleCode + "({Math:{}}))");
|
|||
assertEq(f6.toString(), funcCode);
|
||||
assertEq(f6.toSource(), funcCode);
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var mf6 = eval("\"use strict\";\n(" + moduleCode + ")");
|
||||
assertEq(isAsmJSModuleLoadedFromCache(mf6), true);
|
||||
assertEq(isAsmJSModule(mf6), true);
|
||||
var f6 = mf6({Math:{}});
|
||||
assertEq(f6.toString(), funcCode);
|
||||
assertEq(f6.toSource(), funcCode);
|
||||
|
|
|
@ -20,7 +20,6 @@ function dumpStack()
|
|||
setJitCompilerOption("ion.warmup.trigger", 10);
|
||||
setJitCompilerOption("baseline.warmup.trigger", 0);
|
||||
setJitCompilerOption("offthread-compilation.enable", 0);
|
||||
setCachingEnabled(true);
|
||||
|
||||
var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
|
||||
|
||||
|
@ -31,9 +30,9 @@ for (var i = 0; i < 15; i++) {
|
|||
matchStack(stack, ['dumpStack', 'f']);
|
||||
}
|
||||
|
||||
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
|
||||
if (isAsmJSCompilationAvailable()) {
|
||||
var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
|
||||
assertEq(isAsmJSModuleLoadedFromCache(callFFI), true);
|
||||
assertEq(isAsmJSModule(callFFI), true);
|
||||
stack = null;
|
||||
f();
|
||||
matchStack(stack, ['dumpStack', 'f']);
|
||||
|
|
Двоичные данные
js/src/jit-test/tests/binast/lazy/latin1/asm.binjs
Двоичные данные
js/src/jit-test/tests/binast/lazy/latin1/asm.binjs
Двоичный файл не отображается.
|
@ -1 +0,0 @@
|
|||
// |jit-test| skip-if: !isAsmJSCompilationAvailable()
|
Двоичные данные
js/src/jit-test/tests/binast/nonlazy/latin1/asm.binjs
Двоичные данные
js/src/jit-test/tests/binast/nonlazy/latin1/asm.binjs
Двоичный файл не отображается.
|
@ -1 +0,0 @@
|
|||
// |jit-test| skip-if: !isAsmJSCompilationAvailable()
|
|
@ -1,35 +0,0 @@
|
|||
// |jit-test| skip-if: !isAsmJSCompilationAvailable()
|
||||
|
||||
load(libdir + "asm.js");
|
||||
|
||||
setCachingEnabled(true);
|
||||
if (!isCachingEnabled())
|
||||
quit();
|
||||
|
||||
// Test Latin1 and TwoByte PropertyName serialization.
|
||||
|
||||
// Latin1
|
||||
var body1 = "'use asm'; function funName() { return 42 } return funName";
|
||||
var m = new Function(body1);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
assertEq(m()(), 42);
|
||||
var m = new Function(body1);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m()(), 42);
|
||||
|
||||
var f = m();
|
||||
assertEq(isLatin1(f.name), true);
|
||||
assertEq(f.name, "funName");
|
||||
|
||||
// TwoByte
|
||||
var body1 = "'use asm'; function funName\u1200() { return 42 } return funName\u1200";
|
||||
var m = new Function(body1);
|
||||
assertEq(isAsmJSModule(m), true);
|
||||
assertEq(m()(), 42);
|
||||
var m = new Function(body1);
|
||||
assertEq(isAsmJSModuleLoadedFromCache(m), true);
|
||||
assertEq(m()(), 42);
|
||||
|
||||
var f = m();
|
||||
assertEq(isLatin1(f.name), false);
|
||||
assertEq(f.name, "funName\u1200");
|
|
@ -367,7 +367,8 @@ MSG_DEF(JSMSG_BAD_CODE_UNITS, 1, JSEXN_NOTE, "the code units comprising
|
|||
// asm.js
|
||||
MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
|
||||
MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 1, JSEXN_TYPEERR, "asm.js link error: {0}")
|
||||
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code ({0})")
|
||||
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code (total compilation time {0}ms)")
|
||||
MSG_DEF(JSMSG_USE_ASM_TYPE_OK_NO_TIME, 0, JSEXN_WARN, "Successfully compiled asm.js code ()")
|
||||
|
||||
// wasm
|
||||
MSG_DEF(JSMSG_WASM_VERBOSE, 1, JSEXN_WARN, "WebAssembly verbose: {0}")
|
||||
|
|
|
@ -523,7 +523,6 @@ static bool OOM_printAllocationCount = false;
|
|||
#endif
|
||||
|
||||
// Shell state this is only accessed on the main thread.
|
||||
bool jsCachingEnabled = false;
|
||||
mozilla::Atomic<bool> jsCacheOpened(false);
|
||||
|
||||
static bool SetTimeoutValue(JSContext* cx, double t);
|
||||
|
@ -6499,24 +6498,6 @@ static bool WithSourceHook(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool IsCachingEnabled(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
args.rval().setBoolean(jsCachingEnabled && jsCacheAsmJSPath != nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SetCachingEnabled(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (GetShellContext(cx)->isWorker) {
|
||||
JS_ReportErrorASCII(cx, "Caching is not supported in workers");
|
||||
return false;
|
||||
}
|
||||
|
||||
jsCachingEnabled = ToBoolean(args.get(0));
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PrintProfilerEvents_Callback(const char* msg) {
|
||||
fprintf(stderr, "PROFILER EVENT: %s\n", msg);
|
||||
}
|
||||
|
@ -8622,14 +8603,6 @@ JS_FN_HELP("parseBin", BinParse, 1, 0,
|
|||
" This function implements the exact requirements of the $262.IsHTMLDDA\n"
|
||||
" property in test262."),
|
||||
|
||||
JS_FN_HELP("isCachingEnabled", IsCachingEnabled, 0, 0,
|
||||
"isCachingEnabled()",
|
||||
" Return whether JS caching is enabled."),
|
||||
|
||||
JS_FN_HELP("setCachingEnabled", SetCachingEnabled, 1, 0,
|
||||
"setCachingEnabled(b)",
|
||||
" Enable or disable JS caching."),
|
||||
|
||||
JS_FN_HELP("cacheEntry", CacheEntry, 1, 0,
|
||||
"cacheEntry(code)",
|
||||
" Return a new opaque object which emulates a cache entry of a script. This\n"
|
||||
|
@ -9657,59 +9630,7 @@ static const uint32_t asmJSCacheCookie = 0xabbadaba;
|
|||
static bool ShellOpenAsmJSCacheEntryForRead(
|
||||
HandleObject global, const char16_t* begin, const char16_t* limit,
|
||||
size_t* serializedSizeOut, const uint8_t** memoryOut, intptr_t* handleOut) {
|
||||
if (!jsCachingEnabled || !jsCacheAsmJSPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedFileDesc fd(open(jsCacheAsmJSPath, O_RDWR), ScopedFileDesc::READ_LOCK);
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the size and make sure we can dereference at least one uint32_t.
|
||||
off_t off = lseek(fd, 0, SEEK_END);
|
||||
if (off == -1 || off < (off_t)sizeof(uint32_t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map the file into memory.
|
||||
void* memory;
|
||||
#ifdef XP_WIN
|
||||
HANDLE fdOsHandle = (HANDLE)_get_osfhandle(fd);
|
||||
HANDLE fileMapping =
|
||||
CreateFileMapping(fdOsHandle, nullptr, PAGE_READWRITE, 0, 0, nullptr);
|
||||
if (!fileMapping) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memory = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0);
|
||||
CloseHandle(fileMapping);
|
||||
if (!memory) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
memory = mmap(nullptr, off, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (memory == MAP_FAILED) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Perform check described by asmJSCacheCookie comment.
|
||||
if (*(uint32_t*)memory != asmJSCacheCookie) {
|
||||
#ifdef XP_WIN
|
||||
UnmapViewOfFile(memory);
|
||||
#else
|
||||
munmap(memory, off);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// The embedding added the cookie so strip it off of the buffer returned to
|
||||
// the JS engine.
|
||||
*serializedSizeOut = off - sizeof(uint32_t);
|
||||
*memoryOut = (uint8_t*)memory + sizeof(uint32_t);
|
||||
*handleOut = fd.forget();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ShellCloseAsmJSCacheEntryForRead(size_t serializedSize,
|
||||
|
@ -9734,86 +9655,7 @@ static void ShellCloseAsmJSCacheEntryForRead(size_t serializedSize,
|
|||
static JS::AsmJSCacheResult ShellOpenAsmJSCacheEntryForWrite(
|
||||
HandleObject global, const char16_t* begin, const char16_t* end,
|
||||
size_t serializedSize, uint8_t** memoryOut, intptr_t* handleOut) {
|
||||
if (!jsCachingEnabled || !jsCacheAsmJSPath) {
|
||||
return JS::AsmJSCache_Disabled_ShellFlags;
|
||||
}
|
||||
|
||||
// Create the cache directory if it doesn't already exist.
|
||||
struct stat dirStat;
|
||||
if (stat(jsCacheDir, &dirStat) == 0) {
|
||||
if (!(dirStat.st_mode & S_IFDIR)) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
} else {
|
||||
#ifdef XP_WIN
|
||||
if (mkdir(jsCacheDir) != 0) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
#else
|
||||
if (mkdir(jsCacheDir, 0777) != 0) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ScopedFileDesc fd(open(jsCacheAsmJSPath, O_CREAT | O_RDWR, 0660),
|
||||
ScopedFileDesc::WRITE_LOCK);
|
||||
if (fd == -1) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
|
||||
// Include extra space for the asmJSCacheCookie.
|
||||
serializedSize += sizeof(uint32_t);
|
||||
|
||||
// Resize the file to the appropriate size after zeroing their contents.
|
||||
#ifdef XP_WIN
|
||||
if (chsize(fd, 0)) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
if (chsize(fd, serializedSize)) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
#else
|
||||
if (ftruncate(fd, 0)) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
if (ftruncate(fd, serializedSize)) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Map the file into memory.
|
||||
void* memory;
|
||||
#ifdef XP_WIN
|
||||
HANDLE fdOsHandle = (HANDLE)_get_osfhandle(fd);
|
||||
HANDLE fileMapping =
|
||||
CreateFileMapping(fdOsHandle, nullptr, PAGE_READWRITE, 0, 0, nullptr);
|
||||
if (!fileMapping) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
|
||||
memory = MapViewOfFile(fileMapping, FILE_MAP_WRITE, 0, 0, 0);
|
||||
CloseHandle(fileMapping);
|
||||
if (!memory) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
MOZ_ASSERT(*(uint32_t*)memory == 0);
|
||||
#else
|
||||
memory = mmap(nullptr, serializedSize, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (memory == MAP_FAILED) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
MOZ_ASSERT(*(uint32_t*)memory == 0);
|
||||
if (mprotect(memory, serializedSize, PROT_READ | PROT_WRITE)) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
#endif
|
||||
|
||||
// The embedding added the cookie so strip it off of the buffer returned to
|
||||
// the JS engine. The asmJSCacheCookie will be written on close, below.
|
||||
*memoryOut = (uint8_t*)memory + sizeof(uint32_t);
|
||||
*handleOut = fd.forget();
|
||||
return JS::AsmJSCache_Success;
|
||||
return JS::AsmJSCache_Disabled_ShellFlags;
|
||||
}
|
||||
|
||||
static void ShellCloseAsmJSCacheEntryForWrite(size_t serializedSize,
|
||||
|
|
|
@ -7064,409 +7064,6 @@ size_t AsmJSMetadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const {
|
|||
bufferArgumentName.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Assumptions captures ambient state that must be the same when compiling and
|
||||
// deserializing a module for the compiled code to be valid. If it's not, then
|
||||
// the module must be recompiled from scratch.
|
||||
|
||||
struct Assumptions {
|
||||
uint32_t cpuId;
|
||||
JS::BuildIdCharVector buildId;
|
||||
|
||||
Assumptions();
|
||||
bool init();
|
||||
|
||||
bool operator==(const Assumptions& rhs) const;
|
||||
bool operator!=(const Assumptions& rhs) const { return !(*this == rhs); }
|
||||
|
||||
size_t serializedSize() const;
|
||||
uint8_t* serialize(uint8_t* cursor) const;
|
||||
const uint8_t* deserialize(const uint8_t* cursor, size_t remain);
|
||||
};
|
||||
|
||||
Assumptions::Assumptions() : cpuId(ObservedCPUFeatures()), buildId() {}
|
||||
|
||||
bool Assumptions::init() { return GetBuildId && GetBuildId(&buildId); }
|
||||
|
||||
bool Assumptions::operator==(const Assumptions& rhs) const {
|
||||
return cpuId == rhs.cpuId && buildId.length() == rhs.buildId.length() &&
|
||||
ArrayEqual(buildId.begin(), rhs.buildId.begin(), buildId.length());
|
||||
}
|
||||
|
||||
size_t Assumptions::serializedSize() const {
|
||||
return sizeof(uint32_t) + SerializedPodVectorSize(buildId);
|
||||
}
|
||||
|
||||
uint8_t* Assumptions::serialize(uint8_t* cursor) const {
|
||||
// The format of serialized Assumptions must never change in a way that
|
||||
// would cause old cache files written with by an old build-id to match the
|
||||
// assumptions of a different build-id.
|
||||
|
||||
cursor = WriteScalar<uint32_t>(cursor, cpuId);
|
||||
cursor = SerializePodVector(cursor, buildId);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
const uint8_t* Assumptions::deserialize(const uint8_t* cursor, size_t remain) {
|
||||
(cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &cpuId)) &&
|
||||
(cursor = DeserializePodVectorChecked(cursor, &remain, &buildId));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
class ModuleChars {
|
||||
protected:
|
||||
uint32_t isFunCtor_;
|
||||
Vector<CacheableChars, 0, SystemAllocPolicy> funCtorArgs_;
|
||||
|
||||
public:
|
||||
static uint32_t beginOffset(AsmJSParser<char16_t>& parser) {
|
||||
return parser.pc->functionBox()->functionNode->pn_pos.begin;
|
||||
}
|
||||
|
||||
static uint32_t endOffset(AsmJSParser<char16_t>& parser) {
|
||||
TokenPos pos(0, 0); // initialize to silence GCC warning
|
||||
MOZ_ALWAYS_TRUE(
|
||||
parser.tokenStream.peekTokenPos(&pos, TokenStreamShared::Operand));
|
||||
return pos.end;
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleCharsForStore : ModuleChars {
|
||||
uint32_t uncompressedSize_;
|
||||
uint32_t compressedSize_;
|
||||
Vector<char, 0, SystemAllocPolicy> compressedBuffer_;
|
||||
|
||||
public:
|
||||
bool init(AsmJSParser<char16_t>& parser) {
|
||||
MOZ_ASSERT(beginOffset(parser) < endOffset(parser));
|
||||
|
||||
uncompressedSize_ =
|
||||
(endOffset(parser) - beginOffset(parser)) * sizeof(char16_t);
|
||||
size_t maxCompressedSize = LZ4::maxCompressedSize(uncompressedSize_);
|
||||
if (maxCompressedSize < uncompressedSize_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compressedBuffer_.resize(maxCompressedSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char16_t* chars =
|
||||
parser.tokenStream.codeUnitPtrAt(beginOffset(parser));
|
||||
const char* source = reinterpret_cast<const char*>(chars);
|
||||
size_t compressedSize =
|
||||
LZ4::compress(source, uncompressedSize_, compressedBuffer_.begin());
|
||||
if (!compressedSize || compressedSize > UINT32_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
compressedSize_ = compressedSize;
|
||||
|
||||
// For a function statement or named function expression:
|
||||
// function f(x,y,z) { abc }
|
||||
// the range [beginOffset, endOffset) captures the source:
|
||||
// f(x,y,z) { abc }
|
||||
// An unnamed function expression captures the same thing, sans 'f'.
|
||||
// Since asm.js modules do not contain any free variables, equality of
|
||||
// [beginOffset, endOffset) is sufficient to guarantee identical code
|
||||
// generation, modulo Assumptions.
|
||||
//
|
||||
// For functions created with 'new Function', function arguments are
|
||||
// not present in the source so we must manually explicitly serialize
|
||||
// and match the formals as a Vector of PropertyName.
|
||||
isFunCtor_ = parser.pc->isStandaloneFunctionBody();
|
||||
if (isFunCtor_) {
|
||||
unsigned numArgs;
|
||||
CodeNode* functionNode = parser.pc->functionBox()->functionNode;
|
||||
ParseNode* arg = FunctionFormalParametersList(functionNode, &numArgs);
|
||||
for (unsigned i = 0; i < numArgs; i++, arg = arg->pn_next) {
|
||||
UniqueChars name =
|
||||
StringToNewUTF8CharsZ(nullptr, *arg->as<NameNode>().name());
|
||||
if (!name || !funCtorArgs_.append(std::move(name))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t serializedSize() const {
|
||||
return sizeof(uint32_t) + sizeof(uint32_t) + compressedSize_ +
|
||||
sizeof(uint32_t) +
|
||||
(isFunCtor_ ? SerializedVectorSize(funCtorArgs_) : 0);
|
||||
}
|
||||
|
||||
uint8_t* serialize(uint8_t* cursor) const {
|
||||
cursor = WriteScalar<uint32_t>(cursor, uncompressedSize_);
|
||||
cursor = WriteScalar<uint32_t>(cursor, compressedSize_);
|
||||
cursor = WriteBytes(cursor, compressedBuffer_.begin(), compressedSize_);
|
||||
cursor = WriteScalar<uint32_t>(cursor, isFunCtor_);
|
||||
if (isFunCtor_) {
|
||||
cursor = SerializeVector(cursor, funCtorArgs_);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleCharsForLookup : ModuleChars {
|
||||
Vector<char16_t, 0, SystemAllocPolicy> chars_;
|
||||
|
||||
public:
|
||||
const uint8_t* deserialize(const uint8_t* cursor) {
|
||||
uint32_t uncompressedSize;
|
||||
cursor = ReadScalar<uint32_t>(cursor, &uncompressedSize);
|
||||
|
||||
uint32_t compressedSize;
|
||||
cursor = ReadScalar<uint32_t>(cursor, &compressedSize);
|
||||
|
||||
if (!chars_.resize(uncompressedSize / sizeof(char16_t))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* source = reinterpret_cast<const char*>(cursor);
|
||||
char* dest = reinterpret_cast<char*>(chars_.begin());
|
||||
if (!LZ4::decompress(source, dest, uncompressedSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cursor += compressedSize;
|
||||
|
||||
cursor = ReadScalar<uint32_t>(cursor, &isFunCtor_);
|
||||
if (isFunCtor_) {
|
||||
cursor = DeserializeVector(cursor, &funCtorArgs_);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
bool match(AsmJSParser<char16_t>& parser) const {
|
||||
const char16_t* parseBegin =
|
||||
parser.tokenStream.codeUnitPtrAt(beginOffset(parser));
|
||||
const char16_t* parseLimit = parser.tokenStream.rawLimit();
|
||||
MOZ_ASSERT(parseLimit >= parseBegin);
|
||||
if (uint32_t(parseLimit - parseBegin) < chars_.length()) {
|
||||
return false;
|
||||
}
|
||||
if (!ArrayEqual(chars_.begin(), parseBegin, chars_.length())) {
|
||||
return false;
|
||||
}
|
||||
if (isFunCtor_ != parser.pc->isStandaloneFunctionBody()) {
|
||||
return false;
|
||||
}
|
||||
if (isFunCtor_) {
|
||||
// For function statements, the closing } is included as the last
|
||||
// character of the matched source. For Function constructor,
|
||||
// parsing terminates with EOF which we must explicitly check. This
|
||||
// prevents
|
||||
// new Function('"use asm"; function f() {} return f')
|
||||
// from incorrectly matching
|
||||
// new Function('"use asm"; function f() {} return ff')
|
||||
if (parseBegin + chars_.length() != parseLimit) {
|
||||
return false;
|
||||
}
|
||||
unsigned numArgs;
|
||||
CodeNode* functionNode = parser.pc->functionBox()->functionNode;
|
||||
ParseNode* arg = FunctionFormalParametersList(functionNode, &numArgs);
|
||||
if (funCtorArgs_.length() != numArgs) {
|
||||
return false;
|
||||
}
|
||||
for (unsigned i = 0; i < funCtorArgs_.length(); i++, arg = arg->pn_next) {
|
||||
UniqueChars name =
|
||||
StringToNewUTF8CharsZ(nullptr, *arg->as<NameNode>().name());
|
||||
if (!name || strcmp(funCtorArgs_[i].get(), name.get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct ScopedCacheEntryOpenedForWrite {
|
||||
JSContext* cx;
|
||||
const size_t serializedSize;
|
||||
uint8_t* memory;
|
||||
intptr_t handle;
|
||||
|
||||
ScopedCacheEntryOpenedForWrite(JSContext* cx, size_t serializedSize)
|
||||
: cx(cx), serializedSize(serializedSize), memory(nullptr), handle(-1) {}
|
||||
|
||||
~ScopedCacheEntryOpenedForWrite() {
|
||||
if (memory) {
|
||||
cx->asmJSCacheOps().closeEntryForWrite(serializedSize, memory, handle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ScopedCacheEntryOpenedForRead {
|
||||
JSContext* cx;
|
||||
size_t serializedSize;
|
||||
const uint8_t* memory;
|
||||
intptr_t handle;
|
||||
|
||||
explicit ScopedCacheEntryOpenedForRead(JSContext* cx)
|
||||
: cx(cx), serializedSize(0), memory(nullptr), handle(0) {}
|
||||
|
||||
~ScopedCacheEntryOpenedForRead() {
|
||||
if (memory) {
|
||||
cx->asmJSCacheOps().closeEntryForRead(serializedSize, memory, handle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
static JS::AsmJSCacheResult StoreAsmJSModuleInCache(
|
||||
AsmJSParser<char16_t>& parser, const Module& module,
|
||||
const LinkData& linkData, JSContext* cx) {
|
||||
ModuleCharsForStore moduleChars;
|
||||
if (!moduleChars.init(parser)) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
|
||||
size_t moduleSize = module.serializedSize(linkData);
|
||||
MOZ_RELEASE_ASSERT(moduleSize <= UINT32_MAX);
|
||||
|
||||
Assumptions assumptions;
|
||||
if (!assumptions.init()) {
|
||||
return JS::AsmJSCache_InternalError;
|
||||
}
|
||||
|
||||
size_t serializedSize = assumptions.serializedSize() + sizeof(uint32_t) +
|
||||
moduleSize + moduleChars.serializedSize();
|
||||
|
||||
JS::OpenAsmJSCacheEntryForWriteOp open =
|
||||
cx->asmJSCacheOps().openEntryForWrite;
|
||||
if (!open) {
|
||||
return JS::AsmJSCache_Disabled_Internal;
|
||||
}
|
||||
|
||||
const char16_t* begin =
|
||||
parser.tokenStream.codeUnitPtrAt(ModuleChars::beginOffset(parser));
|
||||
const char16_t* end =
|
||||
parser.tokenStream.codeUnitPtrAt(ModuleChars::endOffset(parser));
|
||||
|
||||
ScopedCacheEntryOpenedForWrite entry(cx, serializedSize);
|
||||
JS::AsmJSCacheResult openResult = open(
|
||||
cx->global(), begin, end, serializedSize, &entry.memory, &entry.handle);
|
||||
if (openResult != JS::AsmJSCache_Success) {
|
||||
return openResult;
|
||||
}
|
||||
|
||||
uint8_t* cursor = entry.memory;
|
||||
|
||||
cursor = assumptions.serialize(cursor);
|
||||
|
||||
cursor = WriteScalar<uint32_t>(cursor, moduleSize);
|
||||
|
||||
module.serialize(linkData, cursor, moduleSize);
|
||||
cursor += moduleSize;
|
||||
|
||||
cursor = moduleChars.serialize(cursor);
|
||||
|
||||
MOZ_RELEASE_ASSERT(cursor == entry.memory + serializedSize);
|
||||
|
||||
return JS::AsmJSCache_Success;
|
||||
}
|
||||
|
||||
static bool LookupAsmJSModuleInCache(JSContext* cx,
|
||||
AsmJSParser<char16_t>& parser,
|
||||
bool* loadedFromCache,
|
||||
SharedModule* module,
|
||||
UniqueChars* compilationTimeReport) {
|
||||
int64_t before = PRMJ_Now();
|
||||
|
||||
*loadedFromCache = false;
|
||||
|
||||
JS::OpenAsmJSCacheEntryForReadOp open = cx->asmJSCacheOps().openEntryForRead;
|
||||
if (!open) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char16_t* begin =
|
||||
parser.tokenStream.codeUnitPtrAt(ModuleChars::beginOffset(parser));
|
||||
const char16_t* limit = parser.tokenStream.rawLimit();
|
||||
|
||||
ScopedCacheEntryOpenedForRead entry(cx);
|
||||
if (!open(cx->global(), begin, limit, &entry.serializedSize, &entry.memory,
|
||||
&entry.handle)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint8_t* cursor = entry.memory;
|
||||
|
||||
Assumptions deserializedAssumptions;
|
||||
cursor = deserializedAssumptions.deserialize(cursor, entry.serializedSize);
|
||||
if (!cursor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Assumptions currentAssumptions;
|
||||
if (!currentAssumptions.init() ||
|
||||
currentAssumptions != deserializedAssumptions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t moduleSize;
|
||||
cursor = ReadScalar<uint32_t>(cursor, &moduleSize);
|
||||
if (!cursor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MutableAsmJSMetadata asmJSMetadata = cx->new_<AsmJSMetadata>();
|
||||
if (!asmJSMetadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*module = Module::deserialize(cursor, moduleSize, asmJSMetadata.get());
|
||||
if (!*module) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
cursor += moduleSize;
|
||||
|
||||
// Due to the hash comparison made by openEntryForRead, this should succeed
|
||||
// with high probability.
|
||||
ModuleCharsForLookup moduleChars;
|
||||
cursor = moduleChars.deserialize(cursor);
|
||||
if (!moduleChars.match(parser)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't punish release users by crashing if there is a programmer error
|
||||
// here, just gracefully return with a cache miss.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
MOZ_RELEASE_ASSERT(cursor == entry.memory + entry.serializedSize);
|
||||
#endif
|
||||
if (cursor != entry.memory + entry.serializedSize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// See AsmJSMetadata comment as well as ModuleValidator::init().
|
||||
asmJSMetadata->toStringStart = parser.pc->functionBox()->toStringStart;
|
||||
asmJSMetadata->srcStart =
|
||||
parser.pc->functionBox()->functionNode->body()->pn_pos.begin;
|
||||
asmJSMetadata->strict =
|
||||
parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict();
|
||||
asmJSMetadata->scriptSource.reset(parser.ss);
|
||||
|
||||
if (!parser.tokenStream.advance(asmJSMetadata->srcEndBeforeCurly())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t after = PRMJ_Now();
|
||||
int ms = (after - before) / PRMJ_USEC_PER_MSEC;
|
||||
*compilationTimeReport = JS_smprintf("loaded from cache in %dms", ms);
|
||||
if (!*compilationTimeReport) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*loadedFromCache = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
// Top-level js::CompileAsmJS
|
||||
|
||||
|
@ -7475,8 +7072,19 @@ static bool NoExceptionPending(JSContext* cx) {
|
|||
}
|
||||
|
||||
static bool SuccessfulValidation(frontend::ParserBase& parser,
|
||||
UniqueChars str) {
|
||||
return parser.warningNoOffset(JSMSG_USE_ASM_TYPE_OK, str.get());
|
||||
unsigned compilationTime) {
|
||||
constexpr unsigned errNum =
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
JSMSG_USE_ASM_TYPE_OK_NO_TIME
|
||||
#else
|
||||
JSMSG_USE_ASM_TYPE_OK
|
||||
#endif
|
||||
;
|
||||
|
||||
char timeChars[20];
|
||||
SprintfLiteral(timeChars, "%u", compilationTime);
|
||||
|
||||
return parser.warningNoOffset(errNum, timeChars);
|
||||
}
|
||||
|
||||
static bool TypeFailureWarning(frontend::ParserBase& parser, const char* str) {
|
||||
|
@ -7529,57 +7137,6 @@ static bool EstablishPreconditions(JSContext* cx,
|
|||
return true;
|
||||
}
|
||||
|
||||
static UniqueChars BuildConsoleMessage(unsigned time,
|
||||
JS::AsmJSCacheResult cacheResult) {
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
const char* cacheString = "";
|
||||
switch (cacheResult) {
|
||||
case JS::AsmJSCache_Success:
|
||||
cacheString = "stored in cache";
|
||||
break;
|
||||
case JS::AsmJSCache_ModuleTooSmall:
|
||||
cacheString = "not stored in cache (too small to benefit)";
|
||||
break;
|
||||
case JS::AsmJSCache_SynchronousScript:
|
||||
cacheString =
|
||||
"unable to cache asm.js in synchronous scripts; try loading "
|
||||
"asm.js via <script async> or createElement('script')";
|
||||
break;
|
||||
case JS::AsmJSCache_QuotaExceeded:
|
||||
cacheString = "not enough temporary storage quota to store in cache";
|
||||
break;
|
||||
case JS::AsmJSCache_StorageInitFailure:
|
||||
cacheString = "storage initialization failed (consider filing a bug)";
|
||||
break;
|
||||
case JS::AsmJSCache_Disabled_Internal:
|
||||
cacheString =
|
||||
"caching disabled by internal configuration (consider filing a bug)";
|
||||
break;
|
||||
case JS::AsmJSCache_Disabled_ShellFlags:
|
||||
cacheString = "caching disabled by missing command-line arguments";
|
||||
break;
|
||||
case JS::AsmJSCache_Disabled_JitInspector:
|
||||
cacheString = "caching disabled by active JIT inspector";
|
||||
break;
|
||||
case JS::AsmJSCache_InternalError:
|
||||
cacheString =
|
||||
"unable to store in cache due to internal error (consider filing a "
|
||||
"bug)";
|
||||
break;
|
||||
case JS::AsmJSCache_Disabled_PrivateBrowsing:
|
||||
cacheString = "caching disabled by private browsing mode";
|
||||
break;
|
||||
case JS::AsmJSCache_LIMIT:
|
||||
MOZ_CRASH("bad AsmJSCacheResult");
|
||||
break;
|
||||
}
|
||||
|
||||
return JS_smprintf("total compilation time %dms; %s", time, cacheString);
|
||||
#else
|
||||
return DuplicateString("");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool js::CompileAsmJS(JSContext* cx, AsmJSParser<char16_t>& parser,
|
||||
ParseNode* stmtList, bool* validated) {
|
||||
*validated = false;
|
||||
|
@ -7589,40 +7146,18 @@ bool js::CompileAsmJS(JSContext* cx, AsmJSParser<char16_t>& parser,
|
|||
return NoExceptionPending(cx);
|
||||
}
|
||||
|
||||
// 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.
|
||||
bool loadedFromCache;
|
||||
// Validate and generate code in a single linear pass over the chars of the
|
||||
// asm.js module.
|
||||
SharedModule module;
|
||||
UniqueChars message;
|
||||
if (!LookupAsmJSModuleInCache(cx, parser, &loadedFromCache, &module,
|
||||
&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) {
|
||||
unsigned time;
|
||||
{
|
||||
// "Checking" parses, validates and compiles, producing a fully compiled
|
||||
// WasmModuleObject as result.
|
||||
UniqueLinkData linkData;
|
||||
unsigned time;
|
||||
module = CheckModule(cx, parser, stmtList, &linkData, &time);
|
||||
if (!module) {
|
||||
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.
|
||||
JS::AsmJSCacheResult cacheResult =
|
||||
StoreAsmJSModuleInCache(parser, *module, *linkData, cx);
|
||||
|
||||
// Build the string message to display in the developer console.
|
||||
message = BuildConsoleMessage(time, cacheResult);
|
||||
if (!message) {
|
||||
return NoExceptionPending(cx);
|
||||
}
|
||||
}
|
||||
|
||||
// Hand over ownership to a GC object wrapper which can then be referenced
|
||||
|
@ -7649,9 +7184,10 @@ bool js::CompileAsmJS(JSContext* cx, AsmJSParser<char16_t>& parser,
|
|||
MOZ_ASSERT(funbox->function()->isInterpreted());
|
||||
funbox->clobberFunction(moduleFun);
|
||||
|
||||
// Success! Write to the console with a "warning" message.
|
||||
// Success! Write to the console with a "warning" message indicating
|
||||
// total compilation time.
|
||||
*validated = true;
|
||||
SuccessfulValidation(parser, std::move(message));
|
||||
SuccessfulValidation(parser, time);
|
||||
return NoExceptionPending(cx);
|
||||
}
|
||||
|
||||
|
@ -7737,26 +7273,6 @@ bool js::IsAsmJSFunction(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool js::IsAsmJSModuleLoadedFromCache(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSFunction* fun = MaybeWrappedNativeFunction(args.get(0));
|
||||
if (!fun || !IsAsmJSModule(fun)) {
|
||||
JS_ReportErrorNumberUTF8(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_USE_ASM_TYPE_FAIL,
|
||||
"argument passed to isAsmJSModuleLoadedFromCache is not a "
|
||||
"validated asm.js module");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool loadedFromCache =
|
||||
AsmJSModuleFunctionToModule(fun).metadata().asAsmJS().cacheResult ==
|
||||
CacheResult::Hit;
|
||||
|
||||
args.rval().set(BooleanValue(loadedFromCache));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
// asm.js toString/toSource support
|
||||
|
||||
|
|
|
@ -84,9 +84,6 @@ extern bool IsAsmJSCompilationAvailable(JSContext* cx, unsigned argc,
|
|||
|
||||
extern bool IsAsmJSModule(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
extern bool IsAsmJSModuleLoadedFromCache(JSContext* cx, unsigned argc,
|
||||
JS::Value* vp);
|
||||
|
||||
extern bool IsAsmJSFunction(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
// asm.js toString/toSource support:
|
||||
|
|
Загрузка…
Ссылка в новой задаче