Bug 1207868 - Implement Debugger.Object.asEnvironment. (r=jimb)

This commit is contained in:
Shu-yu Guo 2015-10-19 13:21:00 -07:00
parent cc8437882e
commit 4469c14daa
5 changed files with 54 additions and 10 deletions

View File

@ -427,9 +427,9 @@ code), the call throws a [`Debugger.DebuggeeWouldRun`][wouldrun] exception.
`asEnvironment()`
: If the referent is a global object, return the [`Debugger.Environment`][environment]
instance representing the referent as a variable environment for
evaluating code. If the referent is not a global object, throw a
`TypeError`.
instance representing the referent's global lexical scope. The global
lexical scope's enclosing scope is the global object. If the referent is
not a global object, throw a `TypeError`.
<code>setObjectWatchpoint(<i>handler</i>)</code> <i>(future plan)</i>
: Set a watchpoint on all the referent's own properties, reporting events

View File

@ -0,0 +1,15 @@
// Tests D.O.asEnvironment() returning the global lexical scope.
var g = newGlobal();
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
g.evaluate(`
var x = 42;
let y = "foo"
`);
var globalLexical = gw.asEnvironment();
assertEq(globalLexical.names().length, 1);
assertEq(globalLexical.getVariable("y"), "foo");
assertEq(globalLexical.parent.getVariable("x"), 42);

View File

@ -7687,6 +7687,24 @@ DebuggerObject_executeInGlobalWithBindings(JSContext* cx, unsigned argc, Value*
args.rval(), dbg, globalLexical, nullptr);
}
static bool
DebuggerObject_asEnvironment(JSContext* cx, unsigned argc, Value* vp)
{
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "asEnvironment", args, dbg, referent);
if (!RequireGlobalObject(cx, args.thisv(), referent))
return false;
Rooted<Env*> env(cx);
{
AutoCompartment ac(cx, referent);
env = GetDebugScopeForGlobalLexicalScope(cx);
if (!env)
return false;
}
return dbg->wrapEnvironment(cx, env, args.rval());
}
static bool
DebuggerObject_unwrap(JSContext* cx, unsigned argc, Value* vp)
{
@ -7764,6 +7782,7 @@ static const JSFunctionSpec DebuggerObject_methods[] = {
JS_FN("makeDebuggeeValue", DebuggerObject_makeDebuggeeValue, 1, 0),
JS_FN("executeInGlobal", DebuggerObject_executeInGlobal, 1, 0),
JS_FN("executeInGlobalWithBindings", DebuggerObject_executeInGlobalWithBindings, 2, 0),
JS_FN("asEnvironment", DebuggerObject_asEnvironment, 0, 0),
JS_FN("unwrap", DebuggerObject_unwrap, 0, 0),
JS_FN("unsafeDereference", DebuggerObject_unsafeDereference, 0, 0),
JS_FS_END

View File

@ -2859,6 +2859,13 @@ js::GetDebugScopeForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
return GetDebugScope(cx, si);
}
JSObject*
js::GetDebugScopeForGlobalLexicalScope(JSContext* cx)
{
ScopeIter si(cx, &cx->global()->lexicalScope(), &cx->global()->lexicalScope().staticBlock());
return GetDebugScope(cx, si);
}
// See declaration and documentation in jsfriendapi.h
JS_FRIEND_API(JSObject*)
js::GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun)

View File

@ -1109,13 +1109,13 @@ class LiveScopeVal
* now incomplete: it may not contain all, or any, of the ScopeObjects to
* represent the current scope.
*
* To resolve this, the debugger first calls GetDebugScopeFor(Function|Frame)
* to synthesize a "debug scope chain". A debug scope chain is just a chain of
* objects that fill in missing scopes and protect the engine from unexpected
* access. (The latter means that some debugger operations, like redefining a
* lexical binding, can fail when a true eval would succeed.) To do both of
* these things, GetDebugScopeFor* creates a new proxy DebugScopeObject to sit
* in front of every existing ScopeObject.
* To resolve this, the debugger first calls GetDebugScopeFor* to synthesize a
* "debug scope chain". A debug scope chain is just a chain of objects that
* fill in missing scopes and protect the engine from unexpected access. (The
* latter means that some debugger operations, like redefining a lexical
* binding, can fail when a true eval would succeed.) To do both of these
* things, GetDebugScopeFor* creates a new proxy DebugScopeObject to sit in
* front of every existing ScopeObject.
*
* GetDebugScopeFor* ensures the invariant that the same DebugScopeObject is
* always produced for the same underlying scope (optimized or not!). This is
@ -1128,6 +1128,9 @@ GetDebugScopeForFunction(JSContext* cx, HandleFunction fun);
extern JSObject*
GetDebugScopeForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
extern JSObject*
GetDebugScopeForGlobalLexicalScope(JSContext* cx);
/* Provides debugger access to a scope. */
class DebugScopeObject : public ProxyObject
{