From 18841022a681a8ab9719fff47e05302c38e2d745 Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Tue, 20 Mar 2012 11:22:05 +0100 Subject: [PATCH] Bug 737365 - stop using the cx during finalization, part 3. This part removes the usage of JSContext* during the finalization and when sweeping the compartments. That required to change quite a few methods in type inference, jit and debugger implementation to take a FreeOp rather than JSContext pointer. In turn that also often required to replace cx->compartment usage with extracting the compartment from the passed objects or pass the compartment explicitly. On the plus side it allowed to remove fallible compartment enter code in methods that could be called during finalization. --- js/src/jsapi.cpp | 16 ++-- js/src/jsapi.h | 12 +-- js/src/jsatom.cpp | 2 +- js/src/jscntxt.h | 12 ++- js/src/jscntxtinlines.h | 2 +- js/src/jscompartment.cpp | 26 +++--- js/src/jscompartment.h | 6 +- js/src/jsdbgapi.cpp | 6 +- js/src/jsgc.cpp | 18 ++--- js/src/jsinfer.cpp | 68 ++++++++-------- js/src/jsinfer.h | 13 +-- js/src/jsinferinlines.h | 35 +++++--- js/src/jsobj.cpp | 2 +- js/src/jsobj.h | 3 + js/src/jsobjinlines.h | 6 ++ js/src/jsprobes.cpp | 4 +- js/src/jsprobes.h | 4 +- js/src/jsprvtd.h | 2 +- js/src/jsscript.cpp | 50 ++++++------ js/src/jsscript.h | 16 ++-- js/src/jsxml.cpp | 14 ++-- js/src/jsxml.h | 2 +- js/src/methodjit/MethodJIT.cpp | 18 ++--- js/src/methodjit/MethodJIT.h | 12 +-- js/src/methodjit/Retcon.cpp | 21 ++--- js/src/methodjit/Retcon.h | 4 +- js/src/methodjit/StubCalls.cpp | 8 +- js/src/vm/Debugger.cpp | 128 ++++++++++++------------------ js/src/vm/Debugger.h | 18 ++--- js/src/vm/GlobalObject.cpp | 6 +- js/xpconnect/src/XPCJSRuntime.cpp | 14 ++-- 31 files changed, 267 insertions(+), 281 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f34352404b9b..34eeff4f0726 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -707,7 +707,7 @@ JSRuntime::JSRuntime() nativeStackQuota(0), interpreterFrames(NULL), cxCallback(NULL), - compartmentCallback(NULL), + destroyCompartmentCallback(NULL), activityCallback(NULL), activityCallbackArg(NULL), #ifdef JS_THREADSAFE @@ -776,7 +776,7 @@ JSRuntime::JSRuntime() gcLock(NULL), gcHelperThread(thisFromCtor()), #endif - defaultFreeOp_(thisFromCtor(), false, false, NULL), + defaultFreeOp_(thisFromCtor(), false, false), debuggerMutations(0), securityCallbacks(const_cast(&NullSecurityCallbacks)), destroyPrincipals(NULL), @@ -1325,12 +1325,10 @@ JS_GetImplementationVersion(void) return "JavaScript-C 1.8.5+ 2011-04-16"; } -JS_PUBLIC_API(JSCompartmentCallback) -JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback) +JS_PUBLIC_API(void) +JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback) { - JSCompartmentCallback old = rt->compartmentCallback; - rt->compartmentCallback = callback; - return old; + rt->destroyCompartmentCallback = callback; } JS_PUBLIC_API(JSWrapObjectCallback) @@ -3052,7 +3050,7 @@ JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index) JS_PUBLIC_API(void) JS_DestroyIdArray(JSContext *cx, JSIdArray *ida) { - cx->free_(ida); + DestroyIdArray(cx->runtime->defaultFreeOp(), ida); } JS_PUBLIC_API(JSBool) @@ -4276,7 +4274,7 @@ prop_iter_finalize(FreeOp *fop, JSObject *obj) 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); } } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 01e514b7fe72..0c5be5efaa29 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1597,12 +1597,8 @@ typedef JSObject * 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 @@ -2681,8 +2677,8 @@ 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, diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index 4c815d2973f9..c1bd91d46c49 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -218,7 +218,7 @@ js_FinishAtomState(JSRuntime *rt) 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); } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index f8f9e578dc9a..18fcdcda7418 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -186,18 +186,16 @@ struct ConservativeGCData class FreeOp : public JSFreeOp { bool shouldFreeLater_; bool onBackgroundThread_; - public: - JSContext *context; + public: static FreeOp *get(JSFreeOp *fop) { return static_cast(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) { } @@ -290,8 +288,8 @@ struct JSRuntime : js::RuntimeFriendFields /* Context create/destroy callback. */ JSContextCallback cxCallback; - /* Compartment create/destroy callback. */ - JSCompartmentCallback compartmentCallback; + /* Compartment destroy callback. */ + JSDestroyCompartmentCallback destroyCompartmentCallback; js::ActivityCallback activityCallback; void *activityCallbackArg; diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 1226227eed7d..bb64fd827524 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -98,7 +98,7 @@ class AutoNamespaceArray : protected AutoGCRooter { } ~AutoNamespaceArray() { - array.finish(context); + array.finish(context->runtime->defaultFreeOp()); } uint32_t length() const { return array.length; } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 4c9247500126..817a226696f8 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -466,7 +466,7 @@ JSCompartment::markTypes(JSTracer *trc) } void -JSCompartment::discardJitCode(JSContext *cx) +JSCompartment::discardJitCode(FreeOp *fop) { /* * Kick all frames on the stack into the interpreter, and release all JIT @@ -477,7 +477,7 @@ JSCompartment::discardJitCode(JSContext *cx) for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(fop, script); /* * Use counts for scripts are reset on GC. After discarding code we @@ -521,7 +521,7 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes) { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE); - discardJitCode(fop->context); + discardJitCode(fop); } if (!activeAnalysis) { @@ -552,7 +552,7 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes) for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->types) { - types::TypeScript::Sweep(fop->context, script); + types::TypeScript::Sweep(fop, script); if (releaseTypes) { script->types->destroy(); @@ -565,7 +565,7 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes) { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TYPES); - types.sweep(fop->context); + types.sweep(fop); } { @@ -677,12 +677,12 @@ JSCompartment::setDebugModeFromC(JSContext *cx, bool b) 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) @@ -704,7 +704,7 @@ JSCompartment::updateForDebugMode(JSContext *cx) for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->debugMode != enabled) { - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(fop, script); script->clearAnalysis(); script->debugMode = enabled; } @@ -722,12 +722,12 @@ JSCompartment::addDebuggee(JSContext *cx, js::GlobalObject *global) } 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) { @@ -741,7 +741,7 @@ JSCompartment::removeDebuggee(JSContext *cx, if (debuggees.empty()) { debugModeBits &= ~DebugFromJS; if (wasEnabled && !debugMode()) - updateForDebugMode(cx); + updateForDebugMode(fop); } } @@ -761,7 +761,7 @@ JSCompartment::clearTraps(JSContext *cx) for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->hasAnyBreakpointsOrStepMode()) - script->clearTraps(cx); + script->clearTraps(cx->runtime->defaultFreeOp()); } } @@ -786,7 +786,7 @@ JSCompartment::sweepBreakpoints(FreeOp *fop) for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) { nextbp = bp->nextInSite(); if (scriptGone || IsAboutToBeFinalized(bp->debugger->toJSObject())) - bp->destroy(fop->context); + bp->destroy(fop); } } } diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 2fe4a5fd7de5..c2c15f863517 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -383,7 +383,7 @@ struct JSCompartment 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(); @@ -446,12 +446,12 @@ struct JSCompartment 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); diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 7add81c94872..f7c34c77121b 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -204,7 +204,7 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handle 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; } @@ -213,7 +213,7 @@ 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; @@ -225,7 +225,7 @@ JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JS_PUBLIC_API(void) JS_ClearScriptTraps(JSContext *cx, JSScript *script) { - script->clearTraps(cx); + script->clearTraps(cx->runtime->defaultFreeOp()); } JS_PUBLIC_API(void) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index f05c67e762f6..9f1286ec2593 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2765,7 +2765,7 @@ GCHelperThread::replenishAndFreeLater(void *ptr) void GCHelperThread::doSweep() { - if (JSContext *cx = finalizationContext) { + if (finalizationContext) { finalizationContext = NULL; AutoUnlockGC unlock(rt); @@ -2773,7 +2773,7 @@ GCHelperThread::doSweep() * 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); @@ -2833,7 +2833,7 @@ 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; @@ -2850,7 +2850,7 @@ SweepCompartments(FreeOp *fop, JSGCInvocationKind gckind) { 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); @@ -3115,7 +3115,7 @@ SweepPhase(JSContext *cx, JSGCInvocationKind gckind) 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) @@ -3416,7 +3416,7 @@ IncrementalGCSlice(JSContext *cx, int64_t budget, JSGCInvocationKind gckind) 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); @@ -4175,7 +4175,7 @@ StartVerifyBarriers(JSContext *cx) 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; @@ -4329,7 +4329,7 @@ EndVerifyBarriers(JSContext *cx) 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; @@ -4423,7 +4423,7 @@ static void ReleaseAllJITCode(JSContext *cx) mjit::ClearAllFrames(c); for (CellIter i(c, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), script); } } #endif diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index d07e3e31b780..873a377b60cf 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -2082,7 +2082,7 @@ TypeCompartment::growPendingArray(JSContext *cx) } 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 *pending = pendingRecompiles; @@ -2092,18 +2092,18 @@ TypeCompartment::processPendingRecompiles(JSContext *cx) #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 @@ -2118,10 +2118,16 @@ TypeCompartment::setPendingNukeTypes(JSContext *cx) } void -TypeCompartment::nukeTypes(JSContext *cx) +TypeCompartment::setPendingNukeTypesNoReport() { - JS_ASSERT(this == &cx->compartment->types); + 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 @@ -2135,28 +2141,28 @@ TypeCompartment::nukeTypes(JSContext *cx) */ 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(); if (script->hasJITCode()) - mjit::ReleaseScriptCode(cx, script); + mjit::ReleaseScriptCode(fop, script); } #endif /* JS_METHODJIT */ @@ -5730,7 +5736,7 @@ JSCompartment::getLazyType(JSContext *cx, JSObject *proto) ///////////////////////////////////////////////////////////////////// void -TypeSet::sweep(JSContext *cx, JSCompartment *compartment) +TypeSet::sweep(JSCompartment *compartment) { /* * Purge references to type objects that are no longer live. Type sets hold @@ -5754,7 +5760,7 @@ TypeSet::sweep(JSContext *cx, JSCompartment *compartment) if (pentry) *pentry = object; else - compartment->types.setPendingNukeTypes(cx); + compartment->types.setPendingNukeTypesNoReport(); } } setBaseObjectCount(objectCount); @@ -5789,7 +5795,7 @@ TypeObject::clearProperties() * 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, @@ -5811,7 +5817,7 @@ TypeObject::sweep(JSContext *cx) if (!isMarked()) { if (newScript) - Foreground::free_(newScript); + fop->free_(newScript); return; } @@ -5840,12 +5846,12 @@ TypeObject::sweep(JSContext *cx) (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(); } } } @@ -5856,9 +5862,9 @@ TypeObject::sweep(JSContext *cx) Property *newProp = compartment->typeLifoAlloc.new_(*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; @@ -5882,27 +5888,27 @@ TypeObject::sweep(JSContext *cx) 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(cell); - object->sweep(cx); + object->sweep(fop); } }; void -SweepTypeObjects(JSContext *cx, JSCompartment *compartment) +SweepTypeObjects(FreeOp *fop, JSCompartment *compartment) { - SweepTypeObjectOp op(cx); + 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 @@ -5970,7 +5976,7 @@ TypeCompartment::sweep(JSContext *cx) * to reallocate if the compartment becomes active again. */ if (pendingArray) - cx->free_(pendingArray); + fop->free_(pendingArray); pendingArray = NULL; pendingCapacity = 0; @@ -6004,7 +6010,7 @@ TypeCompartment::~TypeCompartment() } /* static */ void -TypeScript::Sweep(JSContext *cx, JSScript *script) +TypeScript::Sweep(FreeOp *fop, JSScript *script) { JSCompartment *compartment = script->compartment(); JS_ASSERT(compartment->types.inferenceEnabled); @@ -6014,7 +6020,7 @@ TypeScript::Sweep(JSContext *cx, JSScript *script) /* 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) { @@ -6024,7 +6030,7 @@ TypeScript::Sweep(JSContext *cx, JSScript *script) if (!type.isUnknown() && !type.isAnyObject() && type.isObject() && IsAboutToBeFinalized(type.objectKey())) { *presult = result->next; - cx->delete_(result); + fop->delete_(result); } else { presult = &result->next; } diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index ddcfb429e2e4..3398aff2cf1e 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -366,7 +366,7 @@ class TypeSet 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. */ @@ -864,7 +864,7 @@ struct TypeObject : gc::Cell void print(JSContext *cx); inline void clearProperties(); - inline void sweep(JSContext *cx); + inline void sweep(FreeOp *fop); inline size_t computedSizeOfExcludingThis(); @@ -1121,7 +1121,7 @@ class TypeScript 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(); }; @@ -1244,11 +1244,12 @@ struct TypeCompartment /* 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); @@ -1261,7 +1262,7 @@ struct TypeCompartment /* 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(); }; diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index fbde80d76000..29f4874c240e 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -202,23 +202,26 @@ TypeIdString(jsid id) */ 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, @@ -226,14 +229,24 @@ struct AutoEnterTypeInference * 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; + } }; /* diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 15ea133d1d63..8e48472b2f4b 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -858,7 +858,7 @@ class EvalScriptGuard ~EvalScriptGuard() { if (script_) { - js_CallDestroyScriptHook(cx_, script_); + CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_); script_->isActiveEval = false; script_->isCachedEval = true; script_->evalHashLink() = *bucket_; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index a1dd65753efc..459c151baaa6 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1622,6 +1622,9 @@ 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___ */ diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index cd3b51ae0826..5e27650c81cb 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1754,4 +1754,10 @@ js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id) return true; } +inline void +js::DestroyIdArray(FreeOp *fop, JSIdArray *ida) +{ + fop->free_(ida); +} + #endif /* jsobjinlines_h___ */ diff --git a/js/src/jsprobes.cpp b/js/src/jsprobes.cpp index d1767ea573b7..c786e8e98e2f 100644 --- a/js/src/jsprobes.cpp +++ b/js/src/jsprobes.cpp @@ -231,10 +231,10 @@ Probes::registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr, } 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 diff --git a/js/src/jsprobes.h b/js/src/jsprobes.h index a7059dd38278..1c44f96c7eef 100644 --- a/js/src/jsprobes.h +++ b/js/src/jsprobes.h @@ -264,7 +264,7 @@ public: 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, @@ -316,7 +316,7 @@ registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr, * 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 diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 425e65813fe5..624553ea7a6e 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -388,7 +388,7 @@ typedef void /* called just before script destruction */ typedef void -(* JSDestroyScriptHook)(JSContext *cx, +(* JSDestroyScriptHook)(JSFreeOp *fop, JSScript *script, void *callerdata); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 5c88be26fe95..01a41b1385fa 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -818,10 +818,10 @@ JSScript::initScriptCounts(JSContext *cx) } void -JSScript::destroyScriptCounts(JSContext *cx) +JSScript::destroyScriptCounts(FreeOp *fop) { if (scriptCounts) { - cx->free_(scriptCounts.pcCountsVector); + fop->free_(scriptCounts.pcCountsVector); scriptCounts.pcCountsVector = NULL; } } @@ -1380,21 +1380,21 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun) } 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) @@ -1406,10 +1406,10 @@ JSScript::finalize(FreeOp *fop) 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); @@ -1420,7 +1420,7 @@ JSScript::finalize(FreeOp *fop) 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); } } @@ -1685,16 +1685,15 @@ JSScript::ensureHasDebug(JSContext *cx) 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 @@ -1707,10 +1706,7 @@ JSScript::tryNewStepMode(JSContext *cx, uint32_t 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); @@ -1775,18 +1771,18 @@ JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc, } 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; } } @@ -1805,14 +1801,14 @@ JSScript::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler 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; @@ -1821,7 +1817,7 @@ JSScript::clearTraps(JSContext *cx) for (jsbytecode *pc = code; pc < end; pc++) { BreakpointSite *site = getBreakpointSite(pc); if (site) - site->clearTrap(cx); + site->clearTrap(fop); } } @@ -1917,8 +1913,8 @@ JSScript::applySpeculationFailed(JSContext *cx) #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 diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 217a7e9396ab..4c7f42f541f4 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -635,7 +635,7 @@ struct JSScript : public js::gc::Cell } bool initScriptCounts(JSContext *cx); - void destroyScriptCounts(JSContext *cx); + void destroyScriptCounts(js::FreeOp *fop); jsbytecode *main() { return code + mainOffset; @@ -751,10 +751,10 @@ struct JSScript : public js::gc::Cell 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); @@ -774,10 +774,10 @@ struct JSScript : public js::gc::Cell 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); @@ -836,11 +836,11 @@ StackDepth(JSScript *script) extern JS_FRIEND_API(void) js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun); -extern void -js_CallDestroyScriptHook(JSContext *cx, JSScript *script); - namespace js { +extern void +CallDestroyScriptHook(FreeOp *fop, JSScript *script); + extern const char * SaveScriptFilename(JSContext *cx, const char *filename); diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index f82e2de2e1e9..867dbab5b7fb 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -926,15 +926,15 @@ JSXMLArray::trim() template void -JSXMLArray::finish(JSContext *cx) +JSXMLArray::finish(FreeOp *fop) { - if (!cx->runtime->gcRunning) { + 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(); } - cx->free_(vector); + fop->free_(vector); while (JSXMLArrayCursor *cursor = cursors) cursor->disconnect(); @@ -1178,10 +1178,10 @@ 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 @@ -4485,7 +4485,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) 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); } diff --git a/js/src/jsxml.h b/js/src/jsxml.h index 7ea0faab3f4d..e328ca7d6cda 100644 --- a/js/src/jsxml.h +++ b/js/src/jsxml.h @@ -72,7 +72,7 @@ struct JSXMLArray cursors = NULL; } - void finish(JSContext *cx); + void finish(js::FreeOp *fop); bool setCapacity(JSContext *cx, uint32_t capacity); void trim(); diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp index 6df2c3e95747..7fe5033eb3a7 100644 --- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -1313,23 +1313,23 @@ JITChunk::~JITChunk() } 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(); @@ -1341,7 +1341,7 @@ JITScript::destroyChunk(JSContext *cx, unsigned chunkIndex, bool resetUses) 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) { @@ -1438,7 +1438,7 @@ mjit::JITChunk::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) } 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 @@ -1448,8 +1448,8 @@ mjit::ReleaseScriptCode(JSContext *cx, JSScript *script, bool construct) 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; } diff --git a/js/src/methodjit/MethodJIT.h b/js/src/methodjit/MethodJIT.h index 5a14180eac4f..a845a7482684 100644 --- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -866,8 +866,8 @@ struct JITScript 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); }; /* @@ -907,15 +907,15 @@ 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. diff --git a/js/src/methodjit/Retcon.cpp b/js/src/methodjit/Retcon.cpp index 682c866df37d..03ee1feae5fa 100644 --- a/js/src/methodjit/Retcon.cpp +++ b/js/src/methodjit/Retcon.cpp @@ -401,14 +401,15 @@ ClearAllFrames(JSCompartment *compartment) * 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: @@ -422,7 +423,7 @@ Recompiler::clearStackReferences(JSContext *cx, JSScript *script) // 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) { @@ -450,18 +451,18 @@ Recompiler::clearStackReferences(JSContext *cx, JSScript *script) 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) { @@ -469,7 +470,7 @@ Recompiler::clearStackReferencesAndChunk(JSContext *cx, JSScript *script, // 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) { @@ -477,7 +478,7 @@ Recompiler::clearStackReferencesAndChunk(JSContext *cx, JSScript *script, 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; } @@ -486,7 +487,7 @@ Recompiler::clearStackReferencesAndChunk(JSContext *cx, JSScript *script, } if (releaseChunk) - jit->destroyChunk(cx, chunkIndex, resetUses); + jit->destroyChunk(fop, chunkIndex, resetUses); } } /* namespace mjit */ diff --git a/js/src/methodjit/Retcon.h b/js/src/methodjit/Retcon.h index 222d1a9db827..e89950d31576 100644 --- a/js/src/methodjit/Retcon.h +++ b/js/src/methodjit/Retcon.h @@ -68,12 +68,12 @@ 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); diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index ca681d15c8e8..d3c078fba3bd 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -818,8 +818,8 @@ 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 @@ -1670,8 +1670,8 @@ stubs::InvariantFailure(VMFrame &f, void *rval) 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; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index e2edc566ca56..23f27a652379 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -283,58 +283,45 @@ ScriptGlobal(JSContext *cx, JSScript *script, GlobalObject *scriptGlobal) 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 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; @@ -344,19 +331,19 @@ BreakpointSite::clearTrap(JSContext *cx, JSTrapHandler *handlerp, Value *closure 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 * @@ -396,15 +383,14 @@ Breakpoint::fromSiteLinks(JSCList *links) } 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 * @@ -1476,7 +1462,7 @@ Debugger::sweepAll(FreeOp *fop) * 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); } } @@ -1487,19 +1473,19 @@ Debugger::sweepAll(FreeOp *fop) 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 @@ -1575,23 +1561,10 @@ Debugger::setEnabled(JSContext *cx, unsigned argc, Value *vp) 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()); } } @@ -1756,7 +1729,7 @@ Debugger::removeDebuggee(JSContext *cx, unsigned argc, Value *vp) 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; } @@ -1946,7 +1919,7 @@ Debugger::addDebuggeeGlobal(JSContext *cx, GlobalObject *global) } void -Debugger::removeDebuggeeGlobal(JSContext *cx, GlobalObject *global, +Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global, GlobalObjectSet::Enum *compartmentEnum, GlobalObjectSet::Enum *debugEnum) { @@ -1992,7 +1965,7 @@ Debugger::removeDebuggeeGlobal(JSContext *cx, GlobalObject *global, */ v->erase(p); if (v->empty()) - global->compartment()->removeDebuggee(cx, global, compartmentEnum); + global->compartment()->removeDebuggee(fop, global, compartmentEnum); if (debugEnum) debugEnum->removeFront(); else @@ -2608,14 +2581,13 @@ DebuggerScript_setBreakpoint(JSContext *cx, unsigned argc, Value *vp) BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, scriptGlobal); if (!site) return false; - if (site->inc(cx)) { - if (cx->runtime->new_(dbg, site, handler)) { - args.rval().setUndefined(); - return true; - } - site->dec(cx); + site->inc(cx->runtime->defaultFreeOp()); + if (cx->runtime->new_(dbg, site, handler)) { + args.rval().setUndefined(); + return true; } - site->destroyIfEmpty(cx->runtime); + site->dec(cx->runtime->defaultFreeOp()); + site->destroyIfEmpty(cx->runtime->defaultFreeOp()); return false; } diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index c9ab259bd055..5824c06a5c8d 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -122,7 +122,7 @@ class Debugger { 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); @@ -264,7 +264,7 @@ class Debugger { 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); @@ -399,7 +399,7 @@ class BreakpointSite { JSTrapHandler trapHandler; /* jsdbgapi trap state */ HeapValue trapClosure; - bool recompile(JSContext *cx, bool forTrap); + void recompile(FreeOp *fop); public: BreakpointSite(JSScript *script, jsbytecode *pc); @@ -408,11 +408,11 @@ class BreakpointSite { 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); }; /* @@ -449,7 +449,7 @@ class Breakpoint { 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; } diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 2b584858dc6e..87fcea1c5927 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -370,8 +370,8 @@ GlobalObject::clear(JSContext *cx) for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); 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 @@ -507,7 +507,7 @@ GlobalObject::addDebugger(JSContext *cx, Debugger *dbg) 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; diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 59b0ef4cafbd..55579b78de7f 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -251,19 +251,17 @@ 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 priv(static_cast(JS_GetCompartmentPrivate(compartment))); if (!priv) - return true; + return; JS_SetCompartmentPrivate(compartment, nsnull); @@ -275,8 +273,6 @@ CompartmentCallback(JSContext *cx, JSCompartment *compartment, unsigned op) NS_ASSERTION(current == compartment, "compartment mismatch"); #endif map.Remove(key); - - return true; } struct ObjectHolder : public JSDHashEntryHdr @@ -2001,7 +1997,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) 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);