Bug 1193583 - Change the semantics of Debugger.evalInGlobal to be like executing a series of statements at the global level instead of like an indirect eval. (r=jimb)

This is to allow the web console to introduce and persist lexical
bindings on the global level. If evalInGlobal were like an indirect
eval, then no lexical bindings can escape the lexical environment of the
eval.
This commit is contained in:
Shu-yu Guo 2015-08-30 15:08:19 -07:00
Родитель 256fcebeb7
Коммит 1194a532eb
5 изменённых файлов: 37 добавлений и 24 удалений

Просмотреть файл

@ -0,0 +1,13 @@
var g = newGlobal();r
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
// executeInGlobal should be able to introduce and persist lexical bindings.
assertEq(gw.evalInGlobal(`let x = 42; x;`).return, 42);
assertEq(gw.evalInGlobal(`x;`).return, 42);
// By contrast, Debugger.Frame.eval is like direct eval, and shouldn't be able
// to introduce new lexical bindings.
dbg.onDebuggerStatement = function (frame) { frame.eval(`let y = 84;`); };
g.eval(`debugger;`);
assertEq(gw.evalInGlobal(`y;`).return, undefined);

Просмотреть файл

@ -361,7 +361,7 @@ jit::CanEnterBaselineMethod(JSContext* cx, RunState& state)
} else {
MOZ_ASSERT(state.isExecute());
ExecuteType type = state.asExecute()->type();
if (type == EXECUTE_DEBUG || type == EXECUTE_DEBUG_GLOBAL) {
if (type == EXECUTE_DEBUG) {
JitSpew(JitSpew_BaselineAbort, "debugger frame");
return Method_CantCompile;
}

Просмотреть файл

@ -6344,9 +6344,21 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
Rooted<ScopeObject*> enclosingStaticScope(cx);
if (!env->is<GlobalObject>())
enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
Rooted<StaticEvalObject*> staticScope(cx, StaticEvalObject::create(cx, enclosingStaticScope));
if (!staticScope)
return false;
// Do not consider executeInGlobal{WithBindings} as an eval, but instead
// as executing a series of statements at the global level. This is to
// circumvent the fresh lexical scope that all eval have, so that the
// users of executeInGlobal, like the web console, may add new bindings to
// the global scope.
Rooted<ScopeObject*> staticScope(cx);
if (frame) {
staticScope = StaticEvalObject::create(cx, enclosingStaticScope);
if (!staticScope)
return false;
} else {
staticScope = enclosingStaticScope;
}
CompileOptions options(cx);
options.setIsRunOnce(true)
.setForEval(true)
@ -6363,11 +6375,14 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
if (!script)
return false;
if (script->strict())
staticScope->setStrict();
// Again, executeInGlobal is not considered eval.
if (frame) {
if (script->strict())
staticScope->as<StaticEvalObject>().setStrict();
script->setActiveEval();
}
script->setActiveEval();
ExecuteType type = !frame ? EXECUTE_DEBUG_GLOBAL : EXECUTE_DEBUG;
ExecuteType type = !frame ? EXECUTE_GLOBAL : EXECUTE_DEBUG;
return ExecuteKernel(cx, script, *env, thisv, NullValue(), type, frame, rval.address());
}

Просмотреть файл

@ -253,20 +253,6 @@ InterpreterFrame::epilogue(JSContext* cx)
DebugScopes::onPopStrictEvalScope(this);
} else if (isDirectEvalFrame()) {
MOZ_ASSERT_IF(isDebuggerEvalFrame(), !IsSyntacticScope(scopeChain()));
} else {
/*
* Debugger.Object.prototype.evalInGlobal creates indirect eval
* frames scoped to the given global;
* Debugger.Object.prototype.evalInGlobalWithBindings creates
* indirect eval frames scoped to an object carrying the introduced
* bindings.
*/
if (isDebuggerEvalFrame()) {
MOZ_ASSERT(scopeChain()->is<GlobalObject>() ||
scopeChain()->enclosingScope()->is<GlobalObject>());
} else {
MOZ_ASSERT(scopeChain()->is<GlobalObject>());
}
}
return;
}

Просмотреть файл

@ -283,8 +283,7 @@ enum ExecuteType {
EXECUTE_MODULE = 0x4, /* == InterpreterFrame::GLOBAL */
EXECUTE_DIRECT_EVAL = 0x8, /* == InterpreterFrame::EVAL */
EXECUTE_INDIRECT_EVAL = 0x9, /* == InterpreterFrame::GLOBAL | EVAL */
EXECUTE_DEBUG = 0x18, /* == InterpreterFrame::EVAL | DEBUGGER */
EXECUTE_DEBUG_GLOBAL = 0x19 /* == InterpreterFrame::EVAL | DEBUGGER | GLOBAL */
EXECUTE_DEBUG = 0x18, /* == InterpreterFrame::EVAL | DEBUGGER_EVAL */
};
/*****************************************************************************/