Bug 1655768 - Part 2: Remove MergeRealms. r=jonco

Differential Revision: https://phabricator.services.mozilla.com/D131374
This commit is contained in:
Tooru Fujisawa 2021-11-19 04:43:10 +00:00
Родитель b1241a3ef6
Коммит aab63687b4
17 изменённых файлов: 1 добавлений и 281 удалений

Просмотреть файл

@ -322,9 +322,6 @@ class ArenaLists {
MOZ_ALWAYS_INLINE TenuredCell* allocateFromFreeList(AllocKind thingKind);
/* Moves all arenas from |fromArenaLists| into |this|. */
void adoptArenas(ArenaLists* fromArenaLists, bool targetZoneIsCollecting);
inline void checkEmptyFreeLists();
inline void checkEmptyArenaLists();
inline void checkEmptyFreeList(AllocKind kind);

Просмотреть файл

@ -188,12 +188,6 @@ void AtomMarkingRuntime::markAtomValue(JSContext* cx, const Value& value) {
value.isBigInt());
}
void AtomMarkingRuntime::adoptMarkedAtoms(Zone* target, Zone* source) {
MOZ_ASSERT(CurrentThreadCanAccessZone(source));
MOZ_ASSERT(CurrentThreadCanAccessZone(target));
target->markedAtoms().bitwiseOrWith(source->markedAtoms());
}
#ifdef DEBUG
template <typename T>
bool AtomMarkingRuntime::atomIsMarked(Zone* zone, T* thing) {

Просмотреть файл

@ -70,9 +70,6 @@ class AtomMarkingRuntime {
void markId(JSContext* cx, jsid id);
void markAtomValue(JSContext* cx, const Value& value);
// Mark all atoms in |source| as being reachable within |target|.
void adoptMarkedAtoms(Zone* target, Zone* source);
#ifdef DEBUG
// Return whether |thing/id| is in the atom marking bitmap for |zone|.
template <typename T>

Просмотреть файл

@ -1903,19 +1903,6 @@ void Compartment::sweepRealms(JSFreeOp* fop, bool keepAtleastOne,
MOZ_ASSERT_IF(destroyingRuntime, realms().empty());
}
void GCRuntime::deleteEmptyZone(Zone* zone) {
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
MOZ_ASSERT(zone->compartments().empty());
for (auto& i : zones()) {
if (i == zone) {
zones().erase(&i);
zone->destroy(rt->defaultFreeOp());
return;
}
}
MOZ_CRASH("Zone not found");
}
void GCRuntime::sweepZones(JSFreeOp* fop, bool destroyingRuntime) {
MOZ_ASSERT_IF(destroyingRuntime, numActiveZoneIters == 0);
@ -4204,115 +4191,6 @@ Realm* js::NewRealm(JSContext* cx, JSPrincipals* principals,
return realm.release();
}
void gc::MergeRealms(Realm* source, Realm* target) {
JSRuntime* rt = source->runtimeFromMainThread();
rt->gc.mergeRealms(source, target);
rt->gc.maybeTriggerGCAfterAlloc(target->zone());
rt->gc.maybeTriggerGCAfterMalloc(target->zone());
}
void GCRuntime::mergeRealms(Realm* source, Realm* target) {
// The source realm must be specifically flagged as mergable. This
// also implies that the realm is not visible to the debugger.
//
// TODO: Remove
MOZ_ASSERT(false);
MOZ_ASSERT(source->creationOptions().invisibleToDebugger());
MOZ_ASSERT(!source->hasBeenEnteredIgnoringJit());
MOZ_ASSERT(source->zone()->compartments().length() == 1);
JSContext* cx = rt->mainContextFromOwnThread();
MOZ_ASSERT(!source->zone()->wasGCStarted());
JS::AutoAssertNoGC nogc(cx);
AutoTraceSession session(rt);
// Cleanup tables and other state in the source realm/zone that will be
// meaningless after merging into the target realm/zone.
source->clearTables();
source->zone()->clearTables();
source->unsetIsDebuggee();
#ifdef DEBUG
// Release any relocated arenas which we may be holding on to as they might
// be in the source zone
releaseHeldRelocatedArenas();
#endif
// Fixup realm pointers in source to refer to target, and make sure
// type information generations are in sync.
GlobalObject* global = target->maybeGlobal();
MOZ_ASSERT(global);
AssertTargetIsNotGray(global);
for (auto baseShape = source->zone()->cellIterUnsafe<BaseShape>();
!baseShape.done(); baseShape.next()) {
baseShape->setRealmForMergeRealms(target);
}
// Fixup zone pointers in source's zone to refer to target's zone.
bool targetZoneIsCollecting = target->zone()->gcState() > Zone::Prepare;
for (auto thingKind : AllAllocKinds()) {
for (ArenaIter aiter(source->zone(), thingKind); !aiter.done();
aiter.next()) {
Arena* arena = aiter.get();
arena->zone = target->zone();
if (MOZ_UNLIKELY(targetZoneIsCollecting)) {
// If we are currently collecting the target zone then we must
// treat all merged things as if they were allocated during the
// collection.
for (ArenaCellIter cell(arena); !cell.done(); cell.next()) {
MOZ_ASSERT(!cell->isMarkedAny());
cell->markBlack();
}
}
}
}
// The source should be the only realm in its zone.
for (RealmsInZoneIter r(source->zone()); !r.done(); r.next()) {
MOZ_ASSERT(r.get() == source);
}
// Merge the allocator, stats and UIDs in source's zone into target's zone.
target->zone()->arenas.adoptArenas(&source->zone()->arenas,
targetZoneIsCollecting);
target->zone()->addTenuredAllocsSinceMinorGC(
source->zone()->getAndResetTenuredAllocsSinceMinorGC());
target->zone()->gcHeapSize.adopt(source->zone()->gcHeapSize);
target->zone()->adoptUniqueIds(source->zone());
target->zone()->adoptMallocBytes(source->zone());
// Atoms which are marked in source's zone are now marked in target's zone.
atomMarking.adoptMarkedAtoms(target->zone(), source->zone());
// The source Realm is a parse-only realm and should not have collected any
// zone-tracked metadata.
Zone* sourceZone = source->zone();
MOZ_ASSERT(!sourceZone->scriptLCovMap);
MOZ_ASSERT(!sourceZone->scriptCountsMap);
MOZ_ASSERT(!sourceZone->debugScriptMap);
#ifdef MOZ_VTUNE
MOZ_ASSERT(!sourceZone->scriptVTuneIdMap);
#endif
#ifdef JS_CACHEIR_SPEW
MOZ_ASSERT(!sourceZone->scriptFinalWarmUpCountMap);
#endif
// The source realm is now completely empty, and is the only realm in its
// compartment, which is the only compartment in its zone. Delete realm,
// compartment and zone without waiting for this to be cleaned up by a full
// GC.
sourceZone->deleteEmptyCompartment(source->compartment());
deleteEmptyZone(sourceZone);
}
void GCRuntime::runDebugGC() {
#ifdef JS_GC_ZEAL
if (rt->mainContextFromOwnThread()->suppressGC) {
@ -4398,49 +4276,6 @@ void GCRuntime::setDeterministic(bool enabled) {
}
#endif
void ArenaLists::adoptArenas(ArenaLists* fromArenaLists,
bool targetZoneIsCollecting) {
// GC may be active so take the lock here so we can mutate the arena lists.
AutoLockGC lock(runtime());
fromArenaLists->clearFreeLists();
for (auto thingKind : AllAllocKinds()) {
MOZ_ASSERT(fromArenaLists->concurrentUse(thingKind) == ConcurrentUse::None);
ArenaList* fromList = &fromArenaLists->arenaList(thingKind);
ArenaList* toList = &arenaList(thingKind);
fromList->check();
toList->check();
Arena* next;
for (Arena* fromArena = fromList->head(); fromArena; fromArena = next) {
// Copy fromArena->next before releasing/reinserting.
next = fromArena->next;
#ifdef DEBUG
MOZ_ASSERT(!fromArena->isEmpty());
if (targetZoneIsCollecting) {
fromArena->checkAllCellsMarkedBlack();
} else {
fromArena->checkNoMarkedCells();
}
#endif
// If the target zone is being collected then we need to add the
// arenas before the cursor because the collector assumes that the
// cursor is always at the end of the list. This has the side-effect
// of preventing allocation into any non-full arenas until the end
// of the next GC.
if (targetZoneIsCollecting) {
toList->insertBeforeCursor(fromArena);
} else {
toList->insertAtCursor(fromArena);
}
}
fromList->clear();
toList->check();
}
}
#ifdef DEBUG
AutoAssertNoNurseryAlloc::AutoAssertNoNurseryAlloc() {

Просмотреть файл

@ -110,12 +110,6 @@ void FinishGC(JSContext* cx, JS::GCReason = JS::GCReason::FINISH_GC);
void WaitForBackgroundTasks(JSContext* cx);
/*
* Merge all contents of source into target. This can only be used if source is
* the only realm in its zone.
*/
void MergeRealms(JS::Realm* source, JS::Realm* target);
enum VerifierType { PreBarrierVerifier };
#ifdef JS_GC_ZEAL

Просмотреть файл

@ -610,8 +610,6 @@ class GCRuntime {
void updateHelperThreadCount();
size_t parallelWorkerCount() const;
void mergeRealms(JS::Realm* source, JS::Realm* target);
// WeakRefs
bool registerWeakRef(HandleObject target, HandleObject weakRef);
bool unregisterWeakRefWrapper(JSObject* wrapper);
@ -628,9 +626,6 @@ class GCRuntime {
void updateGCThresholdsAfterCollection(const AutoLockGC& lock);
void updateAllGCStartThresholds(const AutoLockGC& lock);
// Delete an empty zone after its contents have been merged.
void deleteEmptyZone(Zone* zone);
// For ArenaLists::allocateFromArena()
friend class ArenaLists;
TenuredChunk* pickChunk(AutoLockGCBgAlloc& lock);

Просмотреть файл

@ -784,15 +784,6 @@ class HeapSize {
parent_->removeBytes(nbytes, wasSwept);
}
}
/* Pair to adoptArenas. Adopts the attendant usage statistics. */
void adopt(HeapSize& source) {
// Skip retainedBytes_: we never adopt zones that are currently being
// collected.
bytes_ += source.bytes_;
source.retainedBytes_ = 0;
source.bytes_ = 0;
}
};
// Heap size thresholds used to trigger GC. This is an abstract base class for

Просмотреть файл

@ -102,16 +102,4 @@ inline void JS::Zone::removeUniqueId(js::gc::Cell* cell) {
uniqueIds().remove(cell);
}
inline void JS::Zone::adoptUniqueIds(JS::Zone* source) {
js::AutoEnterOOMUnsafeRegion oomUnsafe;
for (js::gc::UniqueIdMap::Enum e(source->uniqueIds()); !e.empty();
e.popFront()) {
MOZ_ASSERT(!uniqueIds().has(e.front().key()));
if (!uniqueIds().put(e.front().key(), e.front().value())) {
oomUnsafe.crash("failed to transfer unique ids from off-thread");
}
}
source->uniqueIds().clear();
}
#endif // gc_Zone_inl_h

Просмотреть файл

@ -591,12 +591,6 @@ Zone* Zone::nextZone() const {
return listNext_;
}
void Zone::clearTables() {
MOZ_ASSERT(regExps().empty());
shapeZone().clearTables(runtimeFromMainThread()->defaultFreeOp());
}
void Zone::fixupAfterMovingGC() {
ZoneAllocator::fixupAfterMovingGC();
shapeZone().fixupPropMapShapeTableAfterMovingGC();
@ -615,22 +609,6 @@ bool Zone::addRttValueObject(JSContext* cx, HandleObject obj) {
return true;
}
void Zone::deleteEmptyCompartment(JS::Compartment* comp) {
MOZ_ASSERT(comp->zone() == this);
arenas.checkEmptyArenaLists();
MOZ_ASSERT(compartments().length() == 1);
MOZ_ASSERT(compartments()[0] == comp);
MOZ_ASSERT(comp->realms().length() == 1);
Realm* realm = comp->realms()[0];
JSFreeOp* fop = runtimeFromMainThread()->defaultFreeOp();
realm->destroy(fop);
comp->destroy(fop);
compartments().clear();
}
void Zone::purgeAtomCache() {
atomCache().clearAndCompact();

Просмотреть файл

@ -456,8 +456,6 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
void notifyObservingDebuggers();
void clearTables();
void addTenuredAllocsSinceMinorGC(uint32_t allocs) {
tenuredAllocsSinceMinorGC_ += allocs;
}
@ -587,16 +585,9 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
// Remove any unique id associated with this Cell.
void removeUniqueId(js::gc::Cell* cell);
// When finished parsing off-thread, transfer any UIDs we created in the
// off-thread zone into the target zone.
void adoptUniqueIds(JS::Zone* source);
bool keepPropMapTables() const { return keepPropMapTables_; }
void setKeepPropMapTables(bool b) { keepPropMapTables_ = b; }
// Delete an empty compartment after its contents have been merged.
void deleteEmptyCompartment(JS::Compartment* comp);
void clearRootsForShutdownGC();
void finishRoots();

Просмотреть файл

@ -57,14 +57,6 @@ class ZoneAllocator : public JS::shadow::Zone,
void* reallocPtr = nullptr);
void reportAllocationOverflow() const;
void adoptMallocBytes(ZoneAllocator* other) {
mallocHeapSize.adopt(other->mallocHeapSize);
jitHeapSize.adopt(other->jitHeapSize);
#ifdef DEBUG
mallocTracker.adopt(other->mallocTracker);
#endif
}
void updateMemoryCountersOnGCStart();
void updateGCStartThresholds(gc::GCRuntime& gc, const js::AutoLockGC& lock);
void setGCSliceThresholds(gc::GCRuntime& gc);

Просмотреть файл

@ -593,12 +593,7 @@ bool InitScriptCoverage(JSContext* cx, JSScript* script) {
MOZ_ASSERT(script->hasBytecode(),
"Only initialize coverage data for fully initialized scripts.");
// Don't allocate LCovSource if we on helper thread since we will have our
// realm migrated. The 'GCRunime::mergeRealms' code will do this
// initialization.
if (cx->isHelperThreadContext()) {
return true;
}
MOZ_ASSERT(!cx->isHelperThreadContext());
const char* filename = script->filename();
if (!filename) {

Просмотреть файл

@ -399,20 +399,6 @@ void Realm::purge() {
promiseLookup.purge();
}
void Realm::clearTables() {
global_.unbarrieredGet()->releaseData(runtime_->defaultFreeOp());
global_.set(nullptr);
// No scripts should have run in this realm. This is used when merging
// a realm that has been used off thread into another realm and zone.
compartment()->assertNoCrossCompartmentWrappers();
MOZ_ASSERT(!jitRealm_);
MOZ_ASSERT(!debugEnvs_);
MOZ_ASSERT(objects_.enumerators->next() == objects_.enumerators);
savedStacks_.clear();
}
// Check to see if this individual realm is recording allocations. Debuggers or
// runtimes can try and record allocations, so this method can check to see if
// any initialization is needed.

Просмотреть файл

@ -442,7 +442,6 @@ class JS::Realm : public JS::shadow::Realm {
[[nodiscard]] bool init(JSContext* cx, JSPrincipals* principals);
void destroy(JSFreeOp* fop);
void clearTables();
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t* realmObject, size_t* realmTables,

Просмотреть файл

@ -215,9 +215,6 @@ class BaseShape : public gc::TenuredCellWithNonGCPointer<const JSClass> {
TaggedProto proto() const { return proto_; }
void setRealmForMergeRealms(JS::Realm* realm) { realm_ = realm; }
void setProtoForMergeRealms(TaggedProto proto) { proto_ = proto; }
/*
* Lookup base shapes from the zone's baseShapes table, adding if not
* already found.

Просмотреть файл

@ -82,14 +82,6 @@ ShapeZone::ShapeZone(Zone* zone)
initialShapes(zone),
propMapShapes(zone) {}
void ShapeZone::clearTables(JSFreeOp* fop) {
baseShapes.clear();
initialPropMaps.clear();
initialShapes.clear();
propMapShapes.clear();
purgeShapeCaches(fop);
}
void ShapeZone::purgeShapeCaches(JSFreeOp* fop) {
for (Shape* shape : shapesWithCache) {
MaybeForwarded(shape)->purgeCache(fop);

Просмотреть файл

@ -160,7 +160,6 @@ struct ShapeZone {
explicit ShapeZone(Zone* zone);
void clearTables(JSFreeOp* fop);
void purgeShapeCaches(JSFreeOp* fop);
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,