mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-12 14:37:50 +00:00
Sweep compartments when no objects live in them (bug 639270, r=gregor).
This commit is contained in:
parent
b55a8920aa
commit
74d162d185
@ -1333,7 +1333,7 @@ JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
|
||||
// types of security wrappers based on whether the new compartment
|
||||
// is same origin with them.
|
||||
Value targetv = ObjectValue(*obj);
|
||||
WrapperVector &vector = cx->runtime->compartments;
|
||||
CompartmentVector &vector = cx->runtime->compartments;
|
||||
AutoValueVector toTransplant(cx);
|
||||
if (!toTransplant.reserve(vector.length()))
|
||||
return NULL;
|
||||
@ -1427,7 +1427,7 @@ js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
// and not |origwrapper|. They need to be updated to point at the new
|
||||
// location object.
|
||||
Value targetv = ObjectValue(*targetobj);
|
||||
WrapperVector &vector = cx->runtime->compartments;
|
||||
CompartmentVector &vector = cx->runtime->compartments;
|
||||
AutoValueVector toTransplant(cx);
|
||||
if (!toTransplant.reserve(vector.length()))
|
||||
return NULL;
|
||||
@ -3081,6 +3081,21 @@ JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
|
||||
return obj;
|
||||
}
|
||||
|
||||
class AutoHoldCompartment {
|
||||
public:
|
||||
AutoHoldCompartment(JSCompartment *compartment JS_GUARD_OBJECT_NOTIFIER_PARAM) {
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
*(holdp = &compartment->hold) = true;
|
||||
}
|
||||
|
||||
~AutoHoldCompartment() {
|
||||
*holdp = false;
|
||||
}
|
||||
private:
|
||||
bool *holdp;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
|
||||
{
|
||||
@ -3089,6 +3104,8 @@ JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *pr
|
||||
if (!compartment)
|
||||
return NULL;
|
||||
|
||||
AutoHoldCompartment hold(compartment);
|
||||
|
||||
JSCompartment *saved = cx->compartment;
|
||||
cx->compartment = compartment;
|
||||
JSObject *obj = JS_NewGlobalObject(cx, clasp);
|
||||
|
@ -988,7 +988,7 @@ typedef void
|
||||
|
||||
namespace js {
|
||||
|
||||
typedef js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> WrapperVector;
|
||||
typedef js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> CompartmentVector;
|
||||
|
||||
}
|
||||
|
||||
@ -1000,7 +1000,7 @@ struct JSRuntime {
|
||||
#endif
|
||||
|
||||
/* List of compartments (protected by the GC lock). */
|
||||
js::WrapperVector compartments;
|
||||
js::CompartmentVector compartments;
|
||||
|
||||
/* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
|
||||
JSRuntimeState state;
|
||||
|
@ -66,6 +66,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
gcBytes(0),
|
||||
gcTriggerBytes(0),
|
||||
gcLastBytes(0),
|
||||
hold(false),
|
||||
data(NULL),
|
||||
active(false),
|
||||
#ifdef JS_METHODJIT
|
||||
@ -82,8 +83,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
#if ENABLE_YARR_JIT
|
||||
regExpAllocator(NULL),
|
||||
#endif
|
||||
mathCache(NULL),
|
||||
marked(false)
|
||||
mathCache(NULL)
|
||||
{
|
||||
JS_INIT_CLIST(&scripts);
|
||||
|
||||
@ -447,35 +447,23 @@ ScriptPoolDestroyed(JSContext *cx, mjit::JITScript *jit,
|
||||
|
||||
/*
|
||||
* This method marks pointers that cross compartment boundaries. It should be
|
||||
* called only by per-compartment GCs, since full GCs naturally follow pointers
|
||||
* called only for per-compartment GCs, since full GCs naturally follow pointers
|
||||
* across compartments.
|
||||
*/
|
||||
void
|
||||
JSCompartment::markCrossCompartment(JSTracer *trc)
|
||||
JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
|
||||
{
|
||||
JS_ASSERT(trc->context->runtime->gcCurrentCompartment);
|
||||
|
||||
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront())
|
||||
MarkValue(trc, e.front().key, "cross-compartment wrapper");
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::mark(JSTracer *trc)
|
||||
{
|
||||
if (IS_GC_MARKING_TRACER(trc)) {
|
||||
JSRuntime *rt = trc->context->runtime;
|
||||
|
||||
if (rt->gcCurrentCompartment && rt->gcCurrentCompartment != this)
|
||||
return;
|
||||
|
||||
if (marked)
|
||||
return;
|
||||
marked = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
{
|
||||
chunk = NULL;
|
||||
|
||||
/* Remove dead wrappers from the table. */
|
||||
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
|
||||
JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) &&
|
||||
|
@ -381,6 +381,8 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
size_t gcTriggerBytes;
|
||||
size_t gcLastBytes;
|
||||
|
||||
bool hold;
|
||||
|
||||
#ifdef JS_GCMETER
|
||||
js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT];
|
||||
#endif
|
||||
@ -451,10 +453,7 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
bool init();
|
||||
|
||||
/* Mark cross-compartment wrappers. */
|
||||
void markCrossCompartment(JSTracer *trc);
|
||||
|
||||
/* Mark this compartment's local roots. */
|
||||
void mark(JSTracer *trc);
|
||||
void markCrossCompartmentWrappers(JSTracer *trc);
|
||||
|
||||
bool wrap(JSContext *cx, js::Value *vp);
|
||||
bool wrap(JSContext *cx, JSString **strp);
|
||||
@ -481,8 +480,6 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
|
||||
js::MathCache *allocMathCache(JSContext *cx);
|
||||
|
||||
bool marked;
|
||||
|
||||
typedef js::HashMap<jsbytecode*,
|
||||
size_t,
|
||||
js::DefaultHasher<jsbytecode*>,
|
||||
@ -496,9 +493,6 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||
return mathCache ? mathCache : allocMathCache(cx);
|
||||
}
|
||||
|
||||
bool isMarked() { return marked; }
|
||||
void clearMark() { marked = false; }
|
||||
|
||||
size_t backEdgeCount(jsbytecode *pc) const;
|
||||
size_t incBackEdgeCount(jsbytecode *pc);
|
||||
};
|
||||
|
@ -1633,9 +1633,6 @@ MarkContext(JSTracer *trc, JSContext *acx)
|
||||
js_TraceSharpMap(trc, &acx->sharpObjectMap);
|
||||
|
||||
MarkValue(trc, acx->iterValue, "iterValue");
|
||||
|
||||
if (acx->compartment)
|
||||
acx->compartment->mark(trc);
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK void
|
||||
@ -1724,8 +1721,6 @@ MarkRuntime(JSTracer *trc)
|
||||
while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter))
|
||||
MarkContext(trc, acx);
|
||||
|
||||
rt->atomsCompartment->mark(trc);
|
||||
|
||||
#ifdef JS_TRACER
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||
(*c)->traceMonitor.mark(trc);
|
||||
@ -2187,13 +2182,8 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
|
||||
while (read < end) {
|
||||
JSCompartment *compartment = *read++;
|
||||
|
||||
/*
|
||||
* Unmarked compartments containing marked objects don't get deleted,
|
||||
* except when LAST_CONTEXT GC is performed.
|
||||
*/
|
||||
if ((!compartment->isMarked() && compartment->arenaListsAreEmpty()) ||
|
||||
gckind == GC_LAST_CONTEXT)
|
||||
{
|
||||
if (!compartment->hold &&
|
||||
(compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT)) {
|
||||
JS_ASSERT(compartment->freeLists.isEmpty());
|
||||
if (callback)
|
||||
(void) callback(cx, compartment, JSCOMPARTMENT_DESTROY);
|
||||
@ -2268,7 +2258,6 @@ MarkAndSweepCompartment(JSContext *cx, JSCompartment *comp, JSGCInvocationKind g
|
||||
JS_ASSERT(!rt->gcRegenShapes);
|
||||
JS_ASSERT(gckind != GC_LAST_CONTEXT);
|
||||
JS_ASSERT(comp != rt->atomsCompartment);
|
||||
JS_ASSERT(!comp->isMarked());
|
||||
JS_ASSERT(comp->rt->gcMode == JSGC_MODE_COMPARTMENT);
|
||||
|
||||
/*
|
||||
@ -2284,9 +2273,7 @@ MarkAndSweepCompartment(JSContext *cx, JSCompartment *comp, JSGCInvocationKind g
|
||||
r.front()->clearMarkBitmap();
|
||||
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||
(*c)->markCrossCompartment(&gcmarker);
|
||||
|
||||
comp->mark(&gcmarker);
|
||||
(*c)->markCrossCompartmentWrappers(&gcmarker);
|
||||
|
||||
MarkRuntime(&gcmarker);
|
||||
|
||||
@ -2384,8 +2371,6 @@ MarkAndSweepCompartment(JSContext *cx, JSCompartment *comp, JSGCInvocationKind g
|
||||
ExpireGCChunks(rt);
|
||||
TIMESTAMP(sweepDestroyEnd);
|
||||
|
||||
comp->clearMark();
|
||||
|
||||
if (rt->gcCallback)
|
||||
(void) rt->gcCallback(cx, JSGC_FINALIZE_END);
|
||||
}
|
||||
@ -2523,9 +2508,6 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
|
||||
ExpireGCChunks(rt);
|
||||
TIMESTAMP(sweepDestroyEnd);
|
||||
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||
(*c)->clearMark();
|
||||
|
||||
if (rt->gcCallback)
|
||||
(void) rt->gcCallback(cx, JSGC_FINALIZE_END);
|
||||
#ifdef DEBUG_srcnotesize
|
||||
@ -2736,9 +2718,6 @@ GCUntilDone(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
||||
|
||||
AutoGCSession gcsession(cx);
|
||||
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||
JS_ASSERT(!(*c)->isMarked());
|
||||
|
||||
/*
|
||||
* We should not be depending on cx->compartment in the GC, so set it to
|
||||
* NULL to look for violations.
|
||||
|
@ -6509,11 +6509,6 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
|
||||
|
||||
obj->trace(trc);
|
||||
|
||||
if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
|
||||
JSCompartment *compartment = obj->getCompartment();
|
||||
compartment->mark(trc);
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: clasp->mark could mutate something (which would be a bug, but we are
|
||||
* defensive), so don't hoist this above calling clasp->mark.
|
||||
|
Loading…
Reference in New Issue
Block a user