Bug 862606 - Shift around some marking for brain transplants (r=bhackett)

This commit is contained in:
Bill McCloskey 2013-04-22 14:04:10 -07:00
parent ab0ca9312a
commit 259685d273
7 changed files with 62 additions and 22 deletions

View File

@ -814,7 +814,9 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
gcIsFull(false),
gcTriggerReason(JS::gcreason::NO_REASON),
gcStrictCompartmentChecking(false),
#ifdef DEBUG
gcDisableStrictProxyCheckingCount(0),
#endif
gcIncrementalState(gc::NO_INCREMENTAL),
gcLastMarkSlice(false),
gcSweepOnBackgroundThread(false),
@ -1633,6 +1635,7 @@ JS_TransplantObject(JSContext *cx, JSObject *origobjArg, JSObject *targetArg)
JS_ASSERT(!IsCrossCompartmentWrapper(target));
AutoMaybeTouchDeadZones agc(cx);
AutoDisableProxyCheck adpc(cx->runtime);
JSCompartment *destination = target->compartment();
RootedValue origv(cx, ObjectValue(*origobj));
@ -1706,6 +1709,7 @@ js_TransplantObjectWithWrapper(JSContext *cx,
RootedObject targetwrapper(cx, targetwrapperArg);
AutoMaybeTouchDeadZones agc(cx);
AutoDisableProxyCheck adpc(cx->runtime);
AssertHeapIsIdle(cx);
JS_ASSERT(!IsCrossCompartmentWrapper(origobj));

View File

@ -956,6 +956,7 @@ struct JSRuntime : public JS::shadow::Runtime,
*/
bool gcStrictCompartmentChecking;
#ifdef DEBUG
/*
* If this is 0, all cross-compartment proxies must be registered in the
* wrapper map. This checking must be disabled temporarily while creating
@ -963,6 +964,9 @@ struct JSRuntime : public JS::shadow::Runtime,
* creation.
*/
uintptr_t gcDisableStrictProxyCheckingCount;
#else
uintptr_t unused1;
#endif
/*
* The current incremental GC phase. This is also used internally in

View File

@ -213,15 +213,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleValue vp, HandleObject existingA
JS_CHECK_CHROME_RECURSION(cx, return false);
#ifdef DEBUG
struct AutoDisableProxyCheck {
JSRuntime *runtime;
AutoDisableProxyCheck(JSRuntime *rt) : runtime(rt) {
runtime->gcDisableStrictProxyCheckingCount++;
}
~AutoDisableProxyCheck() { runtime->gcDisableStrictProxyCheckingCount--; }
} adpc(rt);
#endif
AutoDisableProxyCheck adpc(rt);
/* Only GC things have to be wrapped or copied. */
if (!vp.isMarkable())

View File

@ -5112,3 +5112,11 @@ AutoSuppressGC::AutoSuppressGC(JSCompartment *comp)
{
suppressGC_++;
}
#ifdef DEBUG
AutoDisableProxyCheck::AutoDisableProxyCheck(JSRuntime *rt)
: count(rt->gcDisableStrictProxyCheckingCount)
{
count++;
}
#endif

View File

@ -1285,6 +1285,25 @@ class AutoSuppressGC
} /* namespace gc */
#ifdef DEBUG
/* Use this to avoid assertions when manipulating the wrapper map. */
struct AutoDisableProxyCheck
{
uintptr_t &count;
AutoDisableProxyCheck(JSRuntime *rt);
~AutoDisableProxyCheck() {
count--;
}
};
#else
struct AutoDisableProxyCheck
{
AutoDisableProxyCheck(JSRuntime *rt) {}
};
#endif
void
PurgeJITCaches(JS::Zone *zone);

View File

@ -1773,6 +1773,12 @@ bool
JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *aArg, JSObject *bArg,
TradeGutsReserved &reserved)
{
/*
* Avoid GC in here to avoid confusing the tracing code with our
* intermediate state.
*/
AutoSuppressGC suppress(cx);
RootedObject a(cx, aArg);
RootedObject b(cx, bArg);
JS_ASSERT(a->compartment() == b->compartment());
@ -1784,19 +1790,6 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *aArg, JSObject *bArg,
* swaps can be performed infallibly.
*/
#ifdef JSGC_INCREMENTAL
/*
* We need a write barrier here. If |a| was marked and |b| was not, then
* after the swap, |b|'s guts would never be marked. The write barrier
* solves this.
*/
JS::Zone *zone = a->zone();
if (zone->needsBarrier()) {
MarkChildren(zone->barrierTracer(), a);
MarkChildren(zone->barrierTracer(), b);
}
#endif
/*
* Swap prototypes and classes on the two objects, so that TradeGuts can
* preserve the types of the two objects.
@ -2015,6 +2008,24 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
a->lastProperty()->listp = &a->shape_;
if (b->inDictionaryMode())
b->lastProperty()->listp = &b->shape_;
#ifdef JSGC_INCREMENTAL
/*
* We need a write barrier here. If |a| was marked and |b| was not, then
* after the swap, |b|'s guts would never be marked. The write barrier
* solves this.
*
* Normally write barriers happen before the write. However, that's not
* necessary here because nothing is being destroyed. We're just swapping.
* We don't do the barrier before TradeGuts because ReserveForTradeGuts
* makes changes to the objects that might confuse the tracing code.
*/
JS::Zone *zone = a->zone();
if (zone->needsBarrier()) {
MarkChildren(zone->barrierTracer(), a);
MarkChildren(zone->barrierTracer(), b);
}
#endif
}
/* Use this method with extreme caution. It trades the guts of two objects. */

View File

@ -953,6 +953,8 @@ js::RemapWrapper(JSContext *cx, JSObject *wobjArg, JSObject *newTargetArg)
Value origv = ObjectValue(*origTarget);
JSCompartment *wcompartment = wobj->compartment();
AutoDisableProxyCheck adpc(cx->runtime);
// If we're mapping to a different target (as opposed to just recomputing
// for the same target), we must not have an existing wrapper for the new
// target, otherwise this will break.