load(libdir + 'bytecode-cache.js'); var test = ""; var checkAfter; // code a function which has both used and unused inner functions. test = (function () { function f(x) { function ifTrue() { return true; }; function ifFalse() { return false; }; if (x) return ifTrue(); else return ifFalse(); } return f.toSource() + "; f(true)"; })(); evalWithCache(test, { assertEqBytecode: true, assertEqResult : true }); // code a function which uses different inner functions based on the generation. test = (function () { function f(x) { function ifTrue() { return true; }; function ifFalse() { return false; }; if (x) return ifTrue(); else return ifFalse(); } return f.toSource() + "; f((generation % 2) == 0)"; })(); evalWithCache(test, { }); // Code a function which has an enclosing scope. test = (function () { function f() { var upvar = ""; function g() { upvar += ""; return upvar; } return g; } return f.toSource() + "; f()();"; })(); evalWithCache(test, { assertEqBytecode: true, assertEqResult : true }); // Code a lazy function which has an enclosing scope. test = (function () { function f() { var upvar = ""; function g() { upvar += ""; return upvar; } return g; } return f.toSource() + "; f();"; })(); evalWithCache(test, { assertEqBytecode: true }); // (basic/bug535930) Code an enclosing scope which is a Call object. test = (function () { return "(" + (function () { p = function () { Set() }; var Set = function () {}; for (var x = 0; x < 5; x++) { Set = function (z) { return function () { [z] } } (x) } }).toSource() + ")()"; })(); evalWithCache(test, { assertEqBytecode: true }); // Code an arrow function, and execute it. test = (function () { function f() { var g = (a) => a + a; return g; } return f.toSource() + "; f()(1);"; })(); evalWithCache(test, { assertEqBytecode: true, assertEqResult : true }); // Code an arrow function, and do not execute it. test = (function () { function f() { var g = (a) => a + a; return g; } return f.toSource() + "; f();"; })(); evalWithCache(test, { assertEqBytecode: true }); // Extra zeal GCs can cause isRelazifiableFunction() to become true after we // record its value by throwing away JIT code for the function. gczeal(0); // Ensure that decoded functions can be relazified. test = "function f() { }; f();" + "assertEq(isLazyFunction(f), false);" + "var expect = isRelazifiableFunction(f);"; checkAfter = function (ctx) { gc(ctx.global.f, "shrinking"); // relazify f, if possible. evaluate("assertEq(isLazyFunction(f), expect);", ctx); }; evalWithCache(test, { assertEqBytecode: true, // Check that we re-encode the same thing. assertEqResult: true, // The function should remain relazifiable, if it was // during the first run. checkAfter: checkAfter // Check that relazifying the restored function works // if the original was relazifiable. }); // Ensure that decoded functions can be relazified, even if they have free // variables. test = "function f() { return isRelazifiableFunction(f) }; var expect = f();" + "assertEq(isLazyFunction(f), false);" + "expect"; checkAfter = function (ctx) { gc(ctx.global.f, "shrinking"); // relazify f, if possible. evaluate("assertEq(isLazyFunction(f), expect);", ctx); }; evalWithCache(test, { assertEqBytecode: true, // Check that we re-encode the same thing. assertEqResult: true, // The function should remain relazifiable, if it was // during the first run. checkAfter: checkAfter // Check that relazifying the restored function works // if the original was relazifiable. }); // Ensure that if a function is encoded when non-lazy but relazifiable, then // decoded, relazified, and then delazified, the result actually works. test = ` function f() { return true; }; var canBeLazy = isRelazifiableFunction(f) || isLazyFunction(f); relazifyFunctions(); assertEq(isLazyFunction(f), canBeLazy); f()` evalWithCache(test, { assertEqBytecode: true, assertEqResult: true }); // And more of the same, in a slightly different way var g1 = newGlobal({ cloneSingletons: true }); var g2 = newGlobal(); var res = "function f(){}"; var code = cacheEntry(res + "; f();"); evaluate(code, {global:g1, compileAndGo: true, saveBytecode: {value: true}}); evaluate(code, {global:g2, loadBytecode: true}); gc(); assertEq(g2.f.toString(), res); // Another relazification case. var src = "function f() { return 3; }; f(); relazifyFunctions(); 4"; evalWithCache(src, {assertEqBytecode: true, assertEqResult: true});