mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-06 00:31:27 +00:00
Backed out changeset 2a694bf4a9de (bug 1323241) for causing frequent GC crashes in CI.
This commit is contained in:
parent
e9ea578bba
commit
f35d8f4f3b
@ -644,12 +644,12 @@ ExposeGCThingToActiveJS(JS::GCCellPtr thing)
|
|||||||
if (thing.mayBeOwnedByOtherRuntime())
|
if (thing.mayBeOwnedByOtherRuntime())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JS::shadow::Runtime* rt = detail::GetCellRuntime(thing.asCell());
|
JS::shadow::Runtime* rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr());
|
||||||
MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers());
|
MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers());
|
||||||
|
|
||||||
if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing))
|
if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing))
|
||||||
JS::IncrementalReferenceBarrier(thing);
|
JS::IncrementalReferenceBarrier(thing);
|
||||||
else if (!thing.mayBeOwnedByOtherRuntime() && js::gc::detail::CellIsMarkedGray(thing.asCell()))
|
else if (JS::GCThingIsMarkedGray(thing))
|
||||||
JS::UnmarkGrayGCThingRecursively(thing);
|
JS::UnmarkGrayGCThingRecursively(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +280,14 @@ GetGCThingMarkBitmap(const uintptr_t addr)
|
|||||||
return reinterpret_cast<uintptr_t*>(bmap_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
|
static MOZ_ALWAYS_INLINE void
|
||||||
GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color,
|
GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color,
|
||||||
uintptr_t** wordp, uintptr_t* maskp)
|
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
|
static MOZ_ALWAYS_INLINE bool
|
||||||
CellIsMarkedGray(const Cell* cell)
|
CellIsMarkedGray(const Cell* cell)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(cell);
|
MOZ_ASSERT(cell);
|
||||||
if (js::gc::IsInsideNursery(cell))
|
MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
|
||||||
return false;
|
|
||||||
|
|
||||||
uintptr_t* word, mask;
|
uintptr_t* word, mask;
|
||||||
js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), js::gc::GRAY, &word, &mask);
|
js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), js::gc::GRAY, &word, &mask);
|
||||||
return *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 */
|
} /* namespace detail */
|
||||||
|
|
||||||
MOZ_ALWAYS_INLINE bool
|
MOZ_ALWAYS_INLINE bool
|
||||||
@ -370,9 +359,11 @@ GetObjectZone(JSObject* obj);
|
|||||||
static MOZ_ALWAYS_INLINE bool
|
static MOZ_ALWAYS_INLINE bool
|
||||||
GCThingIsMarkedGray(GCCellPtr thing)
|
GCThingIsMarkedGray(GCCellPtr thing)
|
||||||
{
|
{
|
||||||
|
if (js::gc::IsInsideNursery(thing.asCell()))
|
||||||
|
return false;
|
||||||
if (thing.mayBeOwnedByOtherRuntime())
|
if (thing.mayBeOwnedByOtherRuntime())
|
||||||
return false;
|
return false;
|
||||||
return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell());
|
return js::gc::detail::CellIsMarkedGray(thing.asCell());
|
||||||
}
|
}
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JS::TraceKind)
|
extern JS_PUBLIC_API(JS::TraceKind)
|
||||||
|
@ -309,8 +309,14 @@ ObjectIsTenured(const Heap<JSObject*>& obj)
|
|||||||
static MOZ_ALWAYS_INLINE bool
|
static MOZ_ALWAYS_INLINE bool
|
||||||
ObjectIsMarkedGray(JSObject* obj)
|
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
|
static MOZ_ALWAYS_INLINE bool
|
||||||
@ -322,8 +328,7 @@ ObjectIsMarkedGray(const JS::Heap<JSObject*>& obj)
|
|||||||
static MOZ_ALWAYS_INLINE bool
|
static MOZ_ALWAYS_INLINE bool
|
||||||
ScriptIsMarkedGray(JSScript* script)
|
ScriptIsMarkedGray(JSScript* script)
|
||||||
{
|
{
|
||||||
auto cell = reinterpret_cast<js::gc::Cell*>(script);
|
return js::gc::detail::CellIsMarkedGray(reinterpret_cast<js::gc::Cell*>(script));
|
||||||
return js::gc::detail::CellIsMarkedGrayIfKnown(cell);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE bool
|
static MOZ_ALWAYS_INLINE bool
|
||||||
|
@ -816,6 +816,9 @@ class GCRuntime
|
|||||||
bool isFullGc() const { return isFull; }
|
bool isFullGc() const { return isFull; }
|
||||||
bool isCompactingGc() const { return isCompacting; }
|
bool isCompactingGc() const { return isCompacting; }
|
||||||
|
|
||||||
|
bool areGrayBitsValid() const { return grayBitsValid; }
|
||||||
|
void setGrayBitsInvalid() { grayBitsValid = false; }
|
||||||
|
|
||||||
bool minorGCRequested() const { return minorGCTriggerReason != JS::gcreason::NO_REASON; }
|
bool minorGCRequested() const { return minorGCTriggerReason != JS::gcreason::NO_REASON; }
|
||||||
bool majorGCRequested() const { return majorGCTriggerReason != JS::gcreason::NO_REASON; }
|
bool majorGCRequested() const { return majorGCTriggerReason != JS::gcreason::NO_REASON; }
|
||||||
bool isGcNeeded() { return minorGCRequested() || majorGCRequested(); }
|
bool isGcNeeded() { return minorGCRequested() || majorGCRequested(); }
|
||||||
@ -1127,6 +1130,12 @@ class GCRuntime
|
|||||||
resetBufferedGrayRoots();
|
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;
|
mozilla::Atomic<JS::gcreason::Reason, mozilla::Relaxed> majorGCTriggerReason;
|
||||||
|
|
||||||
JS::gcreason::Reason minorGCTriggerReason;
|
JS::gcreason::Reason minorGCTriggerReason;
|
||||||
|
@ -2917,7 +2917,7 @@ UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing)
|
|||||||
* If we run out of stack, we take a more drastic measure: require that
|
* If we run out of stack, we take a more drastic measure: require that
|
||||||
* we GC again before the next CC.
|
* we GC again before the next CC.
|
||||||
*/
|
*/
|
||||||
runtime()->setGCGrayBitsValid(false);
|
runtime()->gc.setGrayBitsInvalid();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ BEGIN_TEST(testGCCellPtr)
|
|||||||
JS::GCCellPtr copy = objcell;
|
JS::GCCellPtr copy = objcell;
|
||||||
CHECK(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -597,7 +597,7 @@ js::TraceWeakMaps(WeakMapTracer* trc)
|
|||||||
extern JS_FRIEND_API(bool)
|
extern JS_FRIEND_API(bool)
|
||||||
js::AreGCGrayBitsValid(JSContext* cx)
|
js::AreGCGrayBitsValid(JSContext* cx)
|
||||||
{
|
{
|
||||||
return cx->areGCGrayBitsValid();
|
return cx->gc.areGrayBitsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(bool)
|
JS_FRIEND_API(bool)
|
||||||
|
@ -823,6 +823,7 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
|
|||||||
numActiveZoneIters(0),
|
numActiveZoneIters(0),
|
||||||
cleanUpEverything(false),
|
cleanUpEverything(false),
|
||||||
grayBufferState(GCRuntime::GrayBufferState::Unused),
|
grayBufferState(GCRuntime::GrayBufferState::Unused),
|
||||||
|
grayBitsValid(false),
|
||||||
majorGCTriggerReason(JS::gcreason::NO_REASON),
|
majorGCTriggerReason(JS::gcreason::NO_REASON),
|
||||||
minorGCTriggerReason(JS::gcreason::NO_REASON),
|
minorGCTriggerReason(JS::gcreason::NO_REASON),
|
||||||
fullGCForAtomsRequested_(false),
|
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 we finished a full GC, then the gray bits are correct. */
|
||||||
if (isFull)
|
if (isFull)
|
||||||
rt->setGCGrayBitsValid(true);
|
grayBitsValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
finishMarkingValidation();
|
finishMarkingValidation();
|
||||||
|
@ -187,16 +187,11 @@ struct Runtime
|
|||||||
|
|
||||||
js::gc::StoreBuffer* gcStoreBufferPtr_;
|
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:
|
public:
|
||||||
Runtime()
|
Runtime()
|
||||||
: heapState_(JS::HeapState::Idle)
|
: heapState_(JS::HeapState::Idle)
|
||||||
, allowGCBarriers_(true)
|
, allowGCBarriers_(true)
|
||||||
, gcStoreBufferPtr_(nullptr)
|
, gcStoreBufferPtr_(nullptr)
|
||||||
, gcGrayBitsValid_(false)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool isHeapBusy() const { return heapState() != JS::HeapState::Idle; }
|
bool isHeapBusy() const { return heapState() != JS::HeapState::Idle; }
|
||||||
@ -212,9 +207,6 @@ struct Runtime
|
|||||||
|
|
||||||
js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; }
|
js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; }
|
||||||
|
|
||||||
bool areGCGrayBitsValid() const { return gcGrayBitsValid_; }
|
|
||||||
void setGCGrayBitsValid(bool valid) { gcGrayBitsValid_ = valid; }
|
|
||||||
|
|
||||||
const JSRuntime* asRuntime() const {
|
const JSRuntime* asRuntime() const {
|
||||||
return reinterpret_cast<const JSRuntime*>(this);
|
return reinterpret_cast<const JSRuntime*>(this);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user