Bug 739512: Patch 9: move JSScript::debug into a table. r=jorendorff.

This commit is contained in:
Nicholas Nethercote 2012-04-10 18:03:01 -07:00
parent eab1ae6a1b
commit b99da5a940
4 changed files with 107 additions and 39 deletions

View File

@ -93,7 +93,8 @@ JSCompartment::JSCompartment(JSRuntime *rt)
mathCache(NULL),
watchpointMap(NULL),
scriptCountsMap(NULL),
sourceMapMap(NULL)
sourceMapMap(NULL),
debugScriptMap(NULL)
{
PodArrayZero(evalCache);
setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
@ -115,6 +116,7 @@ JSCompartment::~JSCompartment()
Foreground::delete_(watchpointMap);
Foreground::delete_(scriptCountsMap);
Foreground::delete_(sourceMapMap);
Foreground::delete_(debugScriptMap);
#ifdef DEBUG
for (size_t i = 0; i < ArrayLength(evalCache); ++i)

View File

@ -467,6 +467,8 @@ struct JSCompartment
js::ScriptCountsMap *scriptCountsMap;
js::SourceMapMap *sourceMapMap;
js::DebugScriptMap *debugScriptMap;
};
#define JS_PROPERTY_TREE(cx) ((cx)->compartment->propertyTree)

View File

@ -1521,19 +1521,7 @@ JSScript::finalize(FreeOp *fop)
destroyScriptCounts(fop);
destroySourceMap(fop);
if (debug) {
jsbytecode *end = code + length;
for (jsbytecode *pc = code; pc < end; pc++) {
if (BreakpointSite *site = getBreakpointSite(pc)) {
/* Breakpoints are swept before finalization. */
JS_ASSERT(site->firstBreakpoint() == NULL);
site->clearTrap(fop, NULL, NULL);
JS_ASSERT(getBreakpointSite(pc) == NULL);
}
}
fop->free_(debug);
}
destroyDebugScript(fop);
JS_POISON(data, 0xdb, computedSizeOfData());
fop->free_(data);
@ -1770,17 +1758,78 @@ js::CloneScript(JSContext *cx, JSScript *script)
return newScript;
}
bool
JSScript::ensureHasDebug(JSContext *cx)
DebugScript *
JSScript::debugScript()
{
if (debug)
JS_ASSERT(hasDebugScript);
DebugScriptMap *map = compartment()->debugScriptMap;
JS_ASSERT(map);
DebugScriptMap::Ptr p = map->lookup(this);
JS_ASSERT(p);
return p->value;
}
DebugScript *
JSScript::releaseDebugScript()
{
JS_ASSERT(hasDebugScript);
DebugScriptMap *map = compartment()->debugScriptMap;
JS_ASSERT(map);
DebugScriptMap::Ptr p = map->lookup(this);
JS_ASSERT(p);
DebugScript *debug = p->value;
map->remove(p);
hasDebugScript = false;
return debug;
}
void
JSScript::destroyDebugScript(FreeOp *fop)
{
if (hasDebugScript) {
jsbytecode *end = code + length;
for (jsbytecode *pc = code; pc < end; pc++) {
if (BreakpointSite *site = getBreakpointSite(pc)) {
/* Breakpoints are swept before finalization. */
JS_ASSERT(site->firstBreakpoint() == NULL);
site->clearTrap(fop, NULL, NULL);
JS_ASSERT(getBreakpointSite(pc) == NULL);
}
}
fop->free_(releaseDebugScript());
}
}
bool
JSScript::ensureHasDebugScript(JSContext *cx)
{
if (hasDebugScript)
return true;
size_t nbytes = offsetof(DebugScript, breakpoints) + length * sizeof(BreakpointSite*);
debug = (DebugScript *) cx->calloc_(nbytes);
DebugScript *debug = (DebugScript *) cx->calloc_(nbytes);
if (!debug)
return false;
/* Create compartment's debugScriptMap if necessary. */
DebugScriptMap *map = compartment()->debugScriptMap;
if (!map) {
map = cx->new_<DebugScriptMap>();
if (!map || !map->init()) {
cx->free_(debug);
cx->delete_(map);
return false;
}
compartment()->debugScriptMap = map;
}
if (!map->putNew(this, debug)) {
cx->free_(debug);
cx->delete_(map);
return false;
}
hasDebugScript = true; // safe to set this; we can't fail after this point
/*
* Ensure that any Interpret() instances running on this script have
* interrupts enabled. The interrupts must stay enabled until the
@ -1807,8 +1856,9 @@ JSScript::recompileForStepMode(FreeOp *fop)
bool
JSScript::tryNewStepMode(JSContext *cx, uint32_t newValue)
{
JS_ASSERT(debug);
JS_ASSERT(hasDebugScript);
DebugScript *debug = debugScript();
uint32_t prior = debug->stepMode;
debug->stepMode = newValue;
@ -1816,10 +1866,8 @@ JSScript::tryNewStepMode(JSContext *cx, uint32_t newValue)
/* Step mode has been enabled or disabled. Alert the methodjit. */
recompileForStepMode(cx->runtime->defaultFreeOp());
if (!stepModeEnabled() && !debug->numSites) {
cx->free_(debug);
debug = NULL;
}
if (!stepModeEnabled() && !debug->numSites)
cx->free_(releaseDebugScript());
}
return true;
@ -1828,21 +1876,23 @@ JSScript::tryNewStepMode(JSContext *cx, uint32_t newValue)
bool
JSScript::setStepModeFlag(JSContext *cx, bool step)
{
if (!ensureHasDebug(cx))
if (!ensureHasDebugScript(cx))
return false;
return tryNewStepMode(cx, (debug->stepMode & stepCountMask) | (step ? stepFlagMask : 0));
return tryNewStepMode(cx, (debugScript()->stepMode & stepCountMask) |
(step ? stepFlagMask : 0));
}
bool
JSScript::changeStepModeCount(JSContext *cx, int delta)
{
if (!ensureHasDebug(cx))
if (!ensureHasDebugScript(cx))
return false;
assertSameCompartment(cx, this);
JS_ASSERT_IF(delta > 0, cx->compartment->debugMode());
DebugScript *debug = debugScript();
uint32_t count = debug->stepMode & stepCountMask;
JS_ASSERT(((count + delta) & stepCountMask) == count + delta);
return tryNewStepMode(cx,
@ -1856,9 +1906,10 @@ JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
{
JS_ASSERT(size_t(pc - code) < length);
if (!ensureHasDebug(cx))
if (!ensureHasDebugScript(cx))
return NULL;
DebugScript *debug = debugScript();
BreakpointSite *&site = debug->breakpoints[pc - code];
if (!site) {
@ -1883,16 +1934,15 @@ JSScript::destroyBreakpointSite(FreeOp *fop, jsbytecode *pc)
{
JS_ASSERT(unsigned(pc - code) < length);
DebugScript *debug = debugScript();
BreakpointSite *&site = debug->breakpoints[pc - code];
JS_ASSERT(site);
fop->delete_(site);
site = NULL;
if (--debug->numSites == 0 && !stepModeEnabled()) {
fop->free_(debug);
debug = NULL;
}
if (--debug->numSites == 0 && !stepModeEnabled())
fop->free_(releaseDebugScript());
}
void
@ -1970,7 +2020,7 @@ JSScript::markChildren(JSTracer *trc)
if (hasAnyBreakpointsOrStepMode()) {
for (unsigned i = 0; i < length; i++) {
BreakpointSite *site = debug->breakpoints[i];
BreakpointSite *site = debugScript()->breakpoints[i];
if (site && site->trapHandler)
MarkValue(trc, &site->trapClosure, "trap closure");
}

View File

@ -347,6 +347,11 @@ class DebugScript
BreakpointSite *breakpoints[1];
};
typedef HashMap<JSScript *,
DebugScript *,
DefaultHasher<JSScript *>,
SystemAllocPolicy> DebugScriptMap;
} /* namespace js */
static const uint32_t JS_SCRIPT_COOKIE = 0xc00cee;
@ -449,7 +454,6 @@ struct JSScript : public js::gc::Cell
#endif
private:
js::DebugScript *debug;
js::HeapPtrFunction function_;
size_t useCount; /* Number of times the script has been called
@ -476,6 +480,11 @@ struct JSScript : public js::gc::Cell
uint32_t idpad;
#endif
#if JS_BITS_PER_WORD == 32
private:
uint32_t pad32;
#endif
// 16-bit fields.
private:
@ -544,6 +553,8 @@ struct JSScript : public js::gc::Cell
JSCompartment::scriptCountsMap */
bool hasSourceMap:1; /* script has an entry in
JSCompartment::sourceMapMap */
bool hasDebugScript:1; /* script has an entry in
JSCompartment::debugScriptMap */
private:
/* See comments below. */
@ -834,16 +845,19 @@ struct JSScript : public js::gc::Cell
/* Attempt to change this->stepMode to |newValue|. */
bool tryNewStepMode(JSContext *cx, uint32_t newValue);
bool ensureHasDebug(JSContext *cx);
bool ensureHasDebugScript(JSContext *cx);
js::DebugScript *debugScript();
js::DebugScript *releaseDebugScript();
void destroyDebugScript(js::FreeOp *fop);
public:
bool hasBreakpointsAt(jsbytecode *pc) { return !!getBreakpointSite(pc); }
bool hasAnyBreakpointsOrStepMode() { return !!debug; }
bool hasAnyBreakpointsOrStepMode() { return hasDebugScript; }
js::BreakpointSite *getBreakpointSite(jsbytecode *pc)
{
JS_ASSERT(size_t(pc - code) < length);
return debug ? debug->breakpoints[pc - code] : NULL;
return hasDebugScript ? debugScript()->breakpoints[pc - code] : NULL;
}
js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
@ -872,10 +886,10 @@ struct JSScript : public js::gc::Cell
*/
bool changeStepModeCount(JSContext *cx, int delta);
bool stepModeEnabled() { return debug && !!debug->stepMode; }
bool stepModeEnabled() { return hasDebugScript && !!debugScript()->stepMode; }
#ifdef DEBUG
uint32_t stepModeCount() { return debug ? (debug->stepMode & stepCountMask) : 0; }
uint32_t stepModeCount() { return hasDebugScript ? (debugScript()->stepMode & stepCountMask) : 0; }
#endif
void finalize(js::FreeOp *fop);
@ -893,7 +907,7 @@ struct JSScript : public js::gc::Cell
void markChildren(JSTracer *trc);
};
/* If this fails, padding_ can be removed. */
/* If this fails, add/remove padding within JSScript. */
JS_STATIC_ASSERT(sizeof(JSScript) % js::gc::Cell::CellSize == 0);
static JS_INLINE unsigned