mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 637572 - Implement Debugger.Script.prototype.source; r=jimb
This commit is contained in:
parent
5717d5d389
commit
32dbbdb389
26
js/src/jit-test/tests/debug/Script-source-01.js
Normal file
26
js/src/jit-test/tests/debug/Script-source-01.js
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Script.prototype.source should be an object. Moreover, it should be the
|
||||
* same object for each child script within the same debugger.
|
||||
*/
|
||||
let g = newGlobal('new-compartment');
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
let count = 0;
|
||||
dbg.onNewScript = function (script) {
|
||||
assertEq(typeof script.source, "object");
|
||||
function traverse(script) {
|
||||
++count;
|
||||
script.getChildScripts().forEach(function (child) {
|
||||
assertEq(child.source, script.source);
|
||||
traverse(child);
|
||||
});
|
||||
}
|
||||
traverse(script);
|
||||
}
|
||||
|
||||
g.eval("2 * 3");
|
||||
g.eval("function f() {}");
|
||||
g.eval("function f() { function g() {} }");
|
||||
g.eval("eval('2 * 3')");
|
||||
g.eval("new Function('2 * 3')");
|
||||
assertEq(count, 10);
|
16
js/src/jit-test/tests/debug/Script-source-02.js
Normal file
16
js/src/jit-test/tests/debug/Script-source-02.js
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Script.prototype.source should be the same object for both the top-level
|
||||
* script and the script of functions accessed as debuggee values on the global
|
||||
*/
|
||||
let g = newGlobal('new-compartment');
|
||||
let dbg = new Debugger();
|
||||
let gw = dbg.addDebuggee(g);
|
||||
|
||||
let count = 0;
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
++count;
|
||||
assertEq(frame.script.source, gw.makeDebuggeeValue(g.f).script.source);
|
||||
}
|
||||
|
||||
g.eval("function f() {}; debugger;");
|
||||
assertEq(count, 1);
|
22
js/src/jit-test/tests/debug/Script-source-03.js
Normal file
22
js/src/jit-test/tests/debug/Script-source-03.js
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Script.prototype.source should be a different object for the same script
|
||||
* within different debuggers.
|
||||
*/
|
||||
let g = newGlobal('new-compartment');
|
||||
let dbg1 = new Debugger(g);
|
||||
let dbg2 = new Debugger(g);
|
||||
|
||||
var count = 0;
|
||||
var source;
|
||||
function test(script) {
|
||||
++count;
|
||||
if (!source)
|
||||
source = script.source;
|
||||
else
|
||||
assertEq(script.source != source, true);
|
||||
};
|
||||
dbg1.onNewScript = test;
|
||||
dbg2.onNewScript = test;
|
||||
|
||||
g.eval("2 * 3");
|
||||
assertEq(count, 2);
|
@ -65,6 +65,7 @@ struct CrossCompartmentKey
|
||||
ObjectWrapper,
|
||||
StringWrapper,
|
||||
DebuggerScript,
|
||||
DebuggerSource,
|
||||
DebuggerObject,
|
||||
DebuggerEnvironment
|
||||
};
|
||||
|
@ -74,6 +74,13 @@ enum {
|
||||
JSSLOT_DEBUGSCRIPT_COUNT
|
||||
};
|
||||
|
||||
extern Class DebuggerSource_class;
|
||||
|
||||
enum {
|
||||
JSSLOT_DEBUGSOURCE_OWNER,
|
||||
JSSLOT_DEBUGSOURCE_COUNT
|
||||
};
|
||||
|
||||
|
||||
/*** Utils ***************************************************************************************/
|
||||
|
||||
@ -360,7 +367,7 @@ Breakpoint::nextInSite()
|
||||
|
||||
Debugger::Debugger(JSContext *cx, JSObject *dbg)
|
||||
: object(dbg), uncaughtExceptionHook(NULL), enabled(true),
|
||||
frames(cx), scripts(cx), objects(cx), environments(cx)
|
||||
frames(cx), scripts(cx), sources(cx), objects(cx), environments(cx)
|
||||
{
|
||||
assertSameCompartment(cx, dbg);
|
||||
|
||||
@ -389,6 +396,7 @@ Debugger::init(JSContext *cx)
|
||||
bool ok = debuggees.init() &&
|
||||
frames.init() &&
|
||||
scripts.init() &&
|
||||
sources.init() &&
|
||||
objects.init() &&
|
||||
environments.init();
|
||||
if (!ok)
|
||||
@ -397,6 +405,7 @@ Debugger::init(JSContext *cx)
|
||||
}
|
||||
|
||||
JS_STATIC_ASSERT(unsigned(JSSLOT_DEBUGFRAME_OWNER) == unsigned(JSSLOT_DEBUGSCRIPT_OWNER));
|
||||
JS_STATIC_ASSERT(unsigned(JSSLOT_DEBUGFRAME_OWNER) == unsigned(JSSLOT_DEBUGSOURCE_OWNER));
|
||||
JS_STATIC_ASSERT(unsigned(JSSLOT_DEBUGFRAME_OWNER) == unsigned(JSSLOT_DEBUGOBJECT_OWNER));
|
||||
JS_STATIC_ASSERT(unsigned(JSSLOT_DEBUGFRAME_OWNER) == unsigned(JSSLOT_DEBUGENV_OWNER));
|
||||
|
||||
@ -1380,6 +1389,7 @@ Debugger::markKeysInCompartment(JSTracer *tracer)
|
||||
objects.markKeys(tracer);
|
||||
environments.markKeys(tracer);
|
||||
scripts.markKeys(tracer);
|
||||
sources.markKeys(tracer);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1391,10 +1401,11 @@ Debugger::markKeysInCompartment(JSTracer *tracer)
|
||||
* cross-compartment WeakMaps in non-GC'd compartments. If their keys and values
|
||||
* might need to be marked, we have to do it manually.
|
||||
*
|
||||
* Each Debugger object keeps three cross-compartment WeakMaps: objects, script,
|
||||
* and environments. They have the nice property that all their values are in
|
||||
* the same compartment as the Debugger object, so we only need to mark the
|
||||
* keys. We must simply mark all keys that are in a compartment being GC'd.
|
||||
* Each Debugger object keeps foud cross-compartment WeakMaps: objects, scripts,
|
||||
* script source objects, and environments. They have the nice property that all
|
||||
* their values are in the same compartment as the Debugger object, so we only
|
||||
* need to mark the keys. We must simply mark all keys that are in a compartment
|
||||
* being GC'd.
|
||||
*
|
||||
* We must scan all Debugger objects regardless of whether they *currently*
|
||||
* have any debuggees in a compartment being GC'd, because the WeakMap
|
||||
@ -1525,6 +1536,7 @@ Debugger::markAll(JSTracer *trc)
|
||||
MarkObject(trc, &dbgobj, "Debugger Object");
|
||||
|
||||
dbg->scripts.trace(trc);
|
||||
dbg->sources.trace(trc);
|
||||
dbg->objects.trace(trc);
|
||||
dbg->environments.trace(trc);
|
||||
|
||||
@ -1567,6 +1579,9 @@ Debugger::trace(JSTracer *trc)
|
||||
/* Trace the weak map from JSScript instances to Debugger.Script objects. */
|
||||
scripts.trace(trc);
|
||||
|
||||
/* Trace the referent ->Debugger.Source weak map */
|
||||
sources.trace(trc);
|
||||
|
||||
/* Trace the referent -> Debugger.Object weak map. */
|
||||
objects.trace(trc);
|
||||
|
||||
@ -1628,6 +1643,7 @@ Debugger::findCompartmentEdges(Zone *zone, js::gc::ComponentFinder<Zone> &finder
|
||||
if (w == zone || !w->isGCMarking())
|
||||
continue;
|
||||
if (dbg->scripts.hasKeyInZone(zone) ||
|
||||
dbg->sources.hasKeyInZone(zone) ||
|
||||
dbg->objects.hasKeyInZone(zone) ||
|
||||
dbg->environments.hasKeyInZone(zone))
|
||||
{
|
||||
@ -2817,6 +2833,21 @@ DebuggerScript_getLineCount(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebuggerScript_getSource(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get source)", args, obj, script);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(obj);
|
||||
|
||||
JS::RootedScriptSource source(cx, script->sourceObject());
|
||||
RootedObject sourceObject(cx, dbg->wrapSource(cx, source));
|
||||
if (!sourceObject)
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*sourceObject);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebuggerScript_getStaticLevel(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -3453,6 +3484,7 @@ static const JSPropertySpec DebuggerScript_properties[] = {
|
||||
JS_PSG("url", DebuggerScript_getUrl, 0),
|
||||
JS_PSG("startLine", DebuggerScript_getStartLine, 0),
|
||||
JS_PSG("lineCount", DebuggerScript_getLineCount, 0),
|
||||
JS_PSG("source", DebuggerScript_getSource, 0),
|
||||
JS_PSG("staticLevel", DebuggerScript_getStaticLevel, 0),
|
||||
JS_PSG("sourceMapURL", DebuggerScript_getSourceMapUrl, 0),
|
||||
JS_PS_END
|
||||
@ -3471,6 +3503,95 @@ static const JSFunctionSpec DebuggerScript_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
||||
/*** Debugger.Source *****************************************************************************/
|
||||
|
||||
static void
|
||||
DebuggerSource_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
/*
|
||||
* There is a barrier on private pointers, so the Unbarriered marking
|
||||
* is okay.
|
||||
*/
|
||||
if (JSObject *referent = (JSObject *) obj->getPrivate()) {
|
||||
MarkCrossCompartmentObjectUnbarriered(trc, obj, &referent, "Debugger.Source referent");
|
||||
obj->setPrivateUnbarriered(referent);
|
||||
}
|
||||
}
|
||||
|
||||
Class DebuggerSource_class = {
|
||||
"Source",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSOURCE_COUNT),
|
||||
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* hasInstance */
|
||||
DebuggerSource_trace
|
||||
};
|
||||
|
||||
JSObject *
|
||||
Debugger::newDebuggerSource(JSContext *cx, JS::HandleScriptSource source)
|
||||
{
|
||||
assertSameCompartment(cx, object.get());
|
||||
|
||||
JSObject *proto = &object->getReservedSlot(JSSLOT_DEBUG_SOURCE_PROTO).toObject();
|
||||
JS_ASSERT(proto);
|
||||
JSObject *sourceobj = NewObjectWithGivenProto(cx, &DebuggerSource_class, proto, NULL);
|
||||
if (!sourceobj)
|
||||
return NULL;
|
||||
sourceobj->setReservedSlot(JSSLOT_DEBUGSOURCE_OWNER, ObjectValue(*object));
|
||||
sourceobj->setPrivateGCThing(source);
|
||||
|
||||
return sourceobj;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
Debugger::wrapSource(JSContext *cx, JS::HandleScriptSource source)
|
||||
{
|
||||
assertSameCompartment(cx, object.get());
|
||||
JS_ASSERT(cx->compartment != source->compartment());
|
||||
SourceWeakMap::AddPtr p = sources.lookupForAdd(source);
|
||||
if (!p) {
|
||||
JSObject *sourceobj = newDebuggerSource(cx, source);
|
||||
if (!sourceobj)
|
||||
return NULL;
|
||||
|
||||
/* The allocation may have caused a GC, which can remove table entries. */
|
||||
if (!sources.relookupOrAdd(p, source, sourceobj)) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CrossCompartmentKey key(CrossCompartmentKey::DebuggerSource, object, source);
|
||||
if (!object->compartment()->putWrapper(key, ObjectValue(*sourceobj))) {
|
||||
sources.remove(source);
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JS_ASSERT((JSObject *) p->value->getPrivate() == source);
|
||||
return p->value;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebuggerSource_construct(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR, "Debugger.Source");
|
||||
return false;
|
||||
}
|
||||
|
||||
static const JSPropertySpec DebuggerSource_properties[] = {
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
static const JSFunctionSpec DebuggerSource_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
||||
/*** Debugger.Frame ******************************************************************************/
|
||||
|
||||
@ -5192,6 +5313,7 @@ JS_DefineDebuggerObject(JSContext *cx, JSObject *obj_)
|
||||
debugProto(cx),
|
||||
frameProto(cx),
|
||||
scriptProto(cx),
|
||||
sourceProto(cx),
|
||||
objectProto(cx),
|
||||
envProto(cx);
|
||||
|
||||
@ -5221,6 +5343,13 @@ JS_DefineDebuggerObject(JSContext *cx, JSObject *obj_)
|
||||
if (!scriptProto)
|
||||
return false;
|
||||
|
||||
sourceProto = js_InitClass(cx, debugCtor, sourceProto, &DebuggerSource_class,
|
||||
DebuggerSource_construct, 0,
|
||||
DebuggerSource_properties, DebuggerSource_methods,
|
||||
NULL, NULL);
|
||||
if (!sourceProto)
|
||||
return false;
|
||||
|
||||
objectProto = js_InitClass(cx, debugCtor, objProto, &DebuggerObject_class,
|
||||
DebuggerObject_construct, 0,
|
||||
DebuggerObject_properties, DebuggerObject_methods,
|
||||
@ -5238,6 +5367,7 @@ JS_DefineDebuggerObject(JSContext *cx, JSObject *obj_)
|
||||
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_FRAME_PROTO, ObjectValue(*frameProto));
|
||||
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_OBJECT_PROTO, ObjectValue(*objectProto));
|
||||
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_SCRIPT_PROTO, ObjectValue(*scriptProto));
|
||||
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_SOURCE_PROTO, ObjectValue(*sourceProto));
|
||||
debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_ENV_PROTO, ObjectValue(*envProto));
|
||||
return true;
|
||||
}
|
||||
|
@ -172,6 +172,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
||||
JSSLOT_DEBUG_ENV_PROTO,
|
||||
JSSLOT_DEBUG_OBJECT_PROTO,
|
||||
JSSLOT_DEBUG_SCRIPT_PROTO,
|
||||
JSSLOT_DEBUG_SOURCE_PROTO,
|
||||
JSSLOT_DEBUG_PROTO_STOP,
|
||||
JSSLOT_DEBUG_HOOK_START = JSSLOT_DEBUG_PROTO_STOP,
|
||||
JSSLOT_DEBUG_HOOK_STOP = JSSLOT_DEBUG_HOOK_START + HookCount,
|
||||
@ -216,6 +217,10 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
||||
typedef DebuggerWeakMap<EncapsulatedPtrScript, RelocatablePtrObject> ScriptWeakMap;
|
||||
ScriptWeakMap scripts;
|
||||
|
||||
/* The map from debuggee source script objects to their Debugger.Source instances. */
|
||||
typedef DebuggerWeakMap<EncapsulatedPtrObject, RelocatablePtrObject> SourceWeakMap;
|
||||
SourceWeakMap sources;
|
||||
|
||||
/* The map from debuggee objects to their Debugger.Object instances. */
|
||||
typedef DebuggerWeakMap<EncapsulatedPtrObject, RelocatablePtrObject> ObjectWeakMap;
|
||||
ObjectWeakMap objects;
|
||||
@ -348,6 +353,12 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
||||
*/
|
||||
JSObject *newDebuggerScript(JSContext *cx, HandleScript script);
|
||||
|
||||
/*
|
||||
* Allocate and initialize a Debugger.Source instance whose referent is
|
||||
* |source|.
|
||||
*/
|
||||
JSObject *newDebuggerSource(JSContext *cx, JS::HandleScriptSource source);
|
||||
|
||||
/*
|
||||
* Receive a "new script" event from the engine. A new script was compiled
|
||||
* or deserialized.
|
||||
@ -505,6 +516,13 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
||||
*/
|
||||
JSObject *wrapScript(JSContext *cx, HandleScript script);
|
||||
|
||||
/*
|
||||
* Return the Debugger.Source object for |source|, or create a new one if
|
||||
* needed. The context |cx| must be in the debugger compartment; |source|
|
||||
* must be a script source object in a debuggee compartment.
|
||||
*/
|
||||
JSObject *wrapSource(JSContext *cx, JS::HandleScriptSource source);
|
||||
|
||||
private:
|
||||
Debugger(const Debugger &) MOZ_DELETE;
|
||||
Debugger & operator=(const Debugger &) MOZ_DELETE;
|
||||
|
Loading…
Reference in New Issue
Block a user