From b99da5a94058ec28991d000fb608144afca71713 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Apr 2012 18:03:01 -0700 Subject: [PATCH] Bug 739512: Patch 9: move JSScript::debug into a table. r=jorendorff. --- js/src/jscompartment.cpp | 4 +- js/src/jscompartment.h | 2 + js/src/jsscript.cpp | 112 ++++++++++++++++++++++++++++----------- js/src/jsscript.h | 28 +++++++--- 4 files changed, 107 insertions(+), 39 deletions(-) diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index a7b0f7291033..256ebf7736e4 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -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) diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 139c2c37765a..ed2b89067bbb 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -467,6 +467,8 @@ struct JSCompartment js::ScriptCountsMap *scriptCountsMap; js::SourceMapMap *sourceMapMap; + + js::DebugScriptMap *debugScriptMap; }; #define JS_PROPERTY_TREE(cx) ((cx)->compartment->propertyTree) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 24e5628a96ae..c6762b4eb915 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -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_(); + 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"); } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 38dd676d395e..d6a8cbe91782 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -347,6 +347,11 @@ class DebugScript BreakpointSite *breakpoints[1]; }; +typedef HashMap, + 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