зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1397049 - Fix debugger 'this' in functions with let. r=jorendorff
When the debugger evaluates code in the debuggee frame, the parser may fail to detect we are in a function context and will compute 'this' incorrectly as a result. This patch fixes the environment chain traversal around DebugEnvironmentProxy to more accurately determine the binding type of 'this' within a function. MozReview-Commit-ID: GzRDOJLK8fx
This commit is contained in:
Родитель
f12ca11346
Коммит
20193a2f37
|
@ -341,22 +341,25 @@ EvalSharedContext::EvalSharedContext(JSContext* cx, JSObject* enclosingEnv,
|
|||
computeInWith(enclosingScope);
|
||||
computeThisBinding(enclosingScope);
|
||||
|
||||
// Like all things Debugger, Debugger.Frame.eval needs special
|
||||
// handling. Since the environment chain of such evals are non-syntactic
|
||||
// (DebuggerEnvironmentProxy is not an EnvironmentObject), computing the
|
||||
// this binding with respect to enclosingScope is incorrect if the
|
||||
// Debugger.Frame is a function frame. Recompute the this binding if we
|
||||
// are such an eval.
|
||||
// If this eval is in response to Debugger.Frame.eval, we may have been
|
||||
// passed an incomplete scope chain. In order to better determine the 'this'
|
||||
// binding type, we traverse the environment chain, looking for a CallObject
|
||||
// and recompute the binding type based on its body scope.
|
||||
//
|
||||
// NOTE: A non-debug eval in a non-syntactic environment will also trigger
|
||||
// this code. In that case, we should still compute the same binding type.
|
||||
if (enclosingEnv && enclosingScope->hasOnChain(ScopeKind::NonSyntactic)) {
|
||||
// For Debugger.Frame.eval with bindings, the environment chain may
|
||||
// have more than the DebugEnvironmentProxy.
|
||||
JSObject* env = enclosingEnv;
|
||||
while (env) {
|
||||
// Look at target of any DebugEnvironmentProxy, but be sure to use
|
||||
// enclosingEnvironment() of the proxy itself.
|
||||
JSObject* unwrapped = env;
|
||||
if (env->is<DebugEnvironmentProxy>())
|
||||
env = &env->as<DebugEnvironmentProxy>().environment();
|
||||
unwrapped = &env->as<DebugEnvironmentProxy>().environment();
|
||||
|
||||
if (env->is<CallObject>()) {
|
||||
computeThisBinding(env->as<CallObject>().callee().nonLazyScript()->bodyScope());
|
||||
if (unwrapped->is<CallObject>()) {
|
||||
JSFunction* callee = &unwrapped->as<CallObject>().callee();
|
||||
computeThisBinding(callee->nonLazyScript()->bodyScope());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// Run debugger in its own global
|
||||
let g = newGlobal();
|
||||
g.target = this;
|
||||
g.evaluate(`
|
||||
let d = new Debugger;
|
||||
let gw = d.addDebuggee(target);
|
||||
|
||||
d.onDebuggerStatement = function(frame)
|
||||
{
|
||||
frame = frame.older;
|
||||
|
||||
let res = frame.eval("this");
|
||||
assertEq(res.return, frame.this);
|
||||
|
||||
res = frame.evalWithBindings("this", {x:42});
|
||||
assertEq(res.return, frame.this);
|
||||
}
|
||||
`);
|
||||
|
||||
// Debugger statement affects parse so hide in another function
|
||||
function brk() { debugger; }
|
||||
|
||||
function f1() {
|
||||
var temp = "string";
|
||||
brk();
|
||||
}
|
||||
|
||||
function f2() {
|
||||
let temp = "string";
|
||||
brk();
|
||||
}
|
||||
|
||||
function f3() {
|
||||
const temp = "string";
|
||||
brk();
|
||||
}
|
||||
|
||||
f1.call({});
|
||||
f2.call({});
|
||||
f3.call({});
|
|
@ -908,6 +908,9 @@ class DebugEnvironmentProxy : public ProxyObject
|
|||
static DebugEnvironmentProxy* create(JSContext* cx, EnvironmentObject& env,
|
||||
HandleObject enclosing);
|
||||
|
||||
// NOTE: The environment may be a debug hollow with invalid
|
||||
// enclosingEnvironment. Always use the enclosingEnvironment accessor on
|
||||
// the DebugEnvironmentProxy in order to walk the environment chain.
|
||||
EnvironmentObject& environment() const;
|
||||
JSObject& enclosingEnvironment() const;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче