Bug 998908 - Mark inner objects inside eval'd scripts before firing Debugger's onNewScript hook. (r=till)

This commit is contained in:
Shu-yu Guo 2014-04-29 21:57:36 -07:00
parent df87b3b9de
commit d99af5333f
3 changed files with 46 additions and 28 deletions

View File

@ -191,30 +191,6 @@ TryEvalJSON(JSContext *cx, JSScript *callerScript,
return EvalJSON_NotJSON;
}
static void
MarkFunctionsWithinEvalScript(JSScript *script)
{
// Mark top level functions in an eval script as being within an eval and,
// if applicable, inside a with statement.
if (!script->hasObjects())
return;
ObjectArray *objects = script->objects();
size_t start = script->innerObjectsStart();
for (size_t i = start; i < objects->length; i++) {
JSObject *obj = objects->vector[i];
if (obj->is<JSFunction>()) {
JSFunction *fun = &obj->as<JSFunction>();
if (fun->hasScript())
fun->nonLazyScript()->setDirectlyInsideEval();
else if (fun->isInterpretedLazy())
fun->lazyScript()->setDirectlyInsideEval();
}
}
}
// Define subset of ExecuteType so that casting performs the injection.
enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIRECT_EVAL };
@ -327,8 +303,6 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
if (!compiled)
return false;
MarkFunctionsWithinEvalScript(compiled);
esg.setNewScript(compiled);
}
@ -396,8 +370,6 @@ js::DirectEvalStringFromIon(JSContext *cx,
if (!compiled)
return false;
MarkFunctionsWithinEvalScript(compiled);
esg.setNewScript(compiled);
}

View File

@ -152,6 +152,30 @@ CanLazilyParse(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
cx->compartment()->runtimeFromAnyThread()->debugHooks.newScriptHook);
}
static void
MarkFunctionsWithinEvalScript(JSScript *script)
{
// Mark top level functions in an eval script as being within an eval and,
// if applicable, inside a with statement.
if (!script->hasObjects())
return;
ObjectArray *objects = script->objects();
size_t start = script->innerObjectsStart();
for (size_t i = start; i < objects->length; i++) {
JSObject *obj = objects->vector[i];
if (obj->is<JSFunction>()) {
JSFunction *fun = &obj->as<JSFunction>();
if (fun->hasScript())
fun->nonLazyScript()->setDirectlyInsideEval();
else if (fun->isInterpretedLazy())
fun->lazyScript()->setDirectlyInsideEval();
}
}
}
void
frontend::MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &options,
SourceBufferHolder &srcBuf)
@ -420,6 +444,12 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
if (!JSScript::fullyInitFromEmitter(cx, script, &bce))
return nullptr;
// Note that this marking must happen before we tell Debugger
// about the new script, in case Debugger delazifies the script's
// inner functions.
if (options.forEval)
MarkFunctionsWithinEvalScript(script);
bce.tellDebuggerAboutCompiledScript(cx);
if (sct && !extraSct && !sct->complete())

View File

@ -0,0 +1,16 @@
// Test that lazy inner functions inside eval are tagged properly so we don't
// incorrectly do NAME -> GNAME optimization.
var g = newGlobal();
var dbg = new Debugger(g);
dbg.onNewScript = function delazify(script, global) {
// Force delazification of inner functions.
script.getChildScripts();
};
g.eval("" + function f() {
var $;
eval('var obj={foo:1}; $=function() { assertEq(obj.foo, 1); }');
return $;
});
g.eval("f()();");