Backed out changeset 2a694bf4a9de (bug 1323241) for causing frequent GC crashes in CI.

This commit is contained in:
Ryan VanderMeulen 2017-01-07 10:45:47 -05:00
parent e9ea578bba
commit f35d8f4f3b
9 changed files with 37 additions and 39 deletions

View File

@ -644,12 +644,12 @@ ExposeGCThingToActiveJS(JS::GCCellPtr thing)
if (thing.mayBeOwnedByOtherRuntime())
return;
JS::shadow::Runtime* rt = detail::GetCellRuntime(thing.asCell());
JS::shadow::Runtime* rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr());
MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers());
if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing))
JS::IncrementalReferenceBarrier(thing);
else if (!thing.mayBeOwnedByOtherRuntime() && js::gc::detail::CellIsMarkedGray(thing.asCell()))
else if (JS::GCThingIsMarkedGray(thing))
JS::UnmarkGrayGCThingRecursively(thing);
}

View File

@ -280,6 +280,14 @@ GetGCThingMarkBitmap(const uintptr_t addr)
return reinterpret_cast<uintptr_t*>(bmap_addr);
}
static MOZ_ALWAYS_INLINE JS::shadow::Runtime*
GetGCThingRuntime(const uintptr_t addr)
{
MOZ_ASSERT(addr);
const uintptr_t rt_addr = (addr & ~ChunkMask) | ChunkRuntimeOffset;
return *reinterpret_cast<JS::shadow::Runtime**>(rt_addr);
}
static MOZ_ALWAYS_INLINE void
GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color,
uintptr_t** wordp, uintptr_t* maskp)
@ -302,35 +310,16 @@ GetGCThingZone(const uintptr_t addr)
}
static MOZ_ALWAYS_INLINE JS::shadow::Runtime*
GetCellRuntime(const Cell* cell)
{
MOZ_ASSERT(cell);
const uintptr_t addr = uintptr_t(cell);
const uintptr_t rt_addr = (addr & ~ChunkMask) | ChunkRuntimeOffset;
return *reinterpret_cast<JS::shadow::Runtime**>(rt_addr);
}
static MOZ_ALWAYS_INLINE bool
CellIsMarkedGray(const Cell* cell)
{
MOZ_ASSERT(cell);
if (js::gc::IsInsideNursery(cell))
return false;
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
uintptr_t* word, mask;
js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), js::gc::GRAY, &word, &mask);
return *word & mask;
}
static MOZ_ALWAYS_INLINE bool
CellIsMarkedGrayIfKnown(const Cell* cell)
{
MOZ_ASSERT(cell);
auto rt = js::gc::detail::GetCellRuntime(cell);
return rt->areGCGrayBitsValid() && CellIsMarkedGray(cell);
}
} /* namespace detail */
MOZ_ALWAYS_INLINE bool
@ -370,9 +359,11 @@ GetObjectZone(JSObject* obj);
static MOZ_ALWAYS_INLINE bool
GCThingIsMarkedGray(GCCellPtr thing)
{
if (js::gc::IsInsideNursery(thing.asCell()))
return false;
if (thing.mayBeOwnedByOtherRuntime())
return false;
return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell());
return js::gc::detail::CellIsMarkedGray(thing.asCell());
}
extern JS_PUBLIC_API(JS::TraceKind)

View File

@ -309,8 +309,14 @@ ObjectIsTenured(const Heap<JSObject*>& obj)
static MOZ_ALWAYS_INLINE bool
ObjectIsMarkedGray(JSObject* obj)
{
auto cell = reinterpret_cast<js::gc::Cell*>(obj);
return js::gc::detail::CellIsMarkedGrayIfKnown(cell);
/*
* GC things residing in the nursery cannot be gray: they have no mark bits.
* All live objects in the nursery are moved to tenured at the beginning of
* each GC slice, so the gray marker never sees nursery things.
*/
if (js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(obj)))
return false;
return js::gc::detail::CellIsMarkedGray(reinterpret_cast<js::gc::Cell*>(obj));
}
static MOZ_ALWAYS_INLINE bool
@ -322,8 +328,7 @@ ObjectIsMarkedGray(const JS::Heap<JSObject*>& obj)
static MOZ_ALWAYS_INLINE bool
ScriptIsMarkedGray(JSScript* script)
{
auto cell = reinterpret_cast<js::gc::Cell*>(script);
return js::gc::detail::CellIsMarkedGrayIfKnown(cell);
return js::gc::detail::CellIsMarkedGray(reinterpret_cast<js::gc::Cell*>(script));
}
static MOZ_ALWAYS_INLINE bool

View File

@ -816,6 +816,9 @@ class GCRuntime
bool isFullGc() const { return isFull; }
bool isCompactingGc() const { return isCompacting; }
bool areGrayBitsValid() const { return grayBitsValid; }
void setGrayBitsInvalid() { grayBitsValid = false; }
bool minorGCRequested() const { return minorGCTriggerReason != JS::gcreason::NO_REASON; }
bool majorGCRequested() const { return majorGCTriggerReason != JS::gcreason::NO_REASON; }
bool isGcNeeded() { return minorGCRequested() || majorGCRequested(); }
@ -1127,6 +1130,12 @@ class GCRuntime
resetBufferedGrayRoots();
}
/*
* The gray bits can become invalid if UnmarkGray overflows the stack. A
* full GC will reset this bit, since it fills in all the gray bits.
*/
bool grayBitsValid;
mozilla::Atomic<JS::gcreason::Reason, mozilla::Relaxed> majorGCTriggerReason;
JS::gcreason::Reason minorGCTriggerReason;

View File

@ -2917,7 +2917,7 @@ UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing)
* If we run out of stack, we take a more drastic measure: require that
* we GC again before the next CC.
*/
runtime()->setGCGrayBitsValid(false);
runtime()->gc.setGrayBitsInvalid();
return;
}

View File

@ -54,7 +54,7 @@ BEGIN_TEST(testGCCellPtr)
JS::GCCellPtr copy = objcell;
CHECK(copy == objcell);
CHECK(js::gc::detail::GetCellRuntime(scriptcell.asCell()) == cx->runtime());
CHECK(js::gc::detail::GetGCThingRuntime(scriptcell.unsafeAsUIntPtr()) == cx->runtime());
return true;
}

View File

@ -597,7 +597,7 @@ js::TraceWeakMaps(WeakMapTracer* trc)
extern JS_FRIEND_API(bool)
js::AreGCGrayBitsValid(JSContext* cx)
{
return cx->areGCGrayBitsValid();
return cx->gc.areGrayBitsValid();
}
JS_FRIEND_API(bool)

View File

@ -823,6 +823,7 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
numActiveZoneIters(0),
cleanUpEverything(false),
grayBufferState(GCRuntime::GrayBufferState::Unused),
grayBitsValid(false),
majorGCTriggerReason(JS::gcreason::NO_REASON),
minorGCTriggerReason(JS::gcreason::NO_REASON),
fullGCForAtomsRequested_(false),
@ -5447,7 +5448,7 @@ GCRuntime::endSweepPhase(bool destroyingRuntime, AutoLockForExclusiveAccess& loc
/* If we finished a full GC, then the gray bits are correct. */
if (isFull)
rt->setGCGrayBitsValid(true);
grayBitsValid = true;
}
finishMarkingValidation();

View File

@ -187,16 +187,11 @@ struct Runtime
js::gc::StoreBuffer* gcStoreBufferPtr_;
// The gray bits can become invalid if UnmarkGray overflows the stack. A
// full GC will reset this bit, since it fills in all the gray bits.
bool gcGrayBitsValid_;
public:
Runtime()
: heapState_(JS::HeapState::Idle)
, allowGCBarriers_(true)
, gcStoreBufferPtr_(nullptr)
, gcGrayBitsValid_(false)
{}
bool isHeapBusy() const { return heapState() != JS::HeapState::Idle; }
@ -212,9 +207,6 @@ struct Runtime
js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; }
bool areGCGrayBitsValid() const { return gcGrayBitsValid_; }
void setGCGrayBitsValid(bool valid) { gcGrayBitsValid_ = valid; }
const JSRuntime* asRuntime() const {
return reinterpret_cast<const JSRuntime*>(this);
}