Bug 738480: Simplify Debugger::ScriptQuery after CPG. Fix missing compile-and-go scripts. r=luke

This commit is contained in:
Jim Blandy 2012-10-19 09:53:00 -07:00
parent ca5d69fe83
commit cf6faf87d0
3 changed files with 45 additions and 68 deletions

View File

@ -0,0 +1,9 @@
// findScripts finds non-compile-and-go scripts
var g = newGlobal("new-compartment");
g.evaluate("function f(x) { return x + 1; }", {compileAndGo: false});
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
var s = dbg.findScripts();
var fw = gw.getOwnPropertyDescriptor("f").value;
assertEq(s.indexOf(fw.script) !== -1, true);

View File

@ -2126,16 +2126,15 @@ class Debugger::ScriptQuery {
public:
/* Construct a ScriptQuery to use matching scripts for |dbg|. */
ScriptQuery(JSContext *cx, Debugger *dbg):
cx(cx), debugger(dbg), compartments(cx), url(cx), innermostForGlobal(cx) {}
cx(cx), debugger(dbg), compartments(cx), url(cx), innermostForCompartment(cx) {}
/*
* Initialize this ScriptQuery. Raise an error and return false if we
* haven't enough memory.
*/
bool init() {
if (!globals.init() ||
!compartments.init() ||
!innermostForGlobal.init())
if (!compartments.init() ||
!innermostForCompartment.init())
{
js_ReportOutOfMemory(cx);
return false;
@ -2247,29 +2246,7 @@ class Debugger::ScriptQuery {
for (CompartmentSet::Range r = compartments.all(); !r.empty(); r.popFront()) {
for (gc::CellIter i(r.front(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
RawScript script = i.get<JSScript>();
if (script->compileAndGo && !script->isForEval()) {
if (!consider(script, &script->global(), vector))
return false;
}
}
}
/*
* Since eval scripts have no global, we need to find them via the call
* stack, where frame's scope tells us the global in use.
*/
for (ScriptFrameIter fri(cx); !fri.done(); ++fri) {
if (fri.isEvalFrame()) {
RawScript script = fri.script();
/*
* Eval scripts were not considered above so we don't need to
* check the existing script vector for duplicates.
*/
JS_ASSERT(script->isForEval());
GlobalObject *global = &fri.interpFrame()->global();
if (!consider(script, global, vector))
if (!consider(script, vector))
return false;
}
}
@ -2277,11 +2254,13 @@ class Debugger::ScriptQuery {
/*
* For most queries, we just accumulate results in 'vector' as we find
* them. But if this is an 'innermost' query, then we've accumulated the
* results in the 'innermostForGlobal' map. In that case, we now need to
* results in the 'innermostForCompartment' map. In that case, we now need to
* walk that map and populate 'vector'.
*/
if (innermost) {
for (GlobalToScriptMap::Range r = innermostForGlobal.all(); !r.empty(); r.popFront()) {
for (CompartmentToScriptMap::Range r = innermostForCompartment.all();
!r.empty();
r.popFront()) {
if (!vector->append(r.front().value)) {
js_ReportOutOfMemory(cx);
return false;
@ -2299,13 +2278,10 @@ class Debugger::ScriptQuery {
/* The debugger for which we conduct queries. */
Debugger *debugger;
/* A script must run in one of these globals to match the query. */
GlobalObjectSet globals;
typedef HashSet<JSCompartment *, DefaultHasher<JSCompartment *>, RuntimeAllocPolicy>
CompartmentSet;
/* The smallest set of compartments that contains all globals in globals. */
/* A script must be in one of these compartments to match the query. */
CompartmentSet compartments;
/* If this is a string, matching scripts have urls equal to it. */
@ -2323,20 +2299,20 @@ class Debugger::ScriptQuery {
/* True if the query has an 'innermost' property whose value is true. */
bool innermost;
typedef HashMap<GlobalObject *, JSScript *, DefaultHasher<GlobalObject *>, RuntimeAllocPolicy>
GlobalToScriptMap;
typedef HashMap<JSCompartment *, JSScript *, DefaultHasher<JSCompartment *>, RuntimeAllocPolicy>
CompartmentToScriptMap;
/*
* For 'innermost' queries, a map from global objects to the innermost
* script we've seen so far in that global. (Instantiation code size
* For 'innermost' queries, a map from compartments to the innermost script
* we've seen so far in that compartment. (Template instantiation code size
* explosion ho!)
*/
GlobalToScriptMap innermostForGlobal;
CompartmentToScriptMap innermostForCompartment;
/* Arrange for this ScriptQuery to match only scripts that run in |global|. */
bool matchSingleGlobal(GlobalObject *global) {
JS_ASSERT(globals.count() == 0);
if (!globals.put(global)) {
JS_ASSERT(compartments.count() == 0);
if (!compartments.put(global->compartment())) {
js_ReportOutOfMemory(cx);
return false;
}
@ -2348,10 +2324,10 @@ class Debugger::ScriptQuery {
* globals.
*/
bool matchAllDebuggeeGlobals() {
JS_ASSERT(globals.count() == 0);
/* Copy the debugger's set of debuggee globals to our global set. */
JS_ASSERT(compartments.count() == 0);
/* Build our compartment set from the debugger's set of debuggee globals. */
for (GlobalObjectSet::Range r = debugger->debuggees.all(); !r.empty(); r.popFront()) {
if (!globals.put(r.front())) {
if (!compartments.put(r.front()->compartment())) {
js_ReportOutOfMemory(cx);
return false;
}
@ -2364,17 +2340,6 @@ class Debugger::ScriptQuery {
* match scripts. Set urlCString as appropriate.
*/
bool prepareQuery() {
/*
* Compute the proper value for |compartments|, given the present
* value of |globals|.
*/
for (GlobalObjectSet::Range r = globals.all(); !r.empty(); r.popFront()) {
if (!compartments.put(r.front()->compartment())) {
js_ReportOutOfMemory(cx);
return false;
}
}
/* Compute urlCString, if a url was given. */
if (url.isString()) {
if (!urlCString.encode(cx, url.toString()))
@ -2385,12 +2350,13 @@ class Debugger::ScriptQuery {
}
/*
* If |script|, a script in |global|, matches this query, append it to
* |vector| or place it in |innermostForGlobal|, as appropriate. Return true
* if no error occurs, false if an error occurs.
* If |script| matches this query, append it to |vector| or place it in
* |innermostForCompartment|, as appropriate. Return true if no error
* occurs, false if an error occurs.
*/
bool consider(JSScript *script, GlobalObject *global, AutoScriptVector *vector) {
if (!globals.has(global))
bool consider(JSScript *script, AutoScriptVector *vector) {
JSCompartment *compartment = script->compartment();
if (!compartments.has(compartment))
return true;
if (urlCString.ptr()) {
if (!script->filename || strcmp(script->filename, urlCString.ptr()) != 0)
@ -2400,21 +2366,20 @@ class Debugger::ScriptQuery {
if (line < script->lineno || script->lineno + js_GetScriptLineExtent(script) < line)
return true;
}
if (innermost) {
/*
* For 'innermost' queries, we don't place scripts in |vector| right
* away; we may later find another script that is nested inside this
* one. Instead, we record the innermost script we've found so far
* for each global in innermostForGlobal, and only populate |vector|
* at the bottom of findScripts, when we've traversed all the
* scripts.
* for each compartment in innermostForCompartment, and only
* populate |vector| at the bottom of findScripts, when we've
* traversed all the scripts.
*
* So: check this script against the innermost one we've found so
* far (if any), as recorded in innermostForGlobal, and replace that
* if it's better.
* far (if any), as recorded in innermostForCompartment, and replace
* that if it's better.
*/
GlobalToScriptMap::AddPtr p = innermostForGlobal.lookupForAdd(global);
CompartmentToScriptMap::AddPtr p = innermostForCompartment.lookupForAdd(compartment);
if (p) {
/* Is our newly found script deeper than the last one we found? */
JSScript *incumbent = p->value;
@ -2423,9 +2388,9 @@ class Debugger::ScriptQuery {
} else {
/*
* This is the first matching script we've encountered for this
* global, so it is thus the innermost such script.
* compartment, so it is thus the innermost such script.
*/
if (!innermostForGlobal.add(p, global, script)) {
if (!innermostForCompartment.add(p, compartment, script)) {
js_ReportOutOfMemory(cx);
return false;
}

View File

@ -1052,6 +1052,9 @@ ThreadActor.prototype = {
* @returns true, if the script was added, false otherwise.
*/
_addScript: function TA__addScript(aScript) {
// Ignore anything we don't have a URL for (eval scripts, for example).
if (!aScript.url)
return false;
// Ignore XBL bindings for content debugging.
if (aScript.url.indexOf("chrome://") == 0) {
return false;