author | Igor Bukanov <igor@mir2.org> |
Tue, 20 Mar 2012 11:22:05 +0100 | |
changeset 90998 | d8c5316f513afee907aabd5a04873bdf41fdebb7 |
parent 90997 | 74053b148a3c8883ad1a375107c94359606f6e1e |
child 90999 | 82c7bdff95d4abc73c071f0dd901bde35b9b23f4 |
push id | 22409 |
push user | eakhgari@mozilla.com |
push date | Thu, 05 Apr 2012 17:41:22 +0000 |
treeherder | mozilla-central@90a4942abf08 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 737365 |
milestone | 14.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -702,17 +702,17 @@ JSRuntime::JSRuntime() #endif tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), execAlloc_(NULL), bumpAlloc_(NULL), nativeStackBase(0), nativeStackQuota(0), interpreterFrames(NULL), cxCallback(NULL), - compartmentCallback(NULL), + destroyCompartmentCallback(NULL), activityCallback(NULL), activityCallbackArg(NULL), #ifdef JS_THREADSAFE suspendCount(0), requestDepth(0), # ifdef DEBUG checkRequestDepth(0), # endif @@ -771,17 +771,17 @@ JSRuntime::JSRuntime() debugMode(false), profilingScripts(false), hadOutOfMemory(false), data(NULL), #ifdef JS_THREADSAFE gcLock(NULL), gcHelperThread(thisFromCtor()), #endif - defaultFreeOp_(thisFromCtor(), false, false, NULL), + defaultFreeOp_(thisFromCtor(), false, false), debuggerMutations(0), securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)), destroyPrincipals(NULL), structuredCloneCallbacks(NULL), telemetryCallback(NULL), propertyRemovals(0), thousandsSeparator(0), decimalSeparator(0), @@ -1320,22 +1320,20 @@ JS_SetJitHardening(JSRuntime *rt, JSBool } JS_PUBLIC_API(const char *) JS_GetImplementationVersion(void) { return "JavaScript-C 1.8.5+ 2011-04-16"; } -JS_PUBLIC_API(JSCompartmentCallback) -JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback) -{ - JSCompartmentCallback old = rt->compartmentCallback; - rt->compartmentCallback = callback; - return old; +JS_PUBLIC_API(void) +JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback) +{ + rt->destroyCompartmentCallback = callback; } JS_PUBLIC_API(JSWrapObjectCallback) JS_SetWrapObjectCallbacks(JSRuntime *rt, JSWrapObjectCallback callback, JSPreWrapCallback precallback) { JSWrapObjectCallback old = rt->wrapObjectCallback; @@ -3047,17 +3045,17 @@ JS_IdArrayGet(JSContext *cx, JSIdArray * { JS_ASSERT(index >= 0 && index < ida->length); return ida->vector[index]; } JS_PUBLIC_API(void) JS_DestroyIdArray(JSContext *cx, JSIdArray *ida) { - cx->free_(ida); + DestroyIdArray(cx->runtime->defaultFreeOp(), ida); } JS_PUBLIC_API(JSBool) JS_ValueToId(JSContext *cx, jsval v, jsid *idp) { AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, v); @@ -4271,17 +4269,17 @@ prop_iter_finalize(FreeOp *fop, JSObject { void *pdata = obj->getPrivate(); if (!pdata) return; if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) { /* Non-native case: destroy the ida enumerated when obj was created. */ JSIdArray *ida = (JSIdArray *) pdata; - JS_DestroyIdArray(fop->context, ida); + DestroyIdArray(fop, ida); } } static void prop_iter_trace(JSTracer *trc, JSObject *obj) { void *pdata = obj->getPrivate(); if (!pdata)
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1592,22 +1592,18 @@ typedef JSObject * /* * Callback used by the wrap hook to ask the embedding to prepare an object * for wrapping in a context. This might include unwrapping other wrappers * or even finding a more suitable object for the new compartment. */ typedef JSObject * (* JSPreWrapCallback)(JSContext *cx, JSObject *scope, JSObject *obj, unsigned flags); -typedef enum { - JSCOMPARTMENT_DESTROY -} JSCompartmentOp; - -typedef JSBool -(* JSCompartmentCallback)(JSContext *cx, JSCompartment *compartment, unsigned compartmentOp); +typedef void +(* JSDestroyCompartmentCallback)(JSFreeOp *fop, JSCompartment *compartment); /* * Read structured data from the reader r. This hook is used to read a value * previously serialized by a call to the WriteStructuredCloneOp hook. * * tag and data are the pair of uint32_t values from the header. The callback * may use the JS_Read* APIs to read any other relevant parts of the object * from the reader r. closure is any value passed to the JS_ReadStructuredClone @@ -2676,18 +2672,18 @@ extern JS_PUBLIC_API(uint32_t) JS_ToggleOptions(JSContext *cx, uint32_t options); extern JS_PUBLIC_API(void) JS_SetJitHardening(JSRuntime *rt, JSBool enabled); extern JS_PUBLIC_API(const char *) JS_GetImplementationVersion(void); -extern JS_PUBLIC_API(JSCompartmentCallback) -JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback); +extern JS_PUBLIC_API(void) +JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback); extern JS_PUBLIC_API(JSWrapObjectCallback) JS_SetWrapObjectCallbacks(JSRuntime *rt, JSWrapObjectCallback callback, JSPreWrapCallback precallback); extern JS_PUBLIC_API(JSCrossCompartmentCall *) JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target);
--- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -213,17 +213,17 @@ js_FinishAtomState(JSRuntime *rt) if (!state->atoms.initialized()) { /* * We are called with uninitialized state when JS_NewRuntime fails and * calls JS_DestroyRuntime on a partially initialized runtime. */ return; } - FreeOp fop(rt, false, false, NULL); + FreeOp fop(rt, false, false); for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) r.front().asPtr()->finalize(&fop); } bool js_InitCommonAtoms(JSContext *cx) { JSAtomState *state = &cx->runtime->atomState;
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -181,28 +181,26 @@ struct ConservativeGCData bool hasStackToScan() const { return !!nativeStackTop; } }; class FreeOp : public JSFreeOp { bool shouldFreeLater_; bool onBackgroundThread_; + public: - JSContext *context; - static FreeOp *get(JSFreeOp *fop) { return static_cast<FreeOp *>(fop); } - FreeOp(JSRuntime *rt, bool shouldFreeLater, bool onBackgroundThread, JSContext *cx) + FreeOp(JSRuntime *rt, bool shouldFreeLater, bool onBackgroundThread) : JSFreeOp(rt), shouldFreeLater_(shouldFreeLater), - onBackgroundThread_(onBackgroundThread), - context(cx) + onBackgroundThread_(onBackgroundThread) { } bool shouldFreeLater() const { return shouldFreeLater_; } bool onBackgroundThread() const { @@ -285,18 +283,18 @@ struct JSRuntime : js::RuntimeFriendFiel * Frames currently running in js::Interpret. See InterpreterFrames for * details. */ js::InterpreterFrames *interpreterFrames; /* Context create/destroy callback. */ JSContextCallback cxCallback; - /* Compartment create/destroy callback. */ - JSCompartmentCallback compartmentCallback; + /* Compartment destroy callback. */ + JSDestroyCompartmentCallback destroyCompartmentCallback; js::ActivityCallback activityCallback; void *activityCallbackArg; #ifdef JS_THREADSAFE /* Number of JS_SuspendRequest calls withot JS_ResumeRequest. */ unsigned suspendCount;
--- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -93,17 +93,17 @@ GetGSNCache(JSContext *cx) class AutoNamespaceArray : protected AutoGCRooter { public: AutoNamespaceArray(JSContext *cx) : AutoGCRooter(cx, NAMESPACES), context(cx) { array.init(); } ~AutoNamespaceArray() { - array.finish(context); + array.finish(context->runtime->defaultFreeOp()); } uint32_t length() const { return array.length; } private: JSContext *context; friend void AutoGCRooter::trace(JSTracer *trc);
--- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -461,28 +461,28 @@ JSCompartment::markTypes(JSTracer *trc) for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next()) { types::TypeObject *type = i.get<types::TypeObject>(); MarkTypeObjectRoot(trc, &type, "mark_types_scan"); JS_ASSERT(type == i.get<types::TypeObject>()); } } void -JSCompartment::discardJitCode(JSContext *cx) +JSCompartment::discardJitCode(FreeOp *fop) { /* * Kick all frames on the stack into the interpreter, and release all JIT * code in the compartment. */ #ifdef JS_METHODJIT mjit::ClearAllFrames(this); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(fop, script); /* * Use counts for scripts are reset on GC. After discarding code we * need to let it warm back up to get information like which opcodes * are setting array holes or accessing getter properties. */ script->resetUseCount(); } @@ -516,17 +516,17 @@ JSCompartment::sweep(FreeOp *fop, bool r emptyTypeObject = NULL; newObjectCache.reset(); sweepBreakpoints(fop); { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE); - discardJitCode(fop->context); + discardJitCode(fop); } if (!activeAnalysis) { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS); /* * Clear the analysis pool, but don't release its data yet. While * sweeping types any live data will be allocated into the pool. @@ -547,30 +547,30 @@ JSCompartment::sweep(FreeOp *fop, bool r * enabled in the compartment. */ if (types.inferenceEnabled) { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->types) { - types::TypeScript::Sweep(fop->context, script); + types::TypeScript::Sweep(fop, script); if (releaseTypes) { script->types->destroy(); script->types = NULL; script->typesPurged = true; } } } } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TYPES); - types.sweep(fop->context); + types.sweep(fop); } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_CLEAR_SCRIPT_ANALYSIS); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); script->clearAnalysis(); } @@ -672,22 +672,22 @@ JSCompartment::setDebugModeFromC(JSConte JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_IDLE); return false; } } debugModeBits = (debugModeBits & ~unsigned(DebugFromC)) | (b ? DebugFromC : 0); JS_ASSERT(debugMode() == enabledAfter); if (enabledBefore != enabledAfter) - updateForDebugMode(cx); + updateForDebugMode(cx->runtime->defaultFreeOp()); return true; } void -JSCompartment::updateForDebugMode(JSContext *cx) +JSCompartment::updateForDebugMode(FreeOp *fop) { for (ContextIter acx(rt); !acx.done(); acx.next()) { if (acx->compartment == this) acx->updateJITEnabled(); } #ifdef JS_METHODJIT bool enabled = debugMode(); @@ -699,17 +699,17 @@ JSCompartment::updateForDebugMode(JSCont /* * Discard JIT code and bytecode analyses for any scripts that change * debugMode. */ for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->debugMode != enabled) { - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(fop, script); script->clearAnalysis(); script->debugMode = enabled; } } #endif } bool @@ -717,36 +717,36 @@ JSCompartment::addDebuggee(JSContext *cx { bool wasEnabled = debugMode(); if (!debuggees.put(global)) { js_ReportOutOfMemory(cx); return false; } debugModeBits |= DebugFromJS; if (!wasEnabled) - updateForDebugMode(cx); + updateForDebugMode(cx->runtime->defaultFreeOp()); return true; } void -JSCompartment::removeDebuggee(JSContext *cx, +JSCompartment::removeDebuggee(FreeOp *fop, js::GlobalObject *global, js::GlobalObjectSet::Enum *debuggeesEnum) { bool wasEnabled = debugMode(); JS_ASSERT(debuggees.has(global)); if (debuggeesEnum) debuggeesEnum->removeFront(); else debuggees.remove(global); if (debuggees.empty()) { debugModeBits &= ~DebugFromJS; if (wasEnabled && !debugMode()) - updateForDebugMode(cx); + updateForDebugMode(fop); } } void JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler) { for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); @@ -756,17 +756,17 @@ JSCompartment::clearBreakpointsIn(JSCont } void JSCompartment::clearTraps(JSContext *cx) { for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->hasAnyBreakpointsOrStepMode()) - script->clearTraps(cx); + script->clearTraps(cx->runtime->defaultFreeOp()); } } void JSCompartment::sweepBreakpoints(FreeOp *fop) { if (JS_CLIST_IS_EMPTY(&rt->debuggerList)) return; @@ -781,17 +781,17 @@ JSCompartment::sweepBreakpoints(FreeOp * if (!site) continue; // nextbp is necessary here to avoid possibly reading *bp after // destroying it. Breakpoint *nextbp; for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) { nextbp = bp->nextInSite(); if (scriptGone || IsAboutToBeFinalized(bp->debugger->toJSObject())) - bp->destroy(fop->context); + bp->destroy(fop); } } } } size_t JSCompartment::sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf) {
--- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -378,17 +378,17 @@ struct JSCompartment bool wrap(JSContext *cx, JSObject **objp); bool wrapId(JSContext *cx, jsid *idp); bool wrap(JSContext *cx, js::PropertyOp *op); bool wrap(JSContext *cx, js::StrictPropertyOp *op); bool wrap(JSContext *cx, js::PropertyDescriptor *desc); bool wrap(JSContext *cx, js::AutoIdVector &props); void markTypes(JSTracer *trc); - void discardJitCode(JSContext *cx); + void discardJitCode(js::FreeOp *fop); void sweep(js::FreeOp *fop, bool releaseTypes); void purge(); void setGCLastBytes(size_t lastBytes, size_t lastMallocBytes, js::JSGCInvocationKind gckind); void reduceGCTriggerBytes(size_t amount); void resetGCMallocBytes(); void setGCMaxMallocBytes(size_t value); @@ -441,22 +441,22 @@ struct JSCompartment */ bool debugMode() const { return !!debugModeBits; } /* True if any scripts from this compartment are on the JS stack. */ bool hasScriptsOnStack(); private: /* This is called only when debugMode() has just toggled. */ - void updateForDebugMode(JSContext *cx); + void updateForDebugMode(js::FreeOp *fop); public: js::GlobalObjectSet &getDebuggees() { return debuggees; } bool addDebuggee(JSContext *cx, js::GlobalObject *global); - void removeDebuggee(JSContext *cx, js::GlobalObject *global, + void removeDebuggee(js::FreeOp *fop, js::GlobalObject *global, js::GlobalObjectSet::Enum *debuggeesEnum = NULL); bool setDebugModeFromC(JSContext *cx, bool b); void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler); void clearTraps(JSContext *cx); private: void sweepBreakpoints(js::FreeOp *fop);
--- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -199,38 +199,38 @@ JS_SetTrap(JSContext *cx, JSScript *scri assertSameCompartment(cx, script, closure); if (!CheckDebugMode(cx)) return false; BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, NULL); if (!site) return false; - site->setTrap(cx, handler, closure); + site->setTrap(cx->runtime->defaultFreeOp(), handler, closure); return true; } JS_PUBLIC_API(void) JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler *handlerp, jsval *closurep) { if (BreakpointSite *site = script->getBreakpointSite(pc)) { - site->clearTrap(cx, handlerp, closurep); + site->clearTrap(cx->runtime->defaultFreeOp(), handlerp, closurep); } else { if (handlerp) *handlerp = NULL; if (closurep) *closurep = JSVAL_VOID; } } JS_PUBLIC_API(void) JS_ClearScriptTraps(JSContext *cx, JSScript *script) { - script->clearTraps(cx); + script->clearTraps(cx->runtime->defaultFreeOp()); } JS_PUBLIC_API(void) JS_ClearAllTrapsForCompartment(JSContext *cx) { cx->compartment->clearTraps(cx); }
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2760,25 +2760,25 @@ GCHelperThread::replenishAndFreeLater(vo } while (false); Foreground::free_(ptr); } /* Must be called with the GC lock taken. */ void GCHelperThread::doSweep() { - if (JSContext *cx = finalizationContext) { + if (finalizationContext) { finalizationContext = NULL; AutoUnlockGC unlock(rt); /* * We must finalize in the insert order, see comments in * finalizeObjects. */ - FreeOp fop(rt, false, true, cx); + FreeOp fop(rt, false, true); for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i) ArenaLists::backgroundFinalize(&fop, *i); finalizeVector.resize(0); if (freeCursor) { void **array = freeCursorEnd - FREE_ARRAY_LENGTH; freeElementsAndArray(array, freeCursor); freeCursor = freeCursorEnd = NULL; @@ -2828,34 +2828,34 @@ ReleaseObservedTypes(JSRuntime *rt) return releaseTypes; } static void SweepCompartments(FreeOp *fop, JSGCInvocationKind gckind) { JSRuntime *rt = fop->runtime(); - JSCompartmentCallback callback = rt->compartmentCallback; + JSDestroyCompartmentCallback callback = rt->destroyCompartmentCallback; /* Skip the atomsCompartment. */ JSCompartment **read = rt->compartments.begin() + 1; JSCompartment **end = rt->compartments.end(); JSCompartment **write = read; JS_ASSERT(rt->compartments.length() >= 1); JS_ASSERT(*rt->compartments.begin() == rt->atomsCompartment); while (read < end) { JSCompartment *compartment = *read++; if (!compartment->hold && (compartment->arenas.arenaListsAreEmpty() || !rt->hasContexts())) { compartment->arenas.checkEmptyFreeLists(); if (callback) - JS_ALWAYS_TRUE(callback(fop->context, compartment, JSCOMPARTMENT_DESTROY)); + callback(fop, compartment); if (compartment->principals) JS_DropPrincipals(rt, compartment->principals); fop->delete_(compartment); continue; } *write++ = compartment; } rt->compartments.resize(write - rt->compartments.begin()); @@ -3110,17 +3110,17 @@ SweepPhase(JSContext *cx, JSGCInvocation if (rt->hasContexts() && rt->gcHelperThread.prepareForBackgroundSweep()) cx->gcBackgroundFree = &rt->gcHelperThread; #endif /* Purge the ArenaLists before sweeping. */ for (GCCompartmentsIter c(rt); !c.done(); c.next()) c->arenas.purge(); - FreeOp fop(rt, !!cx->gcBackgroundFree, false, cx); + FreeOp fop(rt, !!cx->gcBackgroundFree, false); { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_FINALIZE_START); if (rt->gcFinalizeCallback) rt->gcFinalizeCallback(&fop, JSFINALIZE_START); } /* Finalize unreachable (key,value) pairs in all weak maps. */ WeakMapBase::sweepAll(&rt->gcMarker); @@ -3411,17 +3411,17 @@ IncrementalGCSlice(JSContext *cx, int64_ } if (rt->gcIncrementalState == MARK_ROOTS) { rt->gcMarker.start(rt); JS_ASSERT(IS_GC_MARKING_TRACER(&rt->gcMarker)); for (GCCompartmentsIter c(rt); !c.done(); c.next()) { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE); - c->discardJitCode(cx); + c->discardJitCode(rt->defaultFreeOp()); } BeginMarkPhase(rt); rt->gcIncrementalState = MARK; } if (rt->gcIncrementalState == MARK) { @@ -4170,17 +4170,17 @@ StartVerifyBarriers(JSContext *cx) AutoCopyFreeListToArenas copy(rt); RecordNativeStackTopForGC(rt); for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) r.front()->bitmap.clear(); for (CompartmentsIter c(rt); !c.done(); c.next()) - c->discardJitCode(cx); + c->discardJitCode(rt->defaultFreeOp()); VerifyTracer *trc = new (js_malloc(sizeof(VerifyTracer))) VerifyTracer; rt->gcNumber++; trc->number = rt->gcNumber; trc->count = 0; JS_TracerInit(trc, rt, AccumulateEdge); @@ -4324,17 +4324,17 @@ EndVerifyBarriers(JSContext *cx) JS_ASSERT(trc->number == rt->gcNumber); rt->gcNumber++; /* We need to disable barriers before tracing, which may invoke barriers. */ for (CompartmentsIter c(rt); !c.done(); c.next()) c->needsBarrier_ = false; for (CompartmentsIter c(rt); !c.done(); c.next()) - c->discardJitCode(cx); + c->discardJitCode(rt->defaultFreeOp()); rt->gcVerifyData = NULL; rt->gcIncrementalState = NO_INCREMENTAL; JS_TracerInit(trc, rt, MarkFromAutorooter); AutoGCRooter::traceAll(trc); @@ -4418,17 +4418,17 @@ MaybeVerifyBarriers(JSContext *cx, bool static void ReleaseAllJITCode(JSContext *cx) { #ifdef JS_METHODJIT for (GCCompartmentsIter c(cx->runtime); !c.done(); c.next()) { mjit::ClearAllFrames(c); for (CellIter i(c, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), script); } } #endif } /* * There are three possible PCCount profiling states: *
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -2077,91 +2077,97 @@ TypeCompartment::growPendingArray(JSCont pendingArray = newArray; pendingCapacity = newCapacity; return true; } void -TypeCompartment::processPendingRecompiles(JSContext *cx) +TypeCompartment::processPendingRecompiles(FreeOp *fop) { /* Steal the list of scripts to recompile, else we will try to recursively recompile them. */ Vector<RecompileInfo> *pending = pendingRecompiles; pendingRecompiles = NULL; JS_ASSERT(!pending->empty()); #ifdef JS_METHODJIT - mjit::ExpandInlineFrames(cx->compartment); + mjit::ExpandInlineFrames(compartment()); for (unsigned i = 0; i < pending->length(); i++) { const RecompileInfo &info = (*pending)[i]; mjit::JITScript *jit = info.script->getJIT(info.constructing); if (jit && jit->chunkDescriptor(info.chunkIndex).chunk) - mjit::Recompiler::clearStackReferencesAndChunk(cx, info.script, jit, info.chunkIndex); + mjit::Recompiler::clearStackReferencesAndChunk(fop, info.script, jit, info.chunkIndex); } #endif /* JS_METHODJIT */ - cx->delete_(pending); + fop->delete_(pending); } void TypeCompartment::setPendingNukeTypes(JSContext *cx) { JS_ASSERT(compartment()->activeInference); if (!pendingNukeTypes) { if (cx->compartment) js_ReportOutOfMemory(cx); pendingNukeTypes = true; } } void -TypeCompartment::nukeTypes(JSContext *cx) -{ - JS_ASSERT(this == &cx->compartment->types); - +TypeCompartment::setPendingNukeTypesNoReport() +{ + JS_ASSERT(compartment()->activeInference); + if (!pendingNukeTypes) + pendingNukeTypes = true; +} + +void +TypeCompartment::nukeTypes(FreeOp *fop) +{ /* * This is the usual response if we encounter an OOM while adding a type * or resolving type constraints. Reset the compartment to not use type * inference, and recompile all scripts. * * Because of the nature of constraint-based analysis (add constraints, and * iterate them until reaching a fixpoint), we can't undo an add of a type set, * and merely aborting the operation which triggered the add will not be * sufficient for correct behavior as we will be leaving the types in an * inconsistent state. */ JS_ASSERT(pendingNukeTypes); if (pendingRecompiles) { - cx->free_(pendingRecompiles); + fop->free_(pendingRecompiles); pendingRecompiles = NULL; } inferenceEnabled = false; /* Update the cached inferenceEnabled bit in all contexts. */ - for (ContextIter acx(cx->runtime); !acx.done(); acx.next()) + for (ContextIter acx(fop->runtime()); !acx.done(); acx.next()) acx->setCompartment(acx->compartment); #ifdef JS_METHODJIT - JSCompartment *compartment = cx->compartment; + JSCompartment *compartment = this->compartment(); mjit::ExpandInlineFrames(compartment); mjit::ClearAllFrames(compartment); /* Throw away all JIT code in the compartment, but leave everything else alone. */ - for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (gc::CellIter i(compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->hasJITCode()) - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(fop, script); } #endif /* JS_METHODJIT */ } void TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info) { @@ -5725,17 +5731,17 @@ JSCompartment::getLazyType(JSContext *cx return type; } ///////////////////////////////////////////////////////////////////// // Tracing ///////////////////////////////////////////////////////////////////// void -TypeSet::sweep(JSContext *cx, JSCompartment *compartment) +TypeSet::sweep(JSCompartment *compartment) { /* * Purge references to type objects that are no longer live. Type sets hold * only weak references. For type sets containing more than one object, * live entries in the object hash need to be copied to the compartment's * new arena. */ unsigned objectCount = baseObjectCount(); @@ -5749,17 +5755,17 @@ TypeSet::sweep(JSContext *cx, JSCompartm TypeObjectKey *object = oldArray[i]; if (object && !IsAboutToBeFinalized(object)) { TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey> (compartment, objectSet, objectCount, object); if (pentry) *pentry = object; else - compartment->types.setPendingNukeTypes(cx); + compartment->types.setPendingNukeTypesNoReport(); } } setBaseObjectCount(objectCount); } else if (objectCount == 1) { TypeObjectKey *object = (TypeObjectKey *) objectSet; if (IsAboutToBeFinalized(object)) { objectSet = NULL; setBaseObjectCount(0); @@ -5784,17 +5790,17 @@ TypeObject::clearProperties() /* * Before sweeping the arenas themselves, scan all type objects in a * compartment to fixup weak references: property type sets referencing dead * JS and type objects, and singleton JS objects whose type is not referenced * elsewhere. This also releases memory associated with dead type objects, * so that type objects do not need later finalization. */ inline void -TypeObject::sweep(JSContext *cx) +TypeObject::sweep(FreeOp *fop) { /* * We may be regenerating existing type sets containing this object, * so reset contributions on each GC to avoid tripping the limit. */ contribution = 0; if (singleton) { @@ -5806,17 +5812,17 @@ TypeObject::sweep(JSContext *cx) */ clearProperties(); return; } if (!isMarked()) { if (newScript) - Foreground::free_(newScript); + fop->free_(newScript); return; } JSCompartment *compartment = this->compartment(); /* * Properties were allocated from the old arena, and need to be copied over * to the new one. Don't hang onto properties without the OWN_PROPERTY @@ -5835,35 +5841,35 @@ TypeObject::sweep(JSContext *cx) if (prop && prop->types.isOwnProperty(false)) { Property *newProp = compartment->typeLifoAlloc.new_<Property>(*prop); if (newProp) { Property **pentry = HashSetInsert<jsid,Property,Property> (compartment, propertySet, propertyCount, prop->id); if (pentry) { *pentry = newProp; - newProp->types.sweep(cx, compartment); + newProp->types.sweep(compartment); } else { - compartment->types.setPendingNukeTypes(cx); + compartment->types.setPendingNukeTypesNoReport(); } } else { - compartment->types.setPendingNukeTypes(cx); + compartment->types.setPendingNukeTypesNoReport(); } } } setBasePropertyCount(propertyCount); } else if (propertyCount == 1) { Property *prop = (Property *) propertySet; if (prop->types.isOwnProperty(false)) { Property *newProp = compartment->typeLifoAlloc.new_<Property>(*prop); if (newProp) { propertySet = (Property **) newProp; - newProp->types.sweep(cx, compartment); + newProp->types.sweep(compartment); } else { - compartment->types.setPendingNukeTypes(cx); + compartment->types.setPendingNukeTypesNoReport(); } } else { propertySet = NULL; setBasePropertyCount(0); } } if (basePropertyCount() <= SET_ARRAY_SIZE) { @@ -5877,37 +5883,37 @@ TypeObject::sweep(JSContext *cx) * the next time we compile code which depends on this info. */ if (newScript) flags |= OBJECT_FLAG_NEW_SCRIPT_REGENERATE; } struct SweepTypeObjectOp { - JSContext *cx; - SweepTypeObjectOp(JSContext *cx) : cx(cx) {} + FreeOp *fop; + SweepTypeObjectOp(FreeOp *fop) : fop(fop) {} void operator()(gc::Cell *cell) { TypeObject *object = static_cast<TypeObject *>(cell); - object->sweep(cx); + object->sweep(fop); } }; void -SweepTypeObjects(JSContext *cx, JSCompartment *compartment) -{ - SweepTypeObjectOp op(cx); +SweepTypeObjects(FreeOp *fop, JSCompartment *compartment) +{ + SweepTypeObjectOp op(fop); gc::ForEachArenaAndCell(compartment, gc::FINALIZE_TYPE_OBJECT, gc::EmptyArenaOp, op); } void -TypeCompartment::sweep(JSContext *cx) +TypeCompartment::sweep(FreeOp *fop) { JSCompartment *compartment = this->compartment(); - SweepTypeObjects(cx, compartment); + SweepTypeObjects(fop, compartment); /* * Iterate through the array/object type tables and remove all entries * referencing collected data. These tables only hold weak references. */ if (arrayTypeTable) { for (ArrayTypeTable::Enum e(*arrayTypeTable); !e.empty(); e.popFront()) { @@ -5965,17 +5971,17 @@ TypeCompartment::sweep(JSContext *cx) } } /* * The pending array is reset on GC, it can grow large (75+ KB) and is easy * to reallocate if the compartment becomes active again. */ if (pendingArray) - cx->free_(pendingArray); + fop->free_(pendingArray); pendingArray = NULL; pendingCapacity = 0; } void JSCompartment::sweepNewTypeObjectTable(TypeObjectSet &table) { @@ -5999,37 +6005,37 @@ TypeCompartment::~TypeCompartment() if (objectTypeTable) Foreground::delete_(objectTypeTable); if (allocationSiteTable) Foreground::delete_(allocationSiteTable); } /* static */ void -TypeScript::Sweep(JSContext *cx, JSScript *script) +TypeScript::Sweep(FreeOp *fop, JSScript *script) { JSCompartment *compartment = script->compartment(); JS_ASSERT(compartment->types.inferenceEnabled); unsigned num = NumTypeSets(script); TypeSet *typeArray = script->types->typeArray(); /* Remove constraints and references to dead objects from the persistent type sets. */ for (unsigned i = 0; i < num; i++) - typeArray[i].sweep(cx, compartment); + typeArray[i].sweep(compartment); TypeResult **presult = &script->types->dynamicList; while (*presult) { TypeResult *result = *presult; Type type = result->type; if (!type.isUnknown() && !type.isAnyObject() && type.isObject() && IsAboutToBeFinalized(type.objectKey())) { *presult = result->next; - cx->delete_(result); + fop->delete_(result); } else { presult = &result->next; } } /* * If the script has nesting state with a most recent activation, we do not * need either to mark the call object or clear it if not live. Even with
--- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -361,17 +361,17 @@ class TypeSet TypeConstraint *constraintList; TypeSet() : flags(0), objectSet(NULL), constraintList(NULL) {} void print(JSContext *cx); - inline void sweep(JSContext *cx, JSCompartment *compartment); + inline void sweep(JSCompartment *compartment); inline size_t computedSizeOfExcludingThis(); /* Whether this set contains a specific type. */ inline bool hasType(Type type); TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; } bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); } bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); } @@ -859,17 +859,17 @@ struct TypeObject : gc::Cell void setFlags(JSContext *cx, TypeObjectFlags flags); void markUnknown(JSContext *cx); void clearNewScript(JSContext *cx); void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false); void print(JSContext *cx); inline void clearProperties(); - inline void sweep(JSContext *cx); + inline void sweep(FreeOp *fop); inline size_t computedSizeOfExcludingThis(); void sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf); /* * Type objects don't have explicit finalizers. Memory owned by a type * object pending deletion is released when weak references are sweeped @@ -1116,17 +1116,17 @@ class TypeScript /* Add a type for a variable in a script. */ static inline void SetThis(JSContext *cx, JSScript *script, Type type); static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value); static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type); static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value); static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type); static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value); - static void Sweep(JSContext *cx, JSScript *script); + static void Sweep(FreeOp *fop, JSScript *script); inline void trace(JSTracer *trc); void destroy(); }; struct ArrayTableKey; typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable; struct ObjectTableKey; @@ -1239,34 +1239,35 @@ struct TypeCompartment * js_ObjectClass). */ TypeObject *newTypeObject(JSContext *cx, JSScript *script, JSProtoKey kind, JSObject *proto, bool unknown = false); /* Make an object for an allocation site. */ TypeObject *newAllocationSiteTypeObject(JSContext *cx, const AllocationSiteKey &key); - void nukeTypes(JSContext *cx); - void processPendingRecompiles(JSContext *cx); + void nukeTypes(FreeOp *fop); + void processPendingRecompiles(FreeOp *fop); /* Mark all types as needing destruction once inference has 'finished'. */ void setPendingNukeTypes(JSContext *cx); + void setPendingNukeTypesNoReport(); /* Mark a script as needing recompilation once inference has finished. */ void addPendingRecompile(JSContext *cx, const RecompileInfo &info); void addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc); /* Monitor future effects on a bytecode. */ void monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset, bool returnOnly = false); /* Mark any type set containing obj as having a generic object type. */ void markSetsUnknown(JSContext *cx, TypeObject *obj); - void sweep(JSContext *cx); + void sweep(FreeOp *fop); void finalizeObjects(); }; enum SpewChannel { ISpewOps, /* ops: New constraints and types. */ ISpewResult, /* result: Final type sets. */ SPEW_COUNT };
--- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -197,48 +197,61 @@ TypeIdString(jsid id) * information is not collected and does not change. * * Pins inference results so that intermediate type information, TypeObjects * and JSScripts won't be collected during GC. Does additional sanity checking * that inference is not reentrant and that recompilations occur properly. */ struct AutoEnterTypeInference { - JSContext *cx; + FreeOp *freeOp; + JSCompartment *compartment; bool oldActiveAnalysis; bool oldActiveInference; AutoEnterTypeInference(JSContext *cx, bool compiling = false) - : cx(cx), oldActiveAnalysis(cx->compartment->activeAnalysis), - oldActiveInference(cx->compartment->activeInference) { JS_ASSERT_IF(!compiling, cx->compartment->types.inferenceEnabled); - cx->compartment->activeAnalysis = true; - cx->compartment->activeInference = true; + init(cx->runtime->defaultFreeOp(), cx->compartment); + } + + AutoEnterTypeInference(FreeOp *fop, JSCompartment *comp) + { + init(fop, comp); } ~AutoEnterTypeInference() { - cx->compartment->activeAnalysis = oldActiveAnalysis; - cx->compartment->activeInference = oldActiveInference; + compartment->activeAnalysis = oldActiveAnalysis; + compartment->activeInference = oldActiveInference; /* * If there are no more type inference activations on the stack, * process any triggered recompilations. Note that we should not be * invoking any scripted code while type inference is running. * :TODO: assert this. */ - if (!cx->compartment->activeInference) { - TypeCompartment *types = &cx->compartment->types; + if (!compartment->activeInference) { + TypeCompartment *types = &compartment->types; if (types->pendingNukeTypes) - types->nukeTypes(cx); + types->nukeTypes(freeOp); else if (types->pendingRecompiles) - types->processPendingRecompiles(cx); + types->processPendingRecompiles(freeOp); } } + + private: + void init(FreeOp *fop, JSCompartment *comp) { + freeOp = fop; + compartment = comp; + oldActiveAnalysis = compartment->activeAnalysis; + oldActiveInference = compartment->activeInference; + compartment->activeAnalysis = true; + compartment->activeInference = true; + } }; /* * Structure marking the currently compiled script, for constraints which can * trigger recompilation. */ struct AutoEnterCompilation {
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -853,17 +853,17 @@ class EvalScriptGuard : cx_(cx), str_(str), script_(NULL) { bucket_ = EvalCacheHash(cx, str); } ~EvalScriptGuard() { if (script_) { - js_CallDestroyScriptHook(cx_, script_); + CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_); script_->isActiveEval = false; script_->isCachedEval = true; script_->evalHashLink() = *bucket_; *bucket_ = script_; } } void lookupInEvalCache(StackFrame *caller, unsigned staticLevel,
--- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1617,11 +1617,14 @@ extern JSPrincipals * PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx); extern JSObject * NonNullObject(JSContext *cx, const Value &v); extern const char * InformalValueTypeName(const Value &v); +inline void +DestroyIdArray(FreeOp *fop, JSIdArray *ida); + } /* namespace js */ #endif /* jsobj_h___ */
--- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1749,9 +1749,15 @@ js_PurgeScopeChainHelper(JSContext *cx, inline bool js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id) { if (obj->isDelegate()) return js_PurgeScopeChainHelper(cx, obj, id); return true; } +inline void +js::DestroyIdArray(FreeOp *fop, JSIdArray *ida) +{ + fop->free_(ida); +} + #endif /* jsobjinlines_h___ */
--- a/js/src/jsprobes.cpp +++ b/js/src/jsprobes.cpp @@ -226,20 +226,20 @@ Probes::registerMJITCode(JSContext *cx, for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) (*p)->registerMJITCode(cx, jscr, outerFrame, inlineFrames, mainCodeAddress, mainCodeSize, stubCodeAddress, stubCodeSize); } void -Probes::discardMJITCode(JSContext *cx, mjit::JITScript *jscr, JSScript *script, void* address) +Probes::discardMJITCode(FreeOp *fop, mjit::JITScript *jscr, JSScript *script, void* address) { for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) - (*p)->discardMJITCode(cx, jscr, script, address); + (*p)->discardMJITCode(fop, jscr, script, address); } void Probes::registerICCode(JSContext *cx, mjit::JITScript *jscr, JSScript *script, jsbytecode* pc, void *start, size_t size) { for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
--- a/js/src/jsprobes.h +++ b/js/src/jsprobes.h @@ -259,17 +259,17 @@ public: mjit::JSActiveFrame **inlineFrames); virtual void registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr, mjit::JSActiveFrame *outerFrame, mjit::JSActiveFrame **inlineFrames, void *mainCodeAddress, size_t mainCodeSize, void *stubCodeAddress, size_t stubCodeSize) = 0; - virtual void discardMJITCode(JSContext *cx, mjit::JITScript *jscr, JSScript *script, + virtual void discardMJITCode(FreeOp *fop, mjit::JITScript *jscr, JSScript *script, void* address) = 0; virtual void registerICCode(JSContext *cx, js::mjit::JITScript *jscr, JSScript *script, jsbytecode* pc, void *start, size_t size) = 0; #endif virtual void discardExecutableRegion(void *start, size_t size) = 0; @@ -311,17 +311,17 @@ registerMJITCode(JSContext *cx, js::mjit mjit::JSActiveFrame **inlineFrames, void *mainCodeAddress, size_t mainCodeSize, void *stubCodeAddress, size_t stubCodeSize); /* * Method JIT code is about to be discarded */ void -discardMJITCode(JSContext *cx, mjit::JITScript *jscr, JSScript *script, void* address); +discardMJITCode(FreeOp *fop, mjit::JITScript *jscr, JSScript *script, void* address); /* * IC code has been allocated within the given JITScript */ void registerICCode(JSContext *cx, mjit::JITScript *jscr, JSScript *script, jsbytecode* pc, void *start, size_t size);
--- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -383,17 +383,17 @@ typedef void const char *filename, /* URL of script */ unsigned lineno, /* first line */ JSScript *script, JSFunction *fun, void *callerdata); /* called just before script destruction */ typedef void -(* JSDestroyScriptHook)(JSContext *cx, +(* JSDestroyScriptHook)(JSFreeOp *fop, JSScript *script, void *callerdata); typedef void (* JSSourceHandler)(const char *filename, unsigned lineno, const jschar *str, size_t length, void **listenerTSData, void *closure); /*
--- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -813,20 +813,20 @@ JSScript::initScriptCounts(JSContext *cx InterpreterFrames *frames; for (frames = cx->runtime->interpreterFrames; frames; frames = frames->older) frames->enableInterruptsIfRunning(this); return true; } void -JSScript::destroyScriptCounts(JSContext *cx) +JSScript::destroyScriptCounts(FreeOp *fop) { if (scriptCounts) { - cx->free_(scriptCounts.pcCountsVector); + fop->free_(scriptCounts.pcCountsVector); scriptCounts.pcCountsVector = NULL; } } /* * Shared script filename management. */ @@ -1375,57 +1375,57 @@ js_CallNewScriptHook(JSContext *cx, JSSc AutoKeepAtoms keep(cx->runtime); hook(cx, script->filename, script->lineno, script, fun, cx->runtime->debugHooks.newScriptHookData); } script->callDestroyHook = true; } void -js_CallDestroyScriptHook(JSContext *cx, JSScript *script) +js::CallDestroyScriptHook(FreeOp *fop, JSScript *script) { if (!script->callDestroyHook) return; - if (JSDestroyScriptHook hook = cx->runtime->debugHooks.destroyScriptHook) - hook(cx, script, cx->runtime->debugHooks.destroyScriptHookData); + if (JSDestroyScriptHook hook = fop->runtime()->debugHooks.destroyScriptHook) + hook(fop, script, fop->runtime()->debugHooks.destroyScriptHookData); script->callDestroyHook = false; - JS_ClearScriptTraps(cx, script); + script->clearTraps(fop); } void JSScript::finalize(FreeOp *fop) { - js_CallDestroyScriptHook(fop->context, this); + CallDestroyScriptHook(fop, this); JS_ASSERT_IF(principals, originPrincipals); if (principals) JS_DropPrincipals(fop->runtime(), principals); if (originPrincipals) JS_DropPrincipals(fop->runtime(), originPrincipals); if (types) types->destroy(); #ifdef JS_METHODJIT - mjit::ReleaseScriptCode(fop->context, this); + mjit::ReleaseScriptCode(fop, this); #endif - destroyScriptCounts(fop->context); + destroyScriptCounts(fop); if (sourceMap) fop->free_(sourceMap); 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->context, NULL, NULL); + site->clearTrap(fop, NULL, NULL); JS_ASSERT(getBreakpointSite(pc) == NULL); } } fop->free_(debug); } JS_POISON(data, 0xdb, computedSizeOfData()); fop->free_(data); @@ -1680,42 +1680,38 @@ JSScript::ensureHasDebug(JSContext *cx) */ InterpreterFrames *frames; for (frames = cx->runtime->interpreterFrames; frames; frames = frames->older) frames->enableInterruptsIfRunning(this); return true; } -bool -JSScript::recompileForStepMode(JSContext *cx) +void +JSScript::recompileForStepMode(FreeOp *fop) { #ifdef JS_METHODJIT if (jitNormal || jitCtor) { - mjit::Recompiler::clearStackReferences(cx, this); - mjit::ReleaseScriptCode(cx, this); + mjit::Recompiler::clearStackReferences(fop, this); + mjit::ReleaseScriptCode(fop, this); } #endif - return true; } bool JSScript::tryNewStepMode(JSContext *cx, uint32_t newValue) { JS_ASSERT(debug); uint32_t prior = debug->stepMode; debug->stepMode = newValue; if (!prior != !newValue) { /* Step mode has been enabled or disabled. Alert the methodjit. */ - if (!recompileForStepMode(cx)) { - debug->stepMode = prior; - return false; - } + recompileForStepMode(cx->runtime->defaultFreeOp()); if (!stepModeEnabled() && !debug->numSites) { cx->free_(debug); debug = NULL; } } return true; @@ -1770,28 +1766,28 @@ JSScript::getOrCreateBreakpointSite(JSCo JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal); else site->scriptGlobal = scriptGlobal; return site; } void -JSScript::destroyBreakpointSite(JSRuntime *rt, jsbytecode *pc) +JSScript::destroyBreakpointSite(FreeOp *fop, jsbytecode *pc) { JS_ASSERT(unsigned(pc - code) < length); BreakpointSite *&site = debug->breakpoints[pc - code]; JS_ASSERT(site); - rt->delete_(site); + fop->delete_(site); site = NULL; if (--debug->numSites == 0 && !stepModeEnabled()) { - rt->free_(debug); + fop->free_(debug); debug = NULL; } } void JSScript::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler) { if (!hasAnyBreakpointsOrStepMode()) @@ -1800,33 +1796,33 @@ JSScript::clearBreakpointsIn(JSContext * jsbytecode *end = code + length; for (jsbytecode *pc = code; pc < end; pc++) { BreakpointSite *site = getBreakpointSite(pc); if (site) { Breakpoint *nextbp; for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) { nextbp = bp->nextInSite(); if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler)) - bp->destroy(cx); + bp->destroy(cx->runtime->defaultFreeOp()); } } } } void -JSScript::clearTraps(JSContext *cx) +JSScript::clearTraps(FreeOp *fop) { if (!hasAnyBreakpointsOrStepMode()) return; jsbytecode *end = code + length; for (jsbytecode *pc = code; pc < end; pc++) { BreakpointSite *site = getBreakpointSite(pc); if (site) - site->clearTrap(cx); + site->clearTrap(fop); } } void JSScript::markChildren(JSTracer *trc) { JS_ASSERT_IF(trc->runtime->gcStrictCompartmentChecking, compartment()->isCollecting()); @@ -1912,18 +1908,18 @@ JSScript::applySpeculationFailed(JSConte needsArgsObj_ = false; return false; } } } #ifdef JS_METHODJIT if (hasJITCode()) { - mjit::Recompiler::clearStackReferences(cx, this); - mjit::ReleaseScriptCode(cx, this); + mjit::Recompiler::clearStackReferences(cx->runtime->defaultFreeOp(), this); + mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), this); } #endif if (hasAnalysis() && analysis()->ranInference()) { types::AutoEnterTypeInference enter(cx); for (unsigned off = 0; off < length; off += GetBytecodeLength(code + off)) { if (code[off] == JSOP_ARGUMENTS) { types::TypeSet *set = analysis()->pushedTypes(off, 0);
--- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -630,17 +630,17 @@ struct JSScript : public js::gc::Cell #endif js::PCCounts getPCCounts(jsbytecode *pc) { JS_ASSERT(size_t(pc - code) < length); return scriptCounts.pcCountsVector[pc - code]; } bool initScriptCounts(JSContext *cx); - void destroyScriptCounts(JSContext *cx); + void destroyScriptCounts(js::FreeOp *fop); jsbytecode *main() { return code + mainOffset; } /* * computedSizeOfData() is the in-use size of all the data sections. * sizeOfData() is the size of the block allocated to hold all the data sections @@ -746,20 +746,20 @@ struct JSScript : public js::gc::Cell uint32_t getClosedVar(uint32_t index) { js::ClosedSlotArray *arr = closedVars(); JS_ASSERT(index < arr->length); return arr->vector[index]; } private: /* - * Attempt to recompile with or without single-stepping support, as directed + * Recompile with or without single-stepping support, as directed * by stepModeEnabled(). */ - bool recompileForStepMode(JSContext *cx); + void recompileForStepMode(js::FreeOp *fop); /* Attempt to change this->stepMode to |newValue|. */ bool tryNewStepMode(JSContext *cx, uint32_t newValue); bool ensureHasDebug(JSContext *cx); public: bool hasBreakpointsAt(jsbytecode *pc) { return !!getBreakpointSite(pc); } @@ -769,20 +769,20 @@ struct JSScript : public js::gc::Cell { JS_ASSERT(size_t(pc - code) < length); return debug ? debug->breakpoints[pc - code] : NULL; } js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc, js::GlobalObject *scriptGlobal); - void destroyBreakpointSite(JSRuntime *rt, jsbytecode *pc); + void destroyBreakpointSite(js::FreeOp *fop, jsbytecode *pc); void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler); - void clearTraps(JSContext *cx); + void clearTraps(js::FreeOp *fop); void markTrapClosures(JSTracer *trc); /* * Set or clear the single-step flag. If the flag is set or the count * (adjusted by changeStepModeCount) is non-zero, then the script is in * single-step mode. (JSD uses an on/off-style interface; Debugger uses a * count-style interface.) @@ -831,20 +831,20 @@ StackDepth(JSScript *script) * New-script-hook calling is factored from NewScriptFromEmitter so that it * and callers of XDRScript can share this code. In the case of callers * of XDRScript, the hook should be invoked only after successful decode * of any owning function (the fun parameter) or script object (null fun). */ extern JS_FRIEND_API(void) js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun); +namespace js { + extern void -js_CallDestroyScriptHook(JSContext *cx, JSScript *script); - -namespace js { +CallDestroyScriptHook(FreeOp *fop, JSScript *script); extern const char * SaveScriptFilename(JSContext *cx, const char *filename); extern void MarkScriptFilename(const char *filename); extern void
--- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -921,25 +921,25 @@ JSXMLArray<T>::trim() if (capacity & JSXML_PRESET_CAPACITY) return; if (length < capacity) setCapacity(NULL, length); } template<class T> void -JSXMLArray<T>::finish(JSContext *cx) -{ - if (!cx->runtime->gcRunning) { +JSXMLArray<T>::finish(FreeOp *fop) +{ + if (!fop->runtime()->gcRunning) { /* We need to clear these to trigger a write barrier. */ for (uint32_t i = 0; i < length; i++) vector[i].~HeapPtr<T>(); } - cx->free_(vector); + fop->free_(vector); while (JSXMLArrayCursor<T> *cursor = cursors) cursor->disconnect(); #ifdef DEBUG memset(this, 0xd5, sizeof *this); #endif } @@ -1173,20 +1173,20 @@ HAS_NS_AFTER_XML(const jschar *chars) static const char xml_namespace_str[] = "http://www.w3.org/XML/1998/namespace"; static const char xmlns_namespace_str[] = "http://www.w3.org/2000/xmlns/"; void JSXML::finalize(FreeOp *fop) { if (JSXML_HAS_KIDS(this)) { - xml_kids.finish(fop->context); + xml_kids.finish(fop); if (xml_class == JSXML_CLASS_ELEMENT) { - xml_namespaces.finish(fop->context); - xml_attrs.finish(fop->context); + xml_namespaces.finish(fop); + xml_attrs.finish(fop); } } #ifdef DEBUG_notme JS_REMOVE_LINK(&links); #endif } static JSObject * @@ -4480,17 +4480,17 @@ PutProperty(JSContext *cx, JSObject *obj } /* 14. */ if (primitiveAssign) { JSXMLArrayCursor<JSXML> cursor(&xml->xml_kids); cursor.index = matchIndex; kid = cursor.getCurrent(); if (JSXML_HAS_KIDS(kid)) { - kid->xml_kids.finish(cx); + kid->xml_kids.finish(cx->runtime->defaultFreeOp()); kid->xml_kids.init(); ok = kid->xml_kids.setCapacity(cx, 1); } /* 14(b-c). */ /* XXXbe Erratum? redundant w.r.t. 7(b-c) else clause above */ if (ok) { ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp);
--- a/js/src/jsxml.h +++ b/js/src/jsxml.h @@ -67,17 +67,17 @@ struct JSXMLArray JSXMLArrayCursor<T> *cursors; void init() { length = capacity = 0; vector = NULL; cursors = NULL; } - void finish(JSContext *cx); + void finish(js::FreeOp *fop); bool setCapacity(JSContext *cx, uint32_t capacity); void trim(); }; template<class T> struct JSXMLArrayCursor {
--- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -1308,45 +1308,45 @@ JITChunk::~JITChunk() callICs_[i].releasePools(); if (callICs_[i].fastGuardedObject) callICs_[i].purgeGuardedObject(); } #endif } void -JITScript::destroy(JSContext *cx) +JITScript::destroy(FreeOp *fop) { for (unsigned i = 0; i < nchunks; i++) - destroyChunk(cx, i); + destroyChunk(fop, i); if (shimPool) shimPool->release(); } void -JITScript::destroyChunk(JSContext *cx, unsigned chunkIndex, bool resetUses) +JITScript::destroyChunk(FreeOp *fop, unsigned chunkIndex, bool resetUses) { ChunkDescriptor &desc = chunkDescriptor(chunkIndex); if (desc.chunk) { - Probes::discardMJITCode(cx, this, script, desc.chunk->code.m_code.executableAddress()); - cx->delete_(desc.chunk); + Probes::discardMJITCode(fop, this, script, desc.chunk->code.m_code.executableAddress()); + fop->delete_(desc.chunk); desc.chunk = NULL; CrossChunkEdge *edges = this->edges(); for (unsigned i = 0; i < nedges; i++) { CrossChunkEdge &edge = edges[i]; if (edge.source >= desc.begin && edge.source < desc.end) { edge.sourceJump1 = edge.sourceJump2 = NULL; #ifdef JS_CPU_X64 edge.sourceTrampoline = NULL; #endif if (edge.jumpTableEntries) { - cx->delete_(edge.jumpTableEntries); + fop->delete_(edge.jumpTableEntries); edge.jumpTableEntries = NULL; } } else if (edge.target >= desc.begin && edge.target < desc.end) { edge.targetLabel = NULL; patchEdge(edge, edge.shimLabel); } } } @@ -1433,28 +1433,28 @@ mjit::JITChunk::computedSizeOfIncludingT /* Please keep in sync with Compiler::finishThisUp! */ size_t mjit::JITChunk::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) { return mallocSizeOf(this); } void -mjit::ReleaseScriptCode(JSContext *cx, JSScript *script, bool construct) +mjit::ReleaseScriptCode(FreeOp *fop, JSScript *script, bool construct) { // NB: The recompiler may call ReleaseScriptCode, in which case it // will get called again when the script is destroyed, so we // must protect against calling ReleaseScriptCode twice. JITScript **pjit = construct ? &script->jitCtor : &script->jitNormal; void **parity = construct ? &script->jitArityCheckCtor : &script->jitArityCheckNormal; if (*pjit) { - (*pjit)->destroy(cx); - cx->free_(*pjit); + (*pjit)->destroy(fop); + fop->free_(*pjit); *pjit = NULL; *parity = NULL; } } #ifdef JS_METHODJIT_PROFILE_STUBS void JS_FASTCALL mjit::ProfileStubCall(VMFrame &f)
--- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -861,18 +861,18 @@ struct JITScript /* Patch any compiled sources in edge to jump to label. */ void patchEdge(const CrossChunkEdge &edge, void *label); jsbytecode *nativeToPC(void *returnAddress, CallSite **pinline); size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf); - void destroy(JSContext *cx); - void destroyChunk(JSContext *cx, unsigned chunkIndex, bool resetUses = true); + void destroy(FreeOp *fop); + void destroyChunk(FreeOp *fop, unsigned chunkIndex, bool resetUses = true); }; /* * Execute the given mjit code. This is a low-level call and callers must * provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT. */ JaegerStatus EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit, bool partial); @@ -902,25 +902,25 @@ enum CompileRequest CompileRequest_JIT }; CompileStatus CanMethodJIT(JSContext *cx, JSScript *script, jsbytecode *pc, bool construct, CompileRequest request); void -ReleaseScriptCode(JSContext *cx, JSScript *script, bool construct); +ReleaseScriptCode(FreeOp *fop, JSScript *script, bool construct); inline void -ReleaseScriptCode(JSContext *cx, JSScript *script) +ReleaseScriptCode(FreeOp *fop, JSScript *script) { if (script->jitCtor) - mjit::ReleaseScriptCode(cx, script, true); + mjit::ReleaseScriptCode(fop, script, true); if (script->jitNormal) - mjit::ReleaseScriptCode(cx, script, false); + mjit::ReleaseScriptCode(fop, script, false); } // Expand all stack frames inlined by the JIT within a compartment. void ExpandInlineFrames(JSCompartment *compartment); // Return all VMFrames in a compartment to the interpreter. This must be // followed by destroying all JIT code in the compartment.
--- a/js/src/methodjit/Retcon.cpp +++ b/js/src/methodjit/Retcon.cpp @@ -396,38 +396,39 @@ ClearAllFrames(JSCompartment *compartmen * - For VMFrames with a stub call return address in the original script, * redirect to the interpoline. * * - For VMFrames whose entryncode address (the value of entryfp->ncode before * being clobbered with JaegerTrampolineReturn) is in the original script, * redirect that entryncode to the interpoline. */ void -Recompiler::clearStackReferences(JSContext *cx, JSScript *script) +Recompiler::clearStackReferences(FreeOp *fop, JSScript *script) { JS_ASSERT(script->hasJITCode()); JaegerSpew(JSpew_Recompile, "recompiling script (file \"%s\") (line \"%d\") (length \"%d\")\n", script->filename, script->lineno, script->length); - types::AutoEnterTypeInference enter(cx, true); + JSCompartment *comp = script->compartment(); + types::AutoEnterTypeInference enter(fop, comp); /* * The strategy for this goes as follows: * * 1) Scan the stack, looking at all return addresses that could go into JIT * code. * 2) If an address corresponds to a call site registered by |callSite| during * the last compilation, patch it to go to the interpoline. * 3) Purge the old compiled state. */ // Find all JIT'd stack frames to account for return addresses that will // need to be patched after recompilation. - for (VMFrame *f = script->compartment()->jaegerCompartment()->activeFrame(); + for (VMFrame *f = comp->jaegerCompartment()->activeFrame(); f != NULL; f = f->previous) { // Scan all frames owned by this VMFrame. StackFrame *end = f->entryfp->prev(); StackFrame *next = NULL; for (StackFrame *fp = f->fp(); fp != end; fp = fp->prev()) { if (fp->script() != script) { @@ -445,52 +446,52 @@ Recompiler::clearStackReferences(JSConte JITChunk *chunk = fp->jit()->findCodeChunk(*addr); patchCall(chunk, fp, addr); } } next = fp; } - patchFrame(cx->compartment, f, script); + patchFrame(comp, f, script); } - cx->compartment->types.recompilations++; + comp->types.recompilations++; } void -Recompiler::clearStackReferencesAndChunk(JSContext *cx, JSScript *script, +Recompiler::clearStackReferencesAndChunk(FreeOp *fop, JSScript *script, JITScript *jit, size_t chunkIndex, bool resetUses) { - Recompiler::clearStackReferences(cx, script); + Recompiler::clearStackReferences(fop, script); bool releaseChunk = true; if (jit->nchunks > 1) { // If we are in the middle of a native call from a native or getter IC, // we need to make sure all JIT code for the script is purged, as // otherwise we will have orphaned the native stub but pointers to it // still exist in the containing chunk. - for (VMFrame *f = cx->compartment->jaegerCompartment()->activeFrame(); + for (VMFrame *f = script->compartment()->jaegerCompartment()->activeFrame(); f != NULL; f = f->previous) { if (f->fp()->script() == script) { JS_ASSERT(f->stubRejoin != REJOIN_NATIVE && f->stubRejoin != REJOIN_NATIVE_LOWERED && f->stubRejoin != REJOIN_NATIVE_GETTER); if (f->stubRejoin == REJOIN_NATIVE_PATCHED) { - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(fop, script); releaseChunk = false; break; } } } } if (releaseChunk) - jit->destroyChunk(cx, chunkIndex, resetUses); + jit->destroyChunk(fop, chunkIndex, resetUses); } } /* namespace mjit */ } /* namespace js */ #endif /* JS_METHODJIT */
--- a/js/src/methodjit/Retcon.h +++ b/js/src/methodjit/Retcon.h @@ -63,22 +63,22 @@ namespace mjit { * JITed code, fixing up the stack in the process. */ class Recompiler { public: // Clear all uses of compiled code for script on the stack. This must be // followed by destroying all JIT code for the script. static void - clearStackReferences(JSContext *cx, JSScript *script); + clearStackReferences(FreeOp *fop, JSScript *script); // Clear all uses of compiled code for script on the stack, along with // the specified compiled chunk. static void - clearStackReferencesAndChunk(JSContext *cx, JSScript *script, + clearStackReferencesAndChunk(FreeOp *fop, JSScript *script, JITScript *jit, size_t chunkIndex, bool resetUses = true); static void expandInlineFrames(JSCompartment *compartment, StackFrame *fp, mjit::CallSite *inlined, StackFrame *next, VMFrame *f); static void patchFrame(JSCompartment *compartment, VMFrame *f, JSScript *script);
--- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -813,18 +813,18 @@ stubs::Interrupt(VMFrame &f, jsbytecode if (!js_HandleExecutionInterrupt(f.cx)) THROW(); } void JS_FASTCALL stubs::RecompileForInline(VMFrame &f) { ExpandInlineFrames(f.cx->compartment); - Recompiler::clearStackReferencesAndChunk(f.cx, f.script(), f.jit(), f.chunkIndex(), - /* resetUses = */ false); + Recompiler::clearStackReferencesAndChunk(f.cx->runtime->defaultFreeOp(), f.script(), f.jit(), + f.chunkIndex(), /* resetUses = */ false); } void JS_FASTCALL stubs::Trap(VMFrame &f, uint32_t trapTypes) { Value rval; /* @@ -1665,18 +1665,18 @@ stubs::InvariantFailure(VMFrame &f, void /* Recompile the outermost script, and don't hoist any bounds checks. */ JSScript *script = f.fp()->script(); JS_ASSERT(!script->failedBoundsCheck); script->failedBoundsCheck = true; ExpandInlineFrames(f.cx->compartment); - mjit::Recompiler::clearStackReferences(f.cx, script); - mjit::ReleaseScriptCode(f.cx, script); + mjit::Recompiler::clearStackReferences(f.cx->runtime->defaultFreeOp(), script); + mjit::ReleaseScriptCode(f.cx->runtime->defaultFreeOp(), script); /* Return the same value (if any) as the call triggering the invariant failure. */ return rval; } void JS_FASTCALL stubs::Exception(VMFrame &f) {
--- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -278,90 +278,77 @@ ScriptGlobal(JSContext *cx, JSScript *sc for (AllFramesIter i(cx->stack.space()); ; ++i) { JS_ASSERT(!i.done()); if (i.fp()->maybeScript() == script) return &i.fp()->scopeChain().global(); } JS_NOT_REACHED("ScriptGlobal: live non-held script not on stack"); } -bool -BreakpointSite::recompile(JSContext *cx, bool forTrap) +void +BreakpointSite::recompile(FreeOp *fop) { #ifdef JS_METHODJIT if (script->hasJITCode()) { - Maybe<AutoCompartment> ac; - if (!forTrap) { - ac.construct(cx, ScriptGlobal(cx, script, scriptGlobal)); - if (!ac.ref().enter()) - return false; - } - mjit::Recompiler::clearStackReferences(cx, script); - mjit::ReleaseScriptCode(cx, script); + mjit::Recompiler::clearStackReferences(fop, script); + mjit::ReleaseScriptCode(fop, script); } #endif - return true; -} - -bool -BreakpointSite::inc(JSContext *cx) -{ - if (enabledCount == 0 && !trapHandler) { - if (!recompile(cx, false)) - return false; - } - enabledCount++; - return true; } void -BreakpointSite::dec(JSContext *cx) +BreakpointSite::inc(FreeOp *fop) +{ + if (enabledCount == 0 && !trapHandler) + recompile(fop); + enabledCount++; +} + +void +BreakpointSite::dec(FreeOp *fop) { JS_ASSERT(enabledCount > 0); enabledCount--; if (enabledCount == 0 && !trapHandler) - recompile(cx, false); /* ignore failure */ -} - -bool -BreakpointSite::setTrap(JSContext *cx, JSTrapHandler handler, const Value &closure) -{ - if (enabledCount == 0) { - if (!recompile(cx, true)) - return false; - } - trapHandler = handler; - trapClosure = closure; - return true; + recompile(fop); } void -BreakpointSite::clearTrap(JSContext *cx, JSTrapHandler *handlerp, Value *closurep) +BreakpointSite::setTrap(FreeOp *fop, JSTrapHandler handler, const Value &closure) +{ + if (enabledCount == 0) + recompile(fop); + trapHandler = handler; + trapClosure = closure; +} + +void +BreakpointSite::clearTrap(FreeOp *fop, JSTrapHandler *handlerp, Value *closurep) { if (handlerp) *handlerp = trapHandler; if (closurep) *closurep = trapClosure; trapHandler = NULL; trapClosure = UndefinedValue(); if (enabledCount == 0) { - if (!cx->runtime->gcRunning) { + if (!fop->runtime()->gcRunning) { /* If the GC is running then the script is being destroyed. */ - recompile(cx, true); /* ignore failure */ + recompile(fop); } - destroyIfEmpty(cx->runtime); + destroyIfEmpty(fop); } } void -BreakpointSite::destroyIfEmpty(JSRuntime *rt) +BreakpointSite::destroyIfEmpty(FreeOp *fop) { if (JS_CLIST_IS_EMPTY(&breakpoints) && !trapHandler) - script->destroyBreakpointSite(rt, pc); + script->destroyBreakpointSite(fop, pc); } Breakpoint * BreakpointSite::firstBreakpoint() const { if (JS_CLIST_IS_EMPTY(&breakpoints)) return NULL; return Breakpoint::fromSiteLinks(JS_NEXT_LINK(&breakpoints)); @@ -391,25 +378,24 @@ Breakpoint::fromDebuggerLinks(JSCList *l Breakpoint * Breakpoint::fromSiteLinks(JSCList *links) { return (Breakpoint *) ((unsigned char *) links - offsetof(Breakpoint, siteLinks)); } void -Breakpoint::destroy(JSContext *cx) +Breakpoint::destroy(FreeOp *fop) { if (debugger->enabled) - site->dec(cx); + site->dec(fop); JS_REMOVE_LINK(&debuggerLinks); JS_REMOVE_LINK(&siteLinks); - JSRuntime *rt = cx->runtime; - site->destroyIfEmpty(rt); - rt->delete_(this); + site->destroyIfEmpty(fop); + fop->delete_(this); } Breakpoint * Breakpoint::nextInDebugger() { JSCList *link = JS_NEXT_LINK(&debuggerLinks); return (link == &debugger->breakpoints) ? NULL : fromDebuggerLinks(link); } @@ -1471,40 +1457,40 @@ Debugger::sweepAll(FreeOp *fop) if (IsAboutToBeFinalized(dbg->object)) { /* * dbg is being GC'd. Detach it from its debuggees. The debuggee * might be GC'd too. Since detaching requires access to both * objects, this must be done before finalize time. */ for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront()) - dbg->removeDebuggeeGlobal(fop->context, e.front(), NULL, &e); + dbg->removeDebuggeeGlobal(fop, e.front(), NULL, &e); } } for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) { /* For each debuggee being GC'd, detach it from all its debuggers. */ GlobalObjectSet &debuggees = (*c)->getDebuggees(); for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) { GlobalObject *global = e.front(); if (IsAboutToBeFinalized(global)) - detachAllDebuggersFromGlobal(fop->context, global, &e); + detachAllDebuggersFromGlobal(fop, global, &e); } } } void -Debugger::detachAllDebuggersFromGlobal(JSContext *cx, GlobalObject *global, +Debugger::detachAllDebuggersFromGlobal(FreeOp *fop, GlobalObject *global, GlobalObjectSet::Enum *compartmentEnum) { const GlobalObject::DebuggerVector *debuggers = global->getDebuggers(); JS_ASSERT(!debuggers->empty()); while (!debuggers->empty()) - debuggers->back()->removeDebuggeeGlobal(cx, global, compartmentEnum, NULL); + debuggers->back()->removeDebuggeeGlobal(fop, global, compartmentEnum, NULL); } void Debugger::finalize(FreeOp *fop, JSObject *obj) { Debugger *dbg = fromJSObject(obj); if (!dbg) return; @@ -1570,33 +1556,20 @@ JSBool Debugger::setEnabled(JSContext *cx, unsigned argc, Value *vp) { REQUIRE_ARGC("Debugger.set enabled", 1); THIS_DEBUGGER(cx, argc, vp, "set enabled", args, dbg); bool enabled = js_ValueToBoolean(args[0]); if (enabled != dbg->enabled) { for (Breakpoint *bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) { - if (enabled) { - if (!bp->site->inc(cx)) { - /* - * Roll back the changes on error to keep the - * BreakpointSite::enabledCount counters correct. - */ - for (Breakpoint *bp2 = dbg->firstBreakpoint(); - bp2 != bp; - bp2 = bp2->nextInDebugger()) - { - bp->site->dec(cx); - } - return false; - } - } else { - bp->site->dec(cx); - } + if (enabled) + bp->site->inc(cx->runtime->defaultFreeOp()); + else + bp->site->dec(cx->runtime->defaultFreeOp()); } } dbg->enabled = enabled; args.rval().setUndefined(); return true; } @@ -1751,17 +1724,17 @@ Debugger::removeDebuggee(JSContext *cx, { REQUIRE_ARGC("Debugger.removeDebuggee", 1); THIS_DEBUGGER(cx, argc, vp, "removeDebuggee", args, dbg); JSObject *referent = dbg->unwrapDebuggeeArgument(cx, args[0]); if (!referent) return false; GlobalObject *global = &referent->global(); if (dbg->debuggees.has(global)) - dbg->removeDebuggeeGlobal(cx, global, NULL, NULL); + dbg->removeDebuggeeGlobal(cx->runtime->defaultFreeOp(), global, NULL, NULL); args.rval().setUndefined(); return true; } JSBool Debugger::hasDebuggee(JSContext *cx, unsigned argc, Value *vp) { REQUIRE_ARGC("Debugger.hasDebuggee", 1); @@ -1941,17 +1914,17 @@ Debugger::addDebuggeeGlobal(JSContext *c } JS_ASSERT(v->back() == this); v->popBack(); } return false; } void -Debugger::removeDebuggeeGlobal(JSContext *cx, GlobalObject *global, +Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global, GlobalObjectSet::Enum *compartmentEnum, GlobalObjectSet::Enum *debugEnum) { /* * Each debuggee is in two HashSets: one for its compartment and one for * its debugger (this). The caller might be enumerating either set; if so, * use HashSet::Enum::removeFront rather than HashSet::remove below, to * avoid invalidating the live enumerator. @@ -1987,17 +1960,17 @@ Debugger::removeDebuggeeGlobal(JSContext JS_ASSERT(p != v->end()); /* * The relation must be removed from up to three places: *v and debuggees * for sure, and possibly the compartment's debuggee set. */ v->erase(p); if (v->empty()) - global->compartment()->removeDebuggee(cx, global, compartmentEnum); + global->compartment()->removeDebuggee(fop, global, compartmentEnum); if (debugEnum) debugEnum->removeFront(); else debuggees.remove(global); } /* A set of JSCompartment pointers. */ typedef HashSet<JSCompartment *, DefaultHasher<JSCompartment *>, RuntimeAllocPolicy> CompartmentSet; @@ -2603,24 +2576,23 @@ DebuggerScript_setBreakpoint(JSContext * JSObject *handler = NonNullObject(cx, args[1]); if (!handler) return false; jsbytecode *pc = script->code + offset; BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, scriptGlobal); if (!site) return false; - if (site->inc(cx)) { - if (cx->runtime->new_<Breakpoint>(dbg, site, handler)) { - args.rval().setUndefined(); - return true; - } - site->dec(cx); + site->inc(cx->runtime->defaultFreeOp()); + if (cx->runtime->new_<Breakpoint>(dbg, site, handler)) { + args.rval().setUndefined(); + return true; } - site->destroyIfEmpty(cx->runtime); + site->dec(cx->runtime->defaultFreeOp()); + site->destroyIfEmpty(cx->runtime->defaultFreeOp()); return false; } static JSBool DebuggerScript_getBreakpoints(JSContext *cx, unsigned argc, Value *vp) { THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getBreakpoints", args, obj, script); Debugger *dbg = Debugger::fromChildJSObject(obj);
--- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -117,17 +117,17 @@ class Debugger { ObjectWeakMap objects; /* The map from debuggee Envs to Debugger.Environment instances. */ ObjectWeakMap environments; class FrameRange; bool addDebuggeeGlobal(JSContext *cx, GlobalObject *obj); - void removeDebuggeeGlobal(JSContext *cx, GlobalObject *global, + void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global, GlobalObjectSet::Enum *compartmentEnum, GlobalObjectSet::Enum *debugEnum); /* * Cope with an error or exception in a debugger hook. * * If callHook is true, then call the uncaughtExceptionHook, if any. If, in * addition, vp is non-null, then parse the value returned by @@ -259,17 +259,17 @@ class Debugger { * * Debugger::markAllIteratively handles the last case. If it finds any * Debugger objects that are definitely live but not yet marked, it marks * them and returns true. If not, it returns false. */ static void markCrossCompartmentDebuggerObjectReferents(JSTracer *tracer); static bool markAllIteratively(GCMarker *trc); static void sweepAll(FreeOp *fop); - static void detachAllDebuggersFromGlobal(JSContext *cx, GlobalObject *global, + static void detachAllDebuggersFromGlobal(FreeOp *fop, GlobalObject *global, GlobalObjectSet::Enum *compartmentEnum); static inline JSTrapStatus onEnterFrame(JSContext *cx, Value *vp); static inline bool onLeaveFrame(JSContext *cx, bool ok); static inline JSTrapStatus onDebuggerStatement(JSContext *cx, Value *vp); static inline JSTrapStatus onExceptionUnwind(JSContext *cx, Value *vp); static inline void onNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal); @@ -394,30 +394,30 @@ class BreakpointSite { */ GlobalObject *scriptGlobal; JSCList breakpoints; /* cyclic list of all js::Breakpoints at this instruction */ size_t enabledCount; /* number of breakpoints in the list that are enabled */ JSTrapHandler trapHandler; /* jsdbgapi trap state */ HeapValue trapClosure; - bool recompile(JSContext *cx, bool forTrap); + void recompile(FreeOp *fop); public: BreakpointSite(JSScript *script, jsbytecode *pc); Breakpoint *firstBreakpoint() const; bool hasBreakpoint(Breakpoint *bp); bool hasTrap() const { return !!trapHandler; } GlobalObject *getScriptGlobal() const { return scriptGlobal; } - bool inc(JSContext *cx); - void dec(JSContext *cx); - bool setTrap(JSContext *cx, JSTrapHandler handler, const Value &closure); - void clearTrap(JSContext *cx, JSTrapHandler *handlerp = NULL, Value *closurep = NULL); - void destroyIfEmpty(JSRuntime *rt); + void inc(FreeOp *fop); + void dec(FreeOp *fop); + void setTrap(FreeOp *fop, JSTrapHandler handler, const Value &closure); + void clearTrap(FreeOp *fop, JSTrapHandler *handlerp = NULL, Value *closurep = NULL); + void destroyIfEmpty(FreeOp *fop); }; /* * Each Breakpoint is a member of two linked lists: its debugger's list and its * site's list. * * GC rules: * - script is live, breakpoint exists, and debugger is enabled @@ -444,17 +444,17 @@ class Breakpoint { js::HeapPtrObject handler; JSCList debuggerLinks; JSCList siteLinks; public: static Breakpoint *fromDebuggerLinks(JSCList *links); static Breakpoint *fromSiteLinks(JSCList *links); Breakpoint(Debugger *debugger, BreakpointSite *site, JSObject *handler); - void destroy(JSContext *cx); + void destroy(FreeOp *fop); Breakpoint *nextInDebugger(); Breakpoint *nextInSite(); const HeapPtrObject &getHandler() const { return handler; } HeapPtrObject &getHandlerRef() { return handler; } }; Debugger * Debugger::fromLinks(JSCList *links)
--- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -365,18 +365,18 @@ GlobalObject::clear(JSContext *cx) /* * Destroy compiled code for any scripts parented to this global. Call ICs * can directly call scripts which have associated JIT code, and do so * without checking whether the script's global has been cleared. */ for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->compileAndGo && script->hasJITCode() && script->hasClearedGlobal()) { - mjit::Recompiler::clearStackReferences(cx, script); - mjit::ReleaseScriptCode(cx, script); + mjit::Recompiler::clearStackReferences(cx->runtime->defaultFreeOp(), script); + mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), script); } } #endif } bool GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx) { @@ -502,15 +502,15 @@ GlobalObject::addDebugger(JSContext *cx, return false; #ifdef DEBUG for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) JS_ASSERT(*p != dbg); #endif if (debuggers->empty() && !compartment()->addDebuggee(cx, this)) return false; if (!debuggers->append(dbg)) { - compartment()->removeDebuggee(cx, this); + compartment()->removeDebuggee(cx->runtime->defaultFreeOp(), this); return false; } return true; } } // namespace js
--- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -246,42 +246,38 @@ ContextCallback(JSContext *cx, unsigned return true; } xpc::CompartmentPrivate::~CompartmentPrivate() { MOZ_COUNT_DTOR(xpc::CompartmentPrivate); } -static JSBool -CompartmentCallback(JSContext *cx, JSCompartment *compartment, unsigned op) +static void +CompartmentDestroyedCallback(JSFreeOp *fop, JSCompartment *compartment) { - JS_ASSERT(op == JSCOMPARTMENT_DESTROY); - XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance(); if (!self) - return true; + return; nsAutoPtr<xpc::CompartmentPrivate> priv(static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment))); if (!priv) - return true; + return; JS_SetCompartmentPrivate(compartment, nsnull); xpc::PtrAndPrincipalHashKey *key = priv->key; XPCCompartmentMap &map = self->GetCompartmentMap(); #ifdef DEBUG JSCompartment *current = NULL; NS_ASSERTION(map.Get(key, ¤t), "no compartment?"); NS_ASSERTION(current == compartment, "compartment mismatch"); #endif map.Remove(key); - - return true; } struct ObjectHolder : public JSDHashEntryHdr { void *holder; nsScriptObjectTracer* tracer; }; @@ -1996,17 +1992,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff); #ifdef MOZ_ASAN // ASan requires more stack space due to redzones JS_SetNativeStackQuota(mJSRuntime, 2 * 128 * sizeof(size_t) * 1024); #else JS_SetNativeStackQuota(mJSRuntime, 128 * sizeof(size_t) * 1024); #endif JS_SetContextCallback(mJSRuntime, ContextCallback); - JS_SetCompartmentCallback(mJSRuntime, CompartmentCallback); + JS_SetDestroyCompartmentCallback(mJSRuntime, CompartmentDestroyedCallback); JS_SetGCCallback(mJSRuntime, GCCallback); JS_SetFinalizeCallback(mJSRuntime, FinalizeCallback); JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this); JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this); JS_SetWrapObjectCallbacks(mJSRuntime, xpc::WrapperFactory::Rewrap, xpc::WrapperFactory::PrepareForWrapping); js::SetPreserveWrapperCallback(mJSRuntime, PreserveWrapper);