Bug 646597 - Make functions made by the Function constructor compile-and-go. Most of patch was originally written by jorendorff. (r=luke)

This commit is contained in:
Shu-yu Guo 2013-05-04 20:53:21 -07:00
parent b0f0481c81
commit 2a348786f9
11 changed files with 42 additions and 21 deletions

View File

@ -330,7 +330,6 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
return false;
}
options.setCompileAndGo(false);
Parser<FullParseHandler> parser(cx, options, chars, length, /* foldConstants = */ true);
if (!parser.init())
return false;
@ -413,9 +412,17 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
#endif
if (generateBytecode) {
/*
* The reason for checking fun->environment() below is that certain
* consumers of JS::CompileFunction, namely
* nsEventListenerManager::CompileEventHandlerInternal, passes in a
* NULL environment. This compiled function is never used, but instead
* is cloned immediately onto the right scope chain.
*/
BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script,
/* evalCaller = */ NullPtr(),
/* hasGlobalScope = */ false, options.lineno);
fun->environment() && fun->environment()->isGlobal(),
options.lineno);
if (!funbce.init())
return false;

View File

@ -20,7 +20,7 @@ dbg.onNewScript = function (s) {
};
assertEq(g.eval("eval('2 + 3')"), 5);
this.gczeal(hits, 2);
var fn = g.Function("a", "return 5 + a;");
var fn = g.evaluate("(function (a) { return 5 + a; })", {compileAndGo: false});
var g2 = newGlobal('new-compartment');
dbg.addDebuggee(g2, dbg);
g2.clone(fn);

View File

@ -1,3 +1,8 @@
// |jit-test| no-ion
//
// We can't guarantee error identity when functions are Ion-compiled due to
// optimization.
function check_one(expected, f, err) {
var failed = true;
try {

View File

@ -19,9 +19,9 @@ function test(str, arg, result)
Reflect.parse(got);
// test xdr by cloning a cross-compartment function
otherGlobal.str = str;
var c = clone(otherGlobal.eval("new Function('x', str)"));
assertEq(c.toSource(), fun.toSource());
var code = "(function (x) { " + str + " })";
var c = clone(otherGlobal.evaluate(code, {compileAndGo: false}));
assertEq(c.toSource(), eval(code).toSource());
var got = fun(arg);
var expect = result;

View File

@ -1,24 +1,28 @@
var g = newGlobal('new-compartment');
g.f = new Function('return function(x) { return x }');
function cloneableFunction(body) {
return evaluate("(function () { " + body + " })", {compileAndGo: false});
}
g.f = cloneableFunction('return function(x) { return x };');
assertEq(g.eval("clone(f)()(9)"), 9);
g.f = new Function('return function(x) { let(y = x+1) { return y } }');
g.f = cloneableFunction('return function(x) { let(y = x+1) { return y } };');
assertEq(g.eval("clone(f)()(9)"), 10);
g.f = new Function('return function(x) { let(y = x, z = 1) { return y+z } }');
g.f = cloneableFunction('return function(x) { let(y = x, z = 1) { return y+z } };');
assertEq(g.eval("clone(f)()(9)"), 10);
g.f = new Function('return function(x) { return x.search(/ponies/) }');
g.f = cloneableFunction('return function(x) { return x.search(/ponies/) };');
assertEq(g.eval("clone(f)()('123ponies')"), 3);
g.f = new Function('return function(x,y) { return x.search(/a/) + y.search(/b/) }');
g.f = cloneableFunction('return function(x,y) { return x.search(/a/) + y.search(/b/) };');
assertEq(g.eval("clone(f)()('12a','foo')"), 1);
g.f = new Function('return [function(x) x+2, function(y) let(z=y+1) z]');
g.f = cloneableFunction('return [function(x) x+2, function(y) let(z=y+1) z];');
assertEq(g.eval("let ([f,g] = clone(f)()) f(g(4))"), 7);
g.f = new Function('return function(x) { switch(x) { case "a": return "b"; case null: return "c" } }');
g.f = cloneableFunction('return function(x) { switch(x) { case "a": return "b"; case null: return "c" } };');
assertEq(g.eval("clone(f)()('a')"), "b");
assertEq(g.eval("clone(f)()(null)"), "c");
assertEq(g.eval("clone(f)()(3)"), undefined);

View File

@ -37,6 +37,7 @@ assertEq(fn(8), 13);
assertEq(hits, 1);
// cloning functions across compartments
fn = g.evaluate("(function(a) { return 5 + a; })", {compileAndGo: false});
var g2 = newGlobal('new-compartment');
dbg.addDebuggee(g2, dbg);
hits = 0;

View File

@ -44,7 +44,7 @@ test(function () { g.eval("var obj = {get x() { return 1; }, set x(v) { print(v)
test(function () { return g.Function("a", "b", "return b - a;"); });
// cloning a function with nested functions
test(function () { g.clone(Function("x", "return x + 1")); });
test(function () { g.clone(evaluate("(function(x) { return x + 1; })", {compileAndGo: false})); });
// eval declaring a generator
test(function () { g.eval("function r(n) { for (var i=0;i<n;i++) yield i; }"); });

View File

@ -1296,7 +1296,8 @@ js::Function(JSContext *cx, unsigned argc, Value *vp)
CompileOptions options(cx);
options.setPrincipals(principals)
.setOriginPrincipals(originPrincipals)
.setFileAndLine(filename, lineno);
.setFileAndLine(filename, lineno)
.setCompileAndGo(true);
unsigned n = args.length() ? args.length() - 1 : 0;
if (n > 0) {

View File

@ -28,14 +28,15 @@ var actualvalues = [];
var expect= '';
var expectedvalues = [];
var f = Function("x","y","\
function h() { return h_peer(); } \
function h_peer() { return (x + cnCOMMA + y); } \
return h");
if (typeof clone == 'function')
{
status = inSection(1);
var f = evaluate("(function(x, y) {\n" +
" function h() { return h_peer(); }\n" +
" function h_peer() { return (x + cnCOMMA + y); }\n" +
" return h;\n" +
"})",
{compileAndGo: false});
var g = clone(f);
g.prototype = new Object;
var h = g(5,6);

View File

@ -27,7 +27,7 @@ function test()
else {
expect = 'PASSED';
f = Function("return a * a;");
f = evaluate("(function () { return a * a; })", {compileAndGo: false});
g = clone(f, {a: 3});
f = null;
gc();

View File

@ -140,6 +140,8 @@ class Test:
test.jitflags.append('--no-jm')
elif name == 'ion-eager':
test.jitflags.append('--ion-eager')
elif name == 'no-ion':
test.jitflags.append('--no-ion')
elif name == 'dump-bytecode':
test.jitflags.append('--dump-bytecode')
else: