Remove remaining conditional GCZeal code.

Creates stubs:
jsgc.h/cpp
VerifyBarriers() stub
MaybeVerifyBarriers() stub
GCRuntime::computeNonIncrementalMarkingForValidation() stub
GCRuntime::validateIncrementalMarking() stub
GCRuntime::finishMarkingValidation() stub
GCRuntime::pushZealSelectedObjects() stub
bool useZeal?
GCRuntime::runDebugGC() stub
XPConnect:
nsXPCComponents_Utils::SetGCZeal() stub (always NS_OK)
This commit is contained in:
wolfbeast 2017-06-26 22:20:37 +02:00 committed by Roy Tam
commit b5de790f2a
20 changed files with 4 additions and 832 deletions

View file

@ -231,21 +231,6 @@ GC(JSContext *cx,
return true;
}
#ifdef JS_GC_ZEAL
static bool
GCZeal(JSContext *cx, unsigned argc, JS::Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
uint32_t zeal;
if (!ToUint32(cx, args.get(0), &zeal))
return false;
JS_SetGCZeal(cx, uint8_t(zeal), JS_DEFAULT_ZEAL_FREQ);
return true;
}
#endif
const JSFunctionSpec gGlobalFunctions[] =
{
JS_FS("print", Print, 0,0),
@ -255,9 +240,6 @@ const JSFunctionSpec gGlobalFunctions[] =
JS_FS("dumpXPC", DumpXPC, 1,0),
JS_FS("dump", Dump, 1,0),
JS_FS("gc", GC, 0,0),
#ifdef JS_GC_ZEAL
JS_FS("gczeal", GCZeal, 1,0),
#endif
JS_FS_END
};

View file

@ -51,10 +51,6 @@ class CompileRuntime
// &runtime()->activation_
const void* addressOfActivation();
#ifdef JS_GC_ZEAL
const void* addressOfGCZealModeBits();
#endif
const void* addressOfInterruptUint32();
// We have to bake JSContext* into JIT code, but this pointer shouldn't be

View file

@ -627,11 +627,7 @@ PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index)
if (obj->is<NativeObject>() &&
!obj->as<NativeObject>().isInWholeCellBuffer() &&
uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength() &&
(obj->as<NativeObject>().getDenseInitializedLength() > MAX_WHOLE_CELL_BUFFER_SIZE
#ifdef JS_GC_ZEAL
|| rt->hasZealMode(gc::ZealMode::ElementsBarrier)
#endif
))
(obj->as<NativeObject>().getDenseInitializedLength() > MAX_WHOLE_CELL_BUFFER_SIZE))
{
rt->gc.storeBuffer.putSlot(&obj->as<NativeObject>(), HeapSlot::Element, index, 1);
return;

View file

@ -38,10 +38,6 @@
/* Define to 1 if SpiderMonkey should include ctypes support. */
#undef JS_HAS_CTYPES
/* Define to 1 if SpiderMonkey should support the ability to perform
entirely too much GC. */
#undef JS_GC_ZEAL
/* Define to 1 if SpiderMonkey should use small chunks. */
#undef JS_GC_SMALL_CHUNK_SIZE

View file

@ -94,36 +94,6 @@ BEGIN_TEST(testGCFinalizeCallback)
CHECK(checkFinalizeStatus());
CHECK(checkFinalizeIsZoneGC(true));
#ifdef JS_GC_ZEAL
/* Full GC with reset due to new zone, becoming zone GC. */
FinalizeCalls = 0;
JS_SetGCZeal(cx, 9, 1000000);
JS::PrepareForFullGC(cx);
js::SliceBudget budget(js::WorkBudget(1));
cx->gc.startDebugGC(GC_NORMAL, budget);
CHECK(cx->gc.state() == js::gc::State::Mark);
CHECK(cx->gc.isFullGc());
JS::RootedObject global4(cx, createTestGlobal());
budget = js::SliceBudget(js::WorkBudget(1));
cx->gc.debugGCSlice(budget);
while (cx->gc.isIncrementalGCInProgress())
cx->gc.debugGCSlice(budget);
CHECK(!cx->gc.isIncrementalGCInProgress());
CHECK(!cx->gc.isFullGc());
CHECK(checkMultipleGroups());
CHECK(checkFinalizeStatus());
for (unsigned i = 0; i < FinalizeCalls - 1; ++i)
CHECK(!IsZoneGCBuffer[i]);
CHECK(IsZoneGCBuffer[FinalizeCalls - 1]);
JS_SetGCZeal(cx, 0, 0);
#endif
/*
* Make some use of the globals here to ensure the compiler doesn't optimize
* them away in release builds, causing the zones to be collected and

View file

@ -40,10 +40,6 @@ JSFunction* CreateGCThing(JSContext* cx)
BEGIN_TEST(testGCHeapPostBarriers)
{
#ifdef JS_GC_ZEAL
AutoLeaveZeal nozeal(cx);
#endif /* JS_GC_ZEAL */
/* Sanity check - objects start in the nursery and then become tenured. */
JS_GC(cx);
JS::RootedObject obj(cx, CreateGCThing<JSObject>(cx));

View file

@ -101,10 +101,6 @@ class CCWTestTracer : public JS::CallbackTracer {
BEGIN_TEST(testTracingIncomingCCWs)
{
#ifdef JS_GC_ZEAL
// Disable zeal modes because this test needs to control exactly when the GC happens.
JS_SetGCZeal(cx, 0, 100);
#endif
JS_GC(cx);
JS::RootedObject global1(cx, JS::CurrentGlobalOrNull(cx));
@ -146,10 +142,6 @@ countWrappers(JSCompartment* comp)
BEGIN_TEST(testDeadNurseryCCW)
{
#ifdef JS_GC_ZEAL
// Disable zeal modes because this test needs to control exactly when the GC happens.
JS_SetGCZeal(cx, 0, 100);
#endif
JS_GC(cx);
JS::RootedObject global1(cx, JS::CurrentGlobalOrNull(cx));
@ -177,10 +169,6 @@ END_TEST(testDeadNurseryCCW)
BEGIN_TEST(testLiveNurseryCCW)
{
#ifdef JS_GC_ZEAL
// Disable zeal modes because this test needs to control exactly when the GC happens.
JS_SetGCZeal(cx, 0, 100);
#endif
JS_GC(cx);
JS::RootedObject global1(cx, JS::CurrentGlobalOrNull(cx));
@ -208,10 +196,6 @@ END_TEST(testLiveNurseryCCW)
BEGIN_TEST(testLiveNurseryWrapperCCW)
{
#ifdef JS_GC_ZEAL
// Disable zeal modes because this test needs to control exactly when the GC happens.
JS_SetGCZeal(cx, 0, 100);
#endif
JS_GC(cx);
JS::RootedObject global1(cx, JS::CurrentGlobalOrNull(cx));
@ -244,10 +228,6 @@ END_TEST(testLiveNurseryWrapperCCW)
BEGIN_TEST(testLiveNurseryWrappeeCCW)
{
#ifdef JS_GC_ZEAL
// Disable zeal modes because this test needs to control exactly when the GC happens.
JS_SetGCZeal(cx, 0, 100);
#endif
JS_GC(cx);
JS::RootedObject global1(cx, JS::CurrentGlobalOrNull(cx));
@ -280,11 +260,6 @@ BEGIN_TEST(testIncrementalRoots)
{
JSRuntime* rt = cx->runtime();
#ifdef JS_GC_ZEAL
// Disable zeal modes because this test needs to control exactly when the GC happens.
JS_SetGCZeal(cx, 0, 100);
#endif
// Construct a big object graph to mark. In JS, the resulting object graph
// is equivalent to:
//

View file

@ -23,10 +23,6 @@ MinimizeHeap(JSContext* cx)
BEGIN_TEST(testGCUID)
{
#ifdef JS_GC_ZEAL
AutoLeaveZeal nozeal(cx);
#endif /* JS_GC_ZEAL */
uint64_t uid = 0;
uint64_t tmp = 0;

View file

@ -418,39 +418,4 @@ class TestJSPrincipals : public JSPrincipals
}
};
#ifdef JS_GC_ZEAL
/*
* Temporarily disable the GC zeal setting. This is only useful in tests that
* need very explicit GC behavior and should not be used elsewhere.
*/
class AutoLeaveZeal
{
JSContext* cx_;
uint32_t zealBits_;
uint32_t frequency_;
public:
explicit AutoLeaveZeal(JSContext* cx) : cx_(cx) {
uint32_t dummy;
JS_GetGCZealBits(cx_, &zealBits_, &frequency_, &dummy);
JS_SetGCZeal(cx_, 0, 0);
JS::PrepareForFullGC(cx_);
JS::GCForReason(cx_, GC_SHRINK, JS::gcreason::DEBUG_GC);
}
~AutoLeaveZeal() {
for (size_t i = 0; i < sizeof(zealBits_) * 8; i++) {
if (zealBits_ & (1 << i))
JS_SetGCZeal(cx_, i, frequency_);
}
#ifdef DEBUG
uint32_t zealBitsAfter, frequencyAfter, dummy;
JS_GetGCZealBits(cx_, &zealBitsAfter, &frequencyAfter, &dummy);
MOZ_ASSERT(zealBitsAfter == zealBits_);
MOZ_ASSERT(frequencyAfter == frequency_);
#endif
}
};
#endif /* JS_GC_ZEAL */
#endif /* jsapi_tests_tests_h */

View file

@ -6263,26 +6263,6 @@ JS_AbortIfWrongThread(JSContext* cx)
MOZ_CRASH();
}
#ifdef JS_GC_ZEAL
JS_PUBLIC_API(void)
JS_GetGCZealBits(JSContext* cx, uint32_t* zealBits, uint32_t* frequency, uint32_t* nextScheduled)
{
cx->runtime()->gc.getZealBits(zealBits, frequency, nextScheduled);
}
JS_PUBLIC_API(void)
JS_SetGCZeal(JSContext* cx, uint8_t zeal, uint32_t frequency)
{
cx->gc.setZeal(zeal, frequency);
}
JS_PUBLIC_API(void)
JS_ScheduleGC(JSContext* cx, uint32_t count)
{
cx->runtime()->gc.setNextScheduled(count);
}
#endif
JS_PUBLIC_API(void)
JS_SetParallelParsingEnabled(JSContext* cx, bool enabled)
{

View file

@ -844,9 +844,6 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
arenasAllocatedDuringSweep(nullptr),
startedCompacting(false),
relocatedArenasToRelease(nullptr),
#ifdef JS_GC_ZEAL
markingValidator(nullptr),
#endif
interFrameGC(false),
defaultTimeBudget_(SliceBudget::UnlimitedTimeBudget),
incrementalAllowed(true),
@ -856,13 +853,6 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
manipulatingDeadZones(false),
objectsMarkedInDeadZones(0),
poked(false),
#ifdef JS_GC_ZEAL
zealModeBits(0),
zealFrequency(0),
nextScheduled(0),
deterministicOnly(false),
incrementalLimit(0),
#endif
fullCompartmentChecks(false),
mallocBytesUntilGC(0),
mallocGCTriggered(false),
@ -881,147 +871,6 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
setGCMode(JSGC_MODE_GLOBAL);
}
#ifdef JS_GC_ZEAL
void
GCRuntime::getZealBits(uint32_t* zealBits, uint32_t* frequency, uint32_t* scheduled)
{
*zealBits = zealModeBits;
*frequency = zealFrequency;
*scheduled = nextScheduled;
}
const char* gc::ZealModeHelpText =
" Specifies how zealous the garbage collector should be. Some of these modes can\n"
" be set simultaneously, by passing multiple level options, e.g. \"2;4\" will activate\n"
" both modes 2 and 4. Modes can be specified by name or number.\n"
" \n"
" Values:\n"
" 0: (None) Normal amount of collection (resets all modes)\n"
" 1: (Poke) Collect when roots are added or removed\n"
" 2: (Alloc) Collect when every N allocations (default: 100)\n"
" 3: (FrameGC) Collect when the window paints (browser only)\n"
" 4: (VerifierPre) Verify pre write barriers between instructions\n"
" 5: (FrameVerifierPre) Verify pre write barriers between paints\n"
" 6: (StackRooting) Verify stack rooting\n"
" 7: (GenerationalGC) Collect the nursery every N nursery allocations\n"
" 8: (IncrementalRootsThenFinish) Incremental GC in two slices: 1) mark roots 2) finish collection\n"
" 9: (IncrementalMarkAllThenFinish) Incremental GC in two slices: 1) mark all 2) new marking and finish\n"
" 10: (IncrementalMultipleSlices) Incremental GC in multiple slices\n"
" 11: (IncrementalMarkingValidator) Verify incremental marking\n"
" 12: (ElementsBarrier) Always use the individual element post-write barrier, regardless of elements size\n"
" 13: (CheckHashTablesOnMinorGC) Check internal hashtables on minor GC\n"
" 14: (Compact) Perform a shrinking collection every N allocations\n"
" 15: (CheckHeapAfterGC) Walk the heap to check its integrity after every GC\n"
" 16: (CheckNursery) Check nursery integrity on minor GC\n";
void
GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
{
MOZ_ASSERT(zeal <= unsigned(ZealMode::Limit));
if (verifyPreData)
VerifyBarriers(rt, PreBarrierVerifier);
if (zeal == 0 && hasZealMode(ZealMode::GenerationalGC)) {
evictNursery(JS::gcreason::DEBUG_GC);
nursery.leaveZealMode();
}
ZealMode zealMode = ZealMode(zeal);
if (zealMode == ZealMode::GenerationalGC)
nursery.enterZealMode();
// Zeal modes 8-10 are mutually exclusive. If we're setting one of those,
// we first reset all of them.
if (zealMode >= ZealMode::IncrementalRootsThenFinish &&
zealMode <= ZealMode::IncrementalMultipleSlices)
{
clearZealMode(ZealMode::IncrementalRootsThenFinish);
clearZealMode(ZealMode::IncrementalMarkAllThenFinish);
clearZealMode(ZealMode::IncrementalMultipleSlices);
}
bool schedule = zealMode >= ZealMode::Alloc;
if (zeal != 0)
zealModeBits |= 1 << unsigned(zeal);
else
zealModeBits = 0;
zealFrequency = frequency;
nextScheduled = schedule ? frequency : 0;
}
void
GCRuntime::setNextScheduled(uint32_t count)
{
nextScheduled = count;
}
bool
GCRuntime::parseAndSetZeal(const char* str)
{
int frequency = -1;
bool foundFrequency = false;
mozilla::Vector<int, 0, SystemAllocPolicy> zeals;
static const struct {
const char* const zealMode;
size_t length;
uint32_t zeal;
} zealModes[] = {
#define ZEAL_MODE(name, value) {#name, sizeof(#name) - 1, value},
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
#undef ZEAL_MODE
{"None", 4, 0}
};
do {
int zeal = -1;
const char* p = nullptr;
if (isdigit(str[0])) {
zeal = atoi(str);
size_t offset = strspn(str, "0123456789");
p = str + offset;
} else {
for (auto z : zealModes) {
if (!strncmp(str, z.zealMode, z.length)) {
zeal = z.zeal;
p = str + z.length;
break;
}
}
}
if (p) {
if (!*p || *p == ';') {
frequency = JS_DEFAULT_ZEAL_FREQ;
} else if (*p == ',') {
frequency = atoi(p + 1);
foundFrequency = true;
}
}
if (zeal < 0 || zeal > int(ZealMode::Limit) || frequency <= 0) {
fprintf(stderr, "Format: JS_GC_ZEAL=level(;level)*[,N]\n");
fputs(ZealModeHelpText, stderr);
return false;
}
if (!zeals.emplaceBack(zeal)) {
return false;
}
} while (!foundFrequency &&
(str = strchr(str, ';')) != nullptr &&
str++);
for (auto z : zeals)
setZeal(z, frequency);
return true;
}
#endif
/*
* Lifetime in number of major GCs for type sets attached to scripts containing
* observed types.
@ -1063,12 +912,6 @@ GCRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
}
}
#ifdef JS_GC_ZEAL
const char* zealSpec = getenv("JS_GC_ZEAL");
if (zealSpec && zealSpec[0] && !parseAndSetZeal(zealSpec))
return false;
#endif
if (!InitTrace(*this))
return false;
@ -1094,11 +937,6 @@ GCRuntime::finish()
allocTask.cancel(GCParallelTask::CancelAndWait);
decommitTask.cancel(GCParallelTask::CancelAndWait);
#ifdef JS_GC_ZEAL
/* Free memory associated with GC verification. */
finishVerifier();
#endif
/* Delete all remaining zones. */
if (rt->gcInitialized) {
AutoSetThreadIsSweeping threadIsSweeping;
@ -2635,7 +2473,7 @@ GCRuntime::releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, const AutoLo
// Mark arena as empty
arena->setAsFullyUnused();
#if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL)
#if defined(JS_CRASH_DIAGNOSTICS)
JS_POISON(reinterpret_cast<void*>(arena->thingsStart()),
JS_MOVED_TENURED_PATTERN, arena->getThingsSpan());
#endif
@ -3048,13 +2886,6 @@ GCRuntime::triggerZoneGC(Zone* zone, JS::gcreason::Reason reason)
if (rt->isHeapCollecting())
return false;
#ifdef JS_GC_ZEAL
if (hasZealMode(ZealMode::Alloc)) {
MOZ_RELEASE_ASSERT(triggerGC(reason));
return true;
}
#endif
if (zone->isAtomsZone()) {
/* We can't do a zone GC of the atoms compartment. */
if (rt->keepAtoms()) {
@ -3077,14 +2908,6 @@ GCRuntime::maybeGC(Zone* zone)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
#ifdef JS_GC_ZEAL
if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::Poke)) {
JS::PrepareForFullGC(rt->contextFromMainThread());
gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
return;
}
#endif
if (gcIfRequested())
return;
@ -3418,11 +3241,6 @@ GCRuntime::shouldReleaseObservedTypes()
{
bool releaseTypes = false;
#ifdef JS_GC_ZEAL
if (zealModeBits != 0)
releaseTypes = true;
#endif
/* We may miss the exact target GC due to resets. */
if (majorGCNumber >= jitReleaseNumber)
releaseTypes = true;
@ -4068,290 +3886,19 @@ GCRuntime::markAllGrayReferences(gcstats::Phase phase)
markGrayReferences<GCZonesIter, GCCompartmentsIter>(phase);
}
#ifdef JS_GC_ZEAL
struct GCChunkHasher {
typedef gc::Chunk* Lookup;
/*
* Strip zeros for better distribution after multiplying by the golden
* ratio.
*/
static HashNumber hash(gc::Chunk* chunk) {
MOZ_ASSERT(!(uintptr_t(chunk) & gc::ChunkMask));
return HashNumber(uintptr_t(chunk) >> gc::ChunkShift);
}
static bool match(gc::Chunk* k, gc::Chunk* l) {
MOZ_ASSERT(!(uintptr_t(k) & gc::ChunkMask));
MOZ_ASSERT(!(uintptr_t(l) & gc::ChunkMask));
return k == l;
}
};
class js::gc::MarkingValidator
{
public:
explicit MarkingValidator(GCRuntime* gc);
~MarkingValidator();
void nonIncrementalMark(AutoLockForExclusiveAccess& lock);
void validate();
private:
GCRuntime* gc;
bool initialized;
typedef HashMap<Chunk*, ChunkBitmap*, GCChunkHasher, SystemAllocPolicy> BitmapMap;
BitmapMap map;
};
js::gc::MarkingValidator::MarkingValidator(GCRuntime* gc)
: gc(gc),
initialized(false)
{}
js::gc::MarkingValidator::~MarkingValidator()
{
if (!map.initialized())
return;
for (BitmapMap::Range r(map.all()); !r.empty(); r.popFront())
js_delete(r.front().value());
}
void
js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock)
{
/*
* Perform a non-incremental mark for all collecting zones and record
* the results for later comparison.
*
* Currently this does not validate gray marking.
*/
if (!map.init())
return;
JSRuntime* runtime = gc->rt;
GCMarker* gcmarker = &gc->marker;
gc->waitBackgroundSweepEnd();
/* Save existing mark bits. */
for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) {
ChunkBitmap* bitmap = &chunk->bitmap;
ChunkBitmap* entry = js_new<ChunkBitmap>();
if (!entry)
return;
memcpy((void*)entry->bitmap, (void*)bitmap->bitmap, sizeof(bitmap->bitmap));
if (!map.putNew(chunk, entry))
return;
}
/*
* Temporarily clear the weakmaps' mark flags for the compartments we are
* collecting.
*/
WeakMapSet markedWeakMaps;
if (!markedWeakMaps.init())
return;
/*
* For saving, smush all of the keys into one big table and split them back
* up into per-zone tables when restoring.
*/
gc::WeakKeyTable savedWeakKeys(SystemAllocPolicy(), runtime->randomHashCodeScrambler());
if (!savedWeakKeys.init())
return;
for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
if (!WeakMapBase::saveZoneMarkedWeakMaps(zone, markedWeakMaps))
return;
AutoEnterOOMUnsafeRegion oomUnsafe;
for (gc::WeakKeyTable::Range r = zone->gcWeakKeys.all(); !r.empty(); r.popFront()) {
if (!savedWeakKeys.put(Move(r.front().key), Move(r.front().value)))
oomUnsafe.crash("saving weak keys table for validator");
}
if (!zone->gcWeakKeys.clear())
oomUnsafe.crash("clearing weak keys table for validator");
}
/*
* After this point, the function should run to completion, so we shouldn't
* do anything fallible.
*/
initialized = true;
/* Re-do all the marking, but non-incrementally. */
js::gc::State state = gc->incrementalState;
gc->incrementalState = State::MarkRoots;
{
gcstats::AutoPhase ap(gc->stats, gcstats::PHASE_MARK);
{
gcstats::AutoPhase ap(gc->stats, gcstats::PHASE_UNMARK);
for (GCZonesIter zone(runtime); !zone.done(); zone.next())
WeakMapBase::unmarkZone(zone);
MOZ_ASSERT(gcmarker->isDrained());
gcmarker->reset();
for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next())
chunk->bitmap.clear();
}
gc->traceRuntimeForMajorGC(gcmarker, lock);
gc->incrementalState = State::Mark;
auto unlimited = SliceBudget::unlimited();
MOZ_RELEASE_ASSERT(gc->marker.drainMarkStack(unlimited));
}
gc->incrementalState = State::Sweep;
{
gcstats::AutoPhase ap1(gc->stats, gcstats::PHASE_SWEEP);
gcstats::AutoPhase ap2(gc->stats, gcstats::PHASE_SWEEP_MARK);
gc->markAllWeakReferences(gcstats::PHASE_SWEEP_MARK_WEAK);
/* Update zone state for gray marking. */
for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
MOZ_ASSERT(zone->isGCMarkingBlack());
zone->setGCState(Zone::MarkGray);
}
gc->marker.setMarkColorGray();
gc->markAllGrayReferences(gcstats::PHASE_SWEEP_MARK_GRAY);
gc->markAllWeakReferences(gcstats::PHASE_SWEEP_MARK_GRAY_WEAK);
/* Restore zone state. */
for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
MOZ_ASSERT(zone->isGCMarkingGray());
zone->setGCState(Zone::Mark);
}
MOZ_ASSERT(gc->marker.isDrained());
gc->marker.setMarkColorBlack();
}
/* Take a copy of the non-incremental mark state and restore the original. */
for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) {
ChunkBitmap* bitmap = &chunk->bitmap;
ChunkBitmap* entry = map.lookup(chunk)->value();
Swap(*entry, *bitmap);
}
for (GCZonesIter zone(runtime); !zone.done(); zone.next()) {
WeakMapBase::unmarkZone(zone);
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!zone->gcWeakKeys.clear())
oomUnsafe.crash("clearing weak keys table for validator");
}
WeakMapBase::restoreMarkedWeakMaps(markedWeakMaps);
for (gc::WeakKeyTable::Range r = savedWeakKeys.all(); !r.empty(); r.popFront()) {
AutoEnterOOMUnsafeRegion oomUnsafe;
Zone* zone = gc::TenuredCell::fromPointer(r.front().key.asCell())->zone();
if (!zone->gcWeakKeys.put(Move(r.front().key), Move(r.front().value)))
oomUnsafe.crash("restoring weak keys table for validator");
}
gc->incrementalState = state;
}
void
js::gc::MarkingValidator::validate()
{
/*
* Validates the incremental marking for a single compartment by comparing
* the mark bits to those previously recorded for a non-incremental mark.
*/
if (!initialized)
return;
gc->waitBackgroundSweepEnd();
for (auto chunk = gc->allNonEmptyChunks(); !chunk.done(); chunk.next()) {
BitmapMap::Ptr ptr = map.lookup(chunk);
if (!ptr)
continue; /* Allocated after we did the non-incremental mark. */
ChunkBitmap* bitmap = ptr->value();
ChunkBitmap* incBitmap = &chunk->bitmap;
for (size_t i = 0; i < ArenasPerChunk; i++) {
if (chunk->decommittedArenas.get(i))
continue;
Arena* arena = &chunk->arenas[i];
if (!arena->allocated())
continue;
if (!arena->zone->isGCSweeping())
continue;
if (arena->allocatedDuringIncremental)
continue;
AllocKind kind = arena->getAllocKind();
uintptr_t thing = arena->thingsStart();
uintptr_t end = arena->thingsEnd();
while (thing < end) {
Cell* cell = (Cell*)thing;
/*
* If a non-incremental GC wouldn't have collected a cell, then
* an incremental GC won't collect it.
*/
MOZ_ASSERT_IF(bitmap->isMarked(cell, BLACK), incBitmap->isMarked(cell, BLACK));
/*
* If the cycle collector isn't allowed to collect an object
* after a non-incremental GC has run, then it isn't allowed to
* collected it after an incremental GC.
*/
MOZ_ASSERT_IF(!bitmap->isMarked(cell, GRAY), !incBitmap->isMarked(cell, GRAY));
thing += Arena::thingSize(kind);
}
}
}
}
#endif // JS_GC_ZEAL
void
GCRuntime::computeNonIncrementalMarkingForValidation(AutoLockForExclusiveAccess& lock)
{
#ifdef JS_GC_ZEAL
MOZ_ASSERT(!markingValidator);
if (isIncremental && hasZealMode(ZealMode::IncrementalMarkingValidator))
markingValidator = js_new<MarkingValidator>(this);
if (markingValidator)
markingValidator->nonIncrementalMark(lock);
#endif
}
void
GCRuntime::validateIncrementalMarking()
{
#ifdef JS_GC_ZEAL
if (markingValidator)
markingValidator->validate();
#endif
}
void
GCRuntime::finishMarkingValidation()
{
#ifdef JS_GC_ZEAL
js_delete(markingValidator);
markingValidator = nullptr;
#endif
}
static void
@ -5785,11 +5332,6 @@ AutoGCSlice::~AutoGCSlice()
void
GCRuntime::pushZealSelectedObjects()
{
#ifdef JS_GC_ZEAL
/* Push selected objects onto the mark stack and clear the list. */
for (JSObject** obj = selectedForMarking.begin(); obj != selectedForMarking.end(); obj++)
TraceManuallyBarrieredEdge(&marker, obj, "selected obj");
#endif
}
static bool
@ -5818,16 +5360,6 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
gc::State initialState = incrementalState;
bool useZeal = false;
#ifdef JS_GC_ZEAL
if (reason == JS::gcreason::DEBUG_GC && !budget.isUnlimited()) {
/*
* Do the incremental collection type specified by zeal mode if the
* collection was triggered by runDebugGC() and incremental GC has not
* been cancelled by resetIncrementalGC().
*/
useZeal = true;
}
#endif
MOZ_ASSERT_IF(isIncrementalGCInProgress(), isIncremental);
isIncremental = !budget.isUnlimited();
@ -6202,11 +5734,6 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
chunkAllocationSinceLastGC = false;
#ifdef JS_GC_ZEAL
/* Keeping these around after a GC is dangerous. */
clearSelectedForMarking();
#endif
/* Clear gcMallocBytes for all zones. */
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
zone->resetGCMallocBytes();
@ -6218,23 +5745,6 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
return false;
}
#ifdef JS_GC_ZEAL
static bool
IsDeterministicGCReason(JS::gcreason::Reason reason)
{
if (reason > JS::gcreason::DEBUG_GC &&
reason != JS::gcreason::CC_FORCED && reason != JS::gcreason::SHUTDOWN_CC)
{
return false;
}
if (reason == JS::gcreason::EAGER_ALLOC_TRIGGER)
return false;
return true;
}
#endif
gcstats::ZoneGCStats
GCRuntime::scanZonesBeforeGC()
{
@ -6300,11 +5810,6 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason)
if (rt->isBeingDestroyed() && !IsShutdownGC(reason))
return false;
#ifdef JS_GC_ZEAL
if (deterministicOnly && !IsDeterministicGCReason(reason))
return false;
#endif
return true;
}
@ -6360,13 +5865,6 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
if (reason == JS::gcreason::COMPARTMENT_REVIVED)
maybeDoCycleCollection();
#ifdef JS_GC_ZEAL
if (rt->hasZealMode(ZealMode::CheckHeapAfterGC)) {
gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_TRACE_HEAP);
CheckHeapAfterGC(rt);
}
#endif
}
js::AutoEnqueuePendingParseTasksAfterGC::~AutoEnqueuePendingParseTasksAfterGC()
@ -6460,17 +5958,6 @@ GCRuntime::notifyDidPaint()
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
#ifdef JS_GC_ZEAL
if (hasZealMode(ZealMode::FrameVerifierPre))
verifyPreBarriers();
if (hasZealMode(ZealMode::FrameGC)) {
JS::PrepareForFullGC(rt->contextFromMainThread());
gc(GC_NORMAL, JS::gcreason::REFRESH_FRAME);
return;
}
#endif
if (isIncrementalGCInProgress() && !interFrameGC && tunables.areRefreshFrameSlicesEnabled()) {
JS::PrepareForIncrementalGC(rt->contextFromMainThread());
gcSlice(JS::gcreason::REFRESH_FRAME);
@ -6566,11 +6053,6 @@ GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::Phase phase)
blocksToFreeAfterMinorGC.freeAll();
#ifdef JS_GC_ZEAL
if (rt->hasZealMode(ZealMode::CheckHeapAfterGC))
CheckHeapAfterGC(rt);
#endif
{
AutoLockGC lock(rt);
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
@ -6756,59 +6238,6 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target)
void
GCRuntime::runDebugGC()
{
#ifdef JS_GC_ZEAL
if (rt->mainThread.suppressGC)
return;
if (hasZealMode(ZealMode::GenerationalGC))
return minorGC(JS::gcreason::DEBUG_GC);
PrepareForDebugGC(rt);
auto budget = SliceBudget::unlimited();
if (hasZealMode(ZealMode::IncrementalRootsThenFinish) ||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish) ||
hasZealMode(ZealMode::IncrementalMultipleSlices))
{
js::gc::State initialState = incrementalState;
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
/*
* Start with a small slice limit and double it every slice. This
* ensure that we get multiple slices, and collection runs to
* completion.
*/
if (!isIncrementalGCInProgress())
incrementalLimit = zealFrequency / 2;
else
incrementalLimit *= 2;
budget = SliceBudget(WorkBudget(incrementalLimit));
} else {
// This triggers incremental GC but is actually ignored by IncrementalMarkSlice.
budget = SliceBudget(WorkBudget(1));
}
if (!isIncrementalGCInProgress())
invocationKind = GC_SHRINK;
collect(false, budget, JS::gcreason::DEBUG_GC);
/*
* For multi-slice zeal, reset the slice size when we get to the sweep
* or compact phases.
*/
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
if ((initialState == State::Mark && incrementalState == State::Sweep) ||
(initialState == State::Sweep && incrementalState == State::Compact))
{
incrementalLimit = zealFrequency / 2;
}
}
} else if (hasZealMode(ZealMode::Compact)) {
gc(GC_SHRINK, JS::gcreason::DEBUG_GC);
} else {
gc(GC_NORMAL, JS::gcreason::DEBUG_GC);
}
#endif
}
void
@ -6818,28 +6247,6 @@ GCRuntime::setFullCompartmentChecks(bool enabled)
fullCompartmentChecks = enabled;
}
#ifdef JS_GC_ZEAL
bool
GCRuntime::selectForMarking(JSObject* object)
{
MOZ_ASSERT(!rt->isHeapMajorCollecting());
return selectedForMarking.append(object);
}
void
GCRuntime::clearSelectedForMarking()
{
selectedForMarking.clearAndFree();
}
void
GCRuntime::setDeterministic(bool enabled)
{
MOZ_ASSERT(!rt->isHeapMajorCollecting());
deterministicOnly = enabled;
}
#endif
#ifdef DEBUG
/* Should only be called manually under gdb */

View file

@ -1264,19 +1264,6 @@ enum VerifierType {
PreBarrierVerifier
};
#ifdef JS_GC_ZEAL
extern const char* ZealModeHelpText;
/* Check that write barriers have been used correctly. See jsgc.cpp. */
void
VerifyBarriers(JSRuntime* rt, VerifierType type);
void
MaybeVerifyBarriers(JSContext* cx, bool always = false);
#else
static inline void
VerifyBarriers(JSRuntime* rt, VerifierType type)
{
@ -1287,8 +1274,6 @@ MaybeVerifyBarriers(JSContext* cx, bool always = false)
{
}
#endif
/*
* Instances of this class set the |JSRuntime::suppressGC| flag for the duration
* that they are live. Use of this class is highly discouraged. Please carefully

View file

@ -22,7 +22,7 @@
#include "js/TraceKind.h"
#include "js/TypeDecls.h"
#if defined(JS_GC_ZEAL) || defined(DEBUG)
#if defined(DEBUG)
# define JSGC_HASH_TABLE_CHECKS
#endif

View file

@ -368,7 +368,7 @@ Poison(void* ptr, uint8_t value, size_t num)
#endif
/* Enable poisoning in crash-diagnostics and zeal builds. */
#if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL)
#if defined(JS_CRASH_DIAGNOSTICS)
# define JS_POISON(p, val, size) Poison(p, val, size)
#else
# define JS_POISON(p, val, size) ((void) 0)

View file

@ -1805,17 +1805,6 @@ if test -n "$MOZ_DEBUG"; then
AC_DEFINE(JS_DEBUG)
fi
dnl ========================================================
dnl Zealous JavaScript GC
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(gczeal,
[ --enable-gczeal Enable zealous GCing],
JS_GC_ZEAL=1,
JS_GC_ZEAL= )
if test -n "$JS_GC_ZEAL" -o -n "$MOZ_DEBUG"; then
AC_DEFINE(JS_GC_ZEAL)
fi
dnl ========================================================
dnl Enable breakpoint for artificial OOMs
dnl ========================================================

View file

@ -323,10 +323,6 @@ static bool enableNativeRegExp = false;
static bool enableUnboxedArrays = false;
static bool enableSharedMemory = SHARED_MEMORY_DEFAULT;
static bool enableWasmAlwaysBaseline = false;
#ifdef JS_GC_ZEAL
static uint32_t gZealBits = 0;
static uint32_t gZealFrequency = 0;
#endif
static bool printTiming = false;
static const char* jsCacheDir = nullptr;
static const char* jsCacheAsmJSPath = nullptr;
@ -7517,16 +7513,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
dumpEntrainedVariables = op.getBoolOption("dump-entrained-variables");
#endif
#ifdef JS_GC_ZEAL
const char* zealStr = op.getStringOption("gc-zeal");
if (zealStr) {
if (!cx->gc.parseAndSetZeal(zealStr))
return false;
uint32_t nextScheduled;
cx->gc.getZealBits(&gZealBits, &gZealFrequency, &nextScheduled);
}
#endif
return true;
}
@ -7544,16 +7530,6 @@ SetWorkerContextOptions(JSContext* cx)
cx->setOffthreadIonCompilationEnabled(offthreadCompilation);
cx->profilingScripts = enableCodeCoverage || enableDisassemblyDumps;
#ifdef JS_GC_ZEAL
if (gZealBits && gZealFrequency) {
#define ZEAL_MODE(_, value) \
if (gZealBits & (1 << value)) \
cx->gc.setZeal(value, gZealFrequency);
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
#undef ZEAL_MODE
}
#endif
JS_SetNativeStackQuota(cx, gMaxStackSize);
}
@ -7838,9 +7814,6 @@ main(int argc, char** argv, char** envp)
"NUMBER of instructions.", -1)
#endif
|| !op.addIntOption('\0', "nursery-size", "SIZE-MB", "Set the maximum nursery size in MB", 16)
#ifdef JS_GC_ZEAL
|| !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", gc::ZealModeHelpText)
#endif
|| !op.addStringOption('\0', "module-load-path", "DIR", "Set directory to load modules from")
)
{

View file

@ -930,9 +930,6 @@ class DebugEnvironments
void mark(JSTracer* trc);
void sweep(JSRuntime* rt);
void finish();
#ifdef JS_GC_ZEAL
void checkHashTablesAfterMovingGC(JSRuntime* rt);
#endif
// If a live frame has a synthesized entry in missingEnvs, make sure it's not
// collected.

View file

@ -3007,9 +3007,6 @@ GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Ion, ion, setIon)
NS_IMETHODIMP
nsXPCComponents_Utils::SetGCZeal(int32_t aValue, JSContext* cx)
{
#ifdef JS_GC_ZEAL
JS_SetGCZeal(cx, uint8_t(aValue), JS_DEFAULT_ZEAL_FREQ);
#endif
return NS_OK;
}

View file

@ -1473,16 +1473,6 @@ ReloadPrefsCallback(const char* pref, void* data)
sExtraWarningsForSystemJS = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict.debug");
#endif
#ifdef JS_GC_ZEAL
int32_t zeal = Preferences::GetInt(JS_OPTIONS_DOT_STR "gczeal", -1);
int32_t zeal_frequency =
Preferences::GetInt(JS_OPTIONS_DOT_STR "gczeal.frequency",
JS_DEFAULT_ZEAL_FREQ);
if (zeal >= 0) {
JS_SetGCZeal(cx, (uint8_t)zeal, zeal_frequency);
}
#endif // JS_GC_ZEAL
JS::ContextOptionsRef(cx).setBaseline(useBaseline)
.setIon(useIon)
.setAsmJS(useAsmJS)

View file

@ -440,21 +440,6 @@ GC(JSContext* cx, unsigned argc, Value* vp)
return true;
}
#ifdef JS_GC_ZEAL
static bool
GCZeal(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
uint32_t zeal;
if (!ToUint32(cx, args.get(0), &zeal))
return false;
JS_SetGCZeal(cx, uint8_t(zeal), JS_DEFAULT_ZEAL_FREQ);
args.rval().setUndefined();
return true;
}
#endif
static bool
SendCommand(JSContext* cx, unsigned argc, Value* vp)
{
@ -652,9 +637,6 @@ static const JSFunctionSpec glob_functions[] = {
JS_FS("dumpXPC", DumpXPC, 1,0),
JS_FS("dump", Dump, 1,0),
JS_FS("gc", GC, 0,0),
#ifdef JS_GC_ZEAL
JS_FS("gczeal", GCZeal, 1,0),
#endif
JS_FS("options", Options, 0,0),
JS_FS("sendCommand", SendCommand, 1,0),
JS_FS("atob", xpc::Atob, 1,0),