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.
This commit is contained in:
Igor Bukanov 2012-03-20 11:22:05 +01:00
parent ac58c404f7
commit 18841022a6
31 changed files with 267 additions and 281 deletions

View File

@ -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<JSSecurityCallbacks *>(&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);
}
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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<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)
{
}
@ -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;

View File

@ -98,7 +98,7 @@ class AutoNamespaceArray : protected AutoGCRooter {
}
~AutoNamespaceArray() {
array.finish(context);
array.finish(context->runtime->defaultFreeOp());
}
uint32_t length() const { return array.length; }

View File

@ -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<JSScript>();
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<JSScript>();
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<JSScript>();
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<JSScript>();
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);
}
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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<JSScript>();
mjit::ReleaseScriptCode(cx, script);
mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), script);
}
}
#endif

View File

@ -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<RecompileInfo> *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<JSScript>();
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_<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;
@ -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<TypeObject *>(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;
}

View File

@ -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();
};

View File

@ -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;
}
};
/*

View File

@ -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_;

View File

@ -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___ */

View File

@ -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___ */

View File

@ -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

View File

@ -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

View File

@ -388,7 +388,7 @@ typedef void
/* called just before script destruction */
typedef void
(* JSDestroyScriptHook)(JSContext *cx,
(* JSDestroyScriptHook)(JSFreeOp *fop,
JSScript *script,
void *callerdata);

View File

@ -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

View File

@ -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);

View File

@ -926,15 +926,15 @@ JSXMLArray<T>::trim()
template<class T>
void
JSXMLArray<T>::finish(JSContext *cx)
JSXMLArray<T>::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<T>();
}
cx->free_(vector);
fop->free_(vector);
while (JSXMLArrayCursor<T> *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);
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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.

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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<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;
@ -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_<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;
}

View File

@ -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; }

View File

@ -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<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
@ -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;

View File

@ -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<xpc::CompartmentPrivate>
priv(static_cast<xpc::CompartmentPrivate*>(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);