Bug 1575350: Move JSScript side-tables from Realm to Zone. r=tcampbell,jonco

Also closes bug 1576216: update ZoneStats and RealmStats memory
accounting for this change.

Differential Revision: https://phabricator.services.mozilla.com/D42977

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Chris Fallin 2019-08-29 22:28:20 +00:00
parent d8ffcbc0d8
commit 52eacd2891
12 changed files with 291 additions and 234 deletions

View File

@ -644,7 +644,8 @@ struct ZoneStats {
MACRO(Other, MallocHeap, shapeTables) \
MACRO(Other, MallocHeap, compartmentObjects) \
MACRO(Other, MallocHeap, crossCompartmentWrappersTables) \
MACRO(Other, MallocHeap, compartmentsPrivateData)
MACRO(Other, MallocHeap, compartmentsPrivateData) \
MACRO(Other, MallocHeap, scriptCountsMap)
ZoneStats() = default;
ZoneStats(ZoneStats&& other) = default;
@ -735,8 +736,7 @@ struct RealmStats {
MACRO(Other, MallocHeap, savedStacksSet) \
MACRO(Other, MallocHeap, varNamesSet) \
MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
MACRO(Other, MallocHeap, jitRealm) \
MACRO(Other, MallocHeap, scriptCountsMap)
MACRO(Other, MallocHeap, jitRealm)
RealmStats() = default;
RealmStats(RealmStats&& other) = default;

View File

@ -42,7 +42,7 @@ namespace js {
/* static */
DebugScript* DebugScript::get(JSScript* script) {
MOZ_ASSERT(script->hasDebugScript());
DebugScriptMap* map = script->realm()->debugScriptMap.get();
DebugScriptMap* map = script->zone()->debugScriptMap.get();
MOZ_ASSERT(map);
DebugScriptMap::Ptr p = map->lookup(script);
MOZ_ASSERT(p);
@ -62,18 +62,18 @@ DebugScript* DebugScript::getOrCreate(JSContext* cx, JSScript* script) {
return nullptr;
}
/* Create realm's debugScriptMap if necessary. */
if (!script->realm()->debugScriptMap) {
/* Create zone's debugScriptMap if necessary. */
if (!script->zone()->debugScriptMap) {
auto map = cx->make_unique<DebugScriptMap>();
if (!map) {
return nullptr;
}
script->realm()->debugScriptMap = std::move(map);
script->zone()->debugScriptMap = std::move(map);
}
DebugScript* borrowed = debug.get();
if (!script->realm()->debugScriptMap->putNew(script, std::move(debug))) {
if (!script->zone()->debugScriptMap->putNew(script, std::move(debug))) {
ReportOutOfMemory(cx);
return nullptr;
}
@ -271,7 +271,7 @@ void DebugScript::decrementGeneratorObserverCount(JSFreeOp* fop,
/* static */
void DebugAPI::destroyDebugScript(JSFreeOp* fop, JSScript* script) {
if (script->hasDebugScript()) {
DebugScriptMap* map = script->realm()->debugScriptMap.get();
DebugScriptMap* map = script->zone()->debugScriptMap.get();
MOZ_ASSERT(map);
DebugScriptMap::Ptr p = map->lookup(script);
MOZ_ASSERT(p);

View File

@ -2416,6 +2416,7 @@ void GCRuntime::updateZonePointersToRelocatedCells(Zone* zone) {
MovingTracer trc(rt);
zone->fixupAfterMovingGC();
zone->fixupScriptMapsAfterMovingGC(&trc);
// Fixup compartment global pointers as these get accessed during marking.
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
@ -7783,28 +7784,33 @@ void GCRuntime::mergeRealms(Realm* source, Realm* target) {
// Atoms which are marked in source's zone are now marked in target's zone.
atomMarking.adoptMarkedAtoms(target->zone(), source->zone());
// Merge script name maps in the target realm's map.
if (coverage::IsLCovEnabled() && source->scriptNameMap) {
// Merge script name map entries from the source zone that come from the
// source realm into the target zone's map. Note that the zones will always
// differ.
Zone* sourceZone = source->zone();
Zone* targetZone = target->zone();
MOZ_ASSERT(sourceZone != targetZone);
if (sourceZone->scriptNameMap) {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!target->scriptNameMap) {
target->scriptNameMap = cx->make_unique<ScriptNameMap>();
if (!targetZone->scriptNameMap) {
targetZone->scriptNameMap = cx->make_unique<ScriptNameMap>();
if (!target->scriptNameMap) {
if (!targetZone->scriptNameMap) {
oomUnsafe.crash("Failed to create a script name map.");
}
}
for (ScriptNameMap::Range r = source->scriptNameMap->all(); !r.empty();
r.popFront()) {
JSScript* key = r.front().key();
auto value = std::move(r.front().value());
if (!target->scriptNameMap->putNew(key, std::move(value))) {
oomUnsafe.crash("Failed to add an entry in the script name map.");
for (auto i = sourceZone->scriptNameMap->modIter(); !i.done(); i.next()) {
JSScript* key = i.get().key();
if (key->realm() == source) {
auto value = std::move(i.get().value());
if (!targetZone->scriptNameMap->putNew(key, std::move(value))) {
oomUnsafe.crash("Failed to add an entry in the script name map.");
}
i.remove();
}
}
source->scriptNameMap->clear();
}
// The source realm is now completely empty, and is the only realm in its
@ -7812,7 +7818,6 @@ void GCRuntime::mergeRealms(Realm* source, Realm* target) {
// compartment and zone without waiting for this to be cleaned up by a full
// GC.
Zone* sourceZone = source->zone();
sourceZone->deleteEmptyCompartment(source->compartment());
deleteEmptyZone(sourceZone);
}
@ -8126,6 +8131,7 @@ void js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt) {
zone->checkInitialShapesTableAfterMovingGC();
zone->checkBaseShapeTableAfterMovingGC();
zone->checkAllCrossCompartmentWrappersAfterMovingGC();
zone->checkScriptMapsAfterMovingGC();
JS::AutoCheckCannotGC nogc;
for (auto baseShape = zone->cellIterUnsafe<BaseShape>(); !baseShape.done();
@ -8139,7 +8145,6 @@ void js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt) {
for (RealmsInCompartmentIter r(c); !r.done(); r.next()) {
r->checkObjectGroupTablesAfterMovingGC();
r->dtoaCache.checkCacheAfterMovingGC();
r->checkScriptMapsAfterMovingGC();
if (r->debugEnvs()) {
r->debugEnvs()->checkHashTablesAfterMovingGC();
}

View File

@ -380,6 +380,16 @@ void js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc,
r->traceRoots(trc, traceOrMark);
}
// Trace zone script-table roots. See comment in
// Zone::traceScriptTableRoots() for justification re: calling this only
// during major (non-nursery) collections.
if (!JS::RuntimeHeapIsMinorCollecting()) {
for (ZonesIter zone(rt, ZoneSelector::SkipAtoms); !zone.done();
zone.next()) {
zone->traceScriptTableRoots(trc);
}
}
// Trace helper thread roots.
HelperThreadState().trace(trc);

View File

@ -591,7 +591,7 @@ void Zone::addSizeOfIncludingThis(
size_t* jitZone, size_t* baselineStubsOptimized, size_t* cachedCFG,
size_t* uniqueIdMap, size_t* shapeCaches, size_t* atomsMarkBitmaps,
size_t* compartmentObjects, size_t* crossCompartmentWrappersTables,
size_t* compartmentsPrivateData) {
size_t* compartmentsPrivateData, size_t* scriptCountsMapArg) {
*typePool += types.typeLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
*regexpZone += regExps().sizeOfExcludingThis(mallocSizeOf);
if (jitZone_) {
@ -610,6 +610,15 @@ void Zone::addSizeOfIncludingThis(
crossCompartmentWrappersTables,
compartmentsPrivateData);
}
if (scriptCountsMap) {
*scriptCountsMapArg +=
scriptCountsMap->shallowSizeOfIncludingThis(mallocSizeOf);
for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
*scriptCountsMapArg +=
r.front().value()->sizeOfIncludingThis(mallocSizeOf);
}
}
}
void* ZoneAllocator::onOutOfMemory(js::AllocFunction allocFunc,
@ -710,3 +719,157 @@ JS_PUBLIC_API void JS::shadow::RegisterWeakCache(
JS::Zone* zone, detail::WeakCacheBase* cachep) {
zone->registerWeakCache(cachep);
}
void Zone::traceScriptTableRoots(JSTracer* trc) {
static_assert(mozilla::IsConvertible<JSScript*, gc::TenuredCell*>::value,
"JSScript must not be nursery-allocated for script-table "
"tracing to work");
// Performance optimization: the script-table keys are JSScripts, which
// cannot be in the nursery, so we can skip this tracing if we are only in a
// minor collection. We static-assert this fact above.
if (JS::RuntimeHeapIsMinorCollecting()) {
return;
}
// N.B.: the script-table keys are weak *except* in an exceptional case: when
// then --dump-bytecode command line option or the PCCount JSFriend API is
// used, then the scripts for all counts must remain alive. We only trace
// when the `trc->runtime()->profilingScripts` flag is set. This flag is
// cleared in JSRuntime::destroyRuntime() during shutdown to ensure that
// scripts are collected before the runtime goes away completely.
if (scriptCountsMap && trc->runtime()->profilingScripts) {
for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty();
r.popFront()) {
JSScript* script = const_cast<JSScript*>(r.front().key());
MOZ_ASSERT(script->hasScriptCounts());
TraceRoot(trc, &script, "profilingScripts");
MOZ_ASSERT(script == r.front().key(), "const_cast is only a work-around");
}
}
}
void Zone::fixupScriptMapsAfterMovingGC(JSTracer* trc) {
// Map entries are removed by JSScript::finalize, but we need to update the
// script pointers here in case they are moved by the GC.
if (scriptCountsMap) {
for (ScriptCountsMap::Enum e(*scriptCountsMap); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
TraceManuallyBarrieredEdge(trc, &script, "Realm::scriptCountsMap::key");
if (script != e.front().key()) {
e.rekeyFront(script);
}
}
}
if (scriptNameMap) {
for (ScriptNameMap::Enum e(*scriptNameMap); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
if (!IsAboutToBeFinalizedUnbarriered(&script) &&
script != e.front().key()) {
e.rekeyFront(script);
}
}
}
if (debugScriptMap) {
for (DebugScriptMap::Enum e(*debugScriptMap); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
if (!IsAboutToBeFinalizedUnbarriered(&script) &&
script != e.front().key()) {
e.rekeyFront(script);
}
}
}
#ifdef MOZ_VTUNE
if (scriptVTuneIdMap) {
for (ScriptVTuneIdMap::Enum e(*scriptVTuneIdMap); !e.empty();
e.popFront()) {
JSScript* script = e.front().key();
if (!IsAboutToBeFinalizedUnbarriered(&script) &&
script != e.front().key()) {
e.rekeyFront(script);
}
}
}
#endif
}
#ifdef JSGC_HASH_TABLE_CHECKS
void Zone::checkScriptMapsAfterMovingGC() {
if (scriptCountsMap) {
for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
MOZ_ASSERT(script->zone() == this);
CheckGCThingAfterMovingGC(script);
auto ptr = scriptCountsMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
if (scriptNameMap) {
for (auto r = scriptNameMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
MOZ_ASSERT(script->zone() == this);
CheckGCThingAfterMovingGC(script);
auto ptr = scriptNameMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
if (debugScriptMap) {
for (auto r = debugScriptMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
MOZ_ASSERT(script->zone() == this);
CheckGCThingAfterMovingGC(script);
DebugScript* ds = r.front().value().get();
DebugAPI::checkDebugScriptAfterMovingGC(ds);
auto ptr = debugScriptMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
# ifdef MOZ_VTUNE
if (scriptVTuneIdMap) {
for (auto r = scriptVTuneIdMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
MOZ_ASSERT(script->zone() == this);
CheckGCThingAfterMovingGC(script);
auto ptr = scriptVTuneIdMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
# endif // MOZ_VTUNE
}
#endif
void Zone::clearScriptCounts(Realm* realm) {
if (!scriptCountsMap) {
return;
}
// Clear all hasScriptCounts_ flags of JSScript, in order to release all
// ScriptCounts entries of the given realm.
for (auto i = scriptCountsMap->modIter(); !i.done(); i.next()) {
JSScript* script = i.get().key();
if (script->realm() == realm) {
script->clearHasScriptCounts();
i.remove();
}
}
}
void Zone::clearScriptNames(Realm* realm) {
if (!scriptNameMap) {
return;
}
for (auto i = scriptNameMap->modIter(); !i.done(); i.next()) {
JSScript* script = i.get().key();
if (script->realm() == realm) {
i.remove();
}
}
}

View File

@ -206,14 +206,12 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
ShouldDiscardBaselineCode discardBaselineCode = DiscardBaselineCode,
ShouldDiscardJitScripts discardJitScripts = KeepJitScripts);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t* typePool, size_t* regexpZone,
size_t* jitZone, size_t* baselineStubsOptimized,
size_t* cachedCFG, size_t* uniqueIdMap,
size_t* shapeCaches, size_t* atomsMarkBitmaps,
size_t* compartmentObjects,
size_t* crossCompartmentWrappersTables,
size_t* compartmentsPrivateData);
void addSizeOfIncludingThis(
mozilla::MallocSizeOf mallocSizeOf, size_t* typePool, size_t* regexpZone,
size_t* jitZone, size_t* baselineStubsOptimized, size_t* cachedCFG,
size_t* uniqueIdMap, size_t* shapeCaches, size_t* atomsMarkBitmaps,
size_t* compartmentObjects, size_t* crossCompartmentWrappersTables,
size_t* compartmentsPrivateData, size_t* scriptCountsMapArg);
// Iterate over all cells in the zone. See the definition of ZoneCellIter
// in gc/GC-inl.h for the possible arguments and documentation.
@ -575,6 +573,7 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
#endif
void fixupInitialShapeTable();
void fixupAfterMovingGC();
void fixupScriptMapsAfterMovingGC(JSTracer* trc);
// Per-zone data for use by an embedder.
js::ZoneData<void*> data;
@ -650,6 +649,27 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
friend bool js::CurrentThreadCanAccessZone(Zone* zone);
friend class js::gc::GCRuntime;
public:
// Script side-tables. These used to be held by Realm, but are now placed
// here in order to allow JSScript to access them during finalize (see bug
// 1568245; this change in 1575350). The tables are initialized lazily by
// JSScript.
js::UniquePtr<js::ScriptCountsMap> scriptCountsMap;
js::UniquePtr<js::ScriptNameMap> scriptNameMap;
js::UniquePtr<js::DebugScriptMap> debugScriptMap;
#ifdef MOZ_VTUNE
js::UniquePtr<js::ScriptVTuneIdMap> scriptVTuneIdMap;
#endif
void traceScriptTableRoots(JSTracer* trc);
void clearScriptCounts(Realm* realm);
void clearScriptNames(Realm* realm);
#ifdef JSGC_HASH_TABLE_CHECKS
void checkScriptMapsAfterMovingGC();
#endif
};
} // namespace JS

View File

@ -1369,14 +1369,14 @@ bool JSScript::initScriptCounts(JSContext* cx) {
base.infallibleEmplaceBack(pcToOffset(jumpTargets[i]));
}
// Create realm's scriptCountsMap if necessary.
if (!realm()->scriptCountsMap) {
// Create zone's scriptCountsMap if necessary.
if (!zone()->scriptCountsMap) {
auto map = cx->make_unique<ScriptCountsMap>();
if (!map) {
return false;
}
realm()->scriptCountsMap = std::move(map);
zone()->scriptCountsMap = std::move(map);
}
// Allocate the ScriptCounts.
@ -1386,8 +1386,8 @@ bool JSScript::initScriptCounts(JSContext* cx) {
return false;
}
// Register the current ScriptCounts in the realm's map.
if (!realm()->scriptCountsMap->putNew(this, std::move(sc))) {
// Register the current ScriptCounts in the zone's map.
if (!zone()->scriptCountsMap->putNew(this, std::move(sc))) {
ReportOutOfMemory(cx);
return false;
}
@ -1408,13 +1408,13 @@ bool JSScript::initScriptCounts(JSContext* cx) {
static inline ScriptCountsMap::Ptr GetScriptCountsMapEntry(JSScript* script) {
MOZ_ASSERT(script->hasScriptCounts());
ScriptCountsMap::Ptr p = script->realm()->scriptCountsMap->lookup(script);
ScriptCountsMap::Ptr p = script->zone()->scriptCountsMap->lookup(script);
MOZ_ASSERT(p);
return p;
}
static inline ScriptNameMap::Ptr GetScriptNameMapEntry(JSScript* script) {
auto p = script->realm()->scriptNameMap->lookup(script);
auto p = script->zone()->scriptNameMap->lookup(script);
MOZ_ASSERT(p);
return p;
}
@ -1591,7 +1591,7 @@ void JSScript::clearHasScriptCounts() {
void JSScript::releaseScriptCounts(ScriptCounts* counts) {
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
*counts = std::move(*p->value().get());
realm()->scriptCountsMap->remove(p);
zone()->scriptCountsMap->remove(p);
clearHasScriptCounts();
}
@ -1604,7 +1604,7 @@ void JSScript::destroyScriptCounts() {
void JSScript::destroyScriptName() {
auto p = GetScriptNameMapEntry(this);
realm()->scriptNameMap->remove(p);
zone()->scriptNameMap->remove(p);
}
void JSScript::resetScriptCounts() {
@ -1624,11 +1624,11 @@ void JSScript::resetScriptCounts() {
}
bool JSScript::hasScriptName() {
if (!realm()->scriptNameMap) {
if (!zone()->scriptNameMap) {
return false;
}
auto p = realm()->scriptNameMap->lookup(this);
auto p = zone()->scriptNameMap->lookup(this);
return p.found();
}
@ -3897,22 +3897,22 @@ JSScript* JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
#ifdef MOZ_VTUNE
uint32_t JSScript::vtuneMethodID() {
if (!realm()->scriptVTuneIdMap) {
if (!zone()->scriptVTuneIdMap) {
auto map = MakeUnique<ScriptVTuneIdMap>();
if (!map) {
MOZ_CRASH("Failed to allocate ScriptVTuneIdMap");
}
realm()->scriptVTuneIdMap = std::move(map);
zone()->scriptVTuneIdMap = std::move(map);
}
ScriptVTuneIdMap::AddPtr p = realm()->scriptVTuneIdMap->lookupForAdd(this);
ScriptVTuneIdMap::AddPtr p = zone()->scriptVTuneIdMap->lookupForAdd(this);
if (p) {
return p->value();
}
uint32_t id = vtune::GenerateUniqueMethodID();
if (!realm()->scriptVTuneIdMap->add(p, this, id)) {
if (!zone()->scriptVTuneIdMap->add(p, this, id)) {
MOZ_CRASH("Failed to add vtune method id");
}
@ -3927,14 +3927,14 @@ bool JSScript::initScriptName(JSContext* cx) {
return true;
}
// Create realm's scriptNameMap if necessary.
if (!realm()->scriptNameMap) {
// Create zone's scriptNameMap if necessary.
if (!zone()->scriptNameMap) {
auto map = cx->make_unique<ScriptNameMap>();
if (!map) {
return false;
}
realm()->scriptNameMap = std::move(map);
zone()->scriptNameMap = std::move(map);
}
UniqueChars name = DuplicateString(filename());
@ -3943,8 +3943,8 @@ bool JSScript::initScriptName(JSContext* cx) {
return false;
}
// Register the script name in the realm's map.
if (!realm()->scriptNameMap->putNew(this, std::move(name))) {
// Register the script name in the zone's map.
if (!zone()->scriptNameMap->putNew(this, std::move(name))) {
ReportOutOfMemory(cx);
return false;
}
@ -4218,9 +4218,9 @@ void JSScript::finalize(JSFreeOp* fop) {
DebugAPI::destroyDebugScript(fop, this);
#ifdef MOZ_VTUNE
if (realm()->scriptVTuneIdMap) {
if (zone()->scriptVTuneIdMap) {
// Note: we should only get here if the VTune JIT profiler is running.
realm()->scriptVTuneIdMap->remove(this);
zone()->scriptVTuneIdMap->remove(this);
}
#endif

View File

@ -231,11 +231,27 @@ class ScriptCounts {
jit::IonScriptCounts* ionCounts_;
};
// Note: The key of this hash map is a weak reference to a JSScript. We do not
// use the WeakMap implementation provided in gc/WeakMap.h because it would be
// collected at the beginning of the sweeping of the realm, thus before the
// calls to the JSScript::finalize function which are used to aggregate code
// coverage results on the realm.
// The key of these side-table hash maps are intentionally not traced GC
// references to JSScript. Instead, we use bare pointers and manually fix up
// when objects could have moved (see Zone::fixupScriptMapsAfterMovingGC) and
// remove when the realm is destroyed (see Zone::clearScriptCounts and
// Zone::clearScriptNames). They essentially behave as weak references, except
// that the references are not cleared early by the GC. They must be non-strong
// references because the tables are kept at the Zone level and otherwise the
// table keys would keep scripts alive, thus keeping Realms alive, beyond their
// expected lifetimes. However, We do not use actual weak references (e.g. as
// used by WeakMap tables provided in gc/WeakMap.h) because they would be
// collected before the calls to the JSScript::finalize function which are used
// to aggregate code coverage results on the realm.
//
// Note carefully, however, that there is an exceptional case for which we *do*
// want the JSScripts to be strong references (and thus traced): when the
// --dump-bytecode command line option or the PCCount JSFriend API is used,
// then the scripts for all counts must remain alive. See
// Zone::traceScriptTableRoots() for more details.
//
// TODO: Clean this up by either aggregating coverage results in some other
// way, or by tweaking sweep ordering.
using UniqueScriptCounts = js::UniquePtr<ScriptCounts>;
using ScriptCountsMap = HashMap<JSScript*, UniqueScriptCounts,
DefaultHasher<JSScript*>, SystemAllocPolicy>;

View File

@ -224,7 +224,8 @@ static void StatsZoneCallback(JSRuntime* rt, void* data, Zone* zone) {
&zStats.jitZone, &zStats.baselineStubsOptimized, &zStats.cachedCFG,
&zStats.uniqueIdMap, &zStats.shapeTables,
&rtStats->runtime.atomsMarkBitmaps, &zStats.compartmentObjects,
&zStats.crossCompartmentWrappersTables, &zStats.compartmentsPrivateData);
&zStats.crossCompartmentWrappersTables, &zStats.compartmentsPrivateData,
&zStats.scriptCountsMap);
}
static void StatsRealmCallback(JSContext* cx, void* data,
@ -248,8 +249,7 @@ static void StatsRealmCallback(JSContext* cx, void* data,
&realmStats.realmTables, &realmStats.innerViewsTable,
&realmStats.lazyArrayBuffersTable, &realmStats.objectMetadataTable,
&realmStats.savedStacksSet, &realmStats.varNamesSet,
&realmStats.nonSyntacticLexicalScopesTable, &realmStats.jitRealm,
&realmStats.scriptCountsMap);
&realmStats.nonSyntacticLexicalScopesTable, &realmStats.jitRealm);
}
static void StatsArenaCallback(JSRuntime* rt, void* data, gc::Arena* arena,

View File

@ -326,28 +326,6 @@ void Realm::traceRoots(JSTracer* trc,
}
objects_.trace(trc);
// If code coverage is only enabled with the Debugger or the LCovOutput,
// then the following comment holds.
//
// The scriptCountsMap maps JSScript weak-pointers to ScriptCounts
// structures. It uses a HashMap instead of a WeakMap, so that we can keep
// the data alive for the JSScript::finalize call. Thus, we do not trace the
// keys of the HashMap to avoid adding a strong reference to the JSScript
// pointers.
//
// If the --dump-bytecode command line option or the PCCount JSFriend API
// is used, then we mark the keys of the map to hold the JSScript alive.
if (scriptCountsMap && trc->runtime()->profilingScripts &&
!JS::RuntimeHeapIsMinorCollecting()) {
for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty();
r.popFront()) {
JSScript* script = const_cast<JSScript*>(r.front().key());
MOZ_ASSERT(script->hasScriptCounts());
TraceRoot(trc, &script, "profilingScripts");
MOZ_ASSERT(script == r.front().key(), "const_cast is only a work-around");
}
}
}
void ObjectRealm::finishRoots() {
@ -373,10 +351,6 @@ void Realm::finishRoots() {
clearScriptCounts();
clearScriptNames();
#ifdef MOZ_VTUNE
scriptVTuneIdMap.reset();
#endif
}
void ObjectRealm::sweepAfterMinorGC() {
@ -475,7 +449,6 @@ void Realm::fixupAfterMovingGC(JSTracer* trc) {
purge();
fixupGlobal();
objectGroups_.fixupTablesAfterMovingGC();
fixupScriptMapsAfterMovingGC(trc);
}
void Realm::fixupGlobal() {
@ -485,102 +458,6 @@ void Realm::fixupGlobal() {
}
}
void Realm::fixupScriptMapsAfterMovingGC(JSTracer* trc) {
// Map entries are removed by JSScript::finalize, but we need to update the
// script pointers here in case they are moved by the GC.
if (scriptCountsMap) {
for (ScriptCountsMap::Enum e(*scriptCountsMap); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
TraceManuallyBarrieredEdge(trc, &script, "Realm::scriptCountsMap::key");
if (script != e.front().key()) {
e.rekeyFront(script);
}
}
}
if (scriptNameMap) {
for (ScriptNameMap::Enum e(*scriptNameMap); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
if (!IsAboutToBeFinalizedUnbarriered(&script) &&
script != e.front().key()) {
e.rekeyFront(script);
}
}
}
if (debugScriptMap) {
for (DebugScriptMap::Enum e(*debugScriptMap); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
if (!IsAboutToBeFinalizedUnbarriered(&script) &&
script != e.front().key()) {
e.rekeyFront(script);
}
}
}
#ifdef MOZ_VTUNE
if (scriptVTuneIdMap) {
for (ScriptVTuneIdMap::Enum e(*scriptVTuneIdMap); !e.empty();
e.popFront()) {
JSScript* script = e.front().key();
if (!IsAboutToBeFinalizedUnbarriered(&script) &&
script != e.front().key()) {
e.rekeyFront(script);
}
}
}
#endif
}
#ifdef JSGC_HASH_TABLE_CHECKS
void Realm::checkScriptMapsAfterMovingGC() {
if (scriptCountsMap) {
for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
MOZ_ASSERT(script->realm() == this);
CheckGCThingAfterMovingGC(script);
auto ptr = scriptCountsMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
if (scriptNameMap) {
for (auto r = scriptNameMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
MOZ_ASSERT(script->realm() == this);
CheckGCThingAfterMovingGC(script);
auto ptr = scriptNameMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
if (debugScriptMap) {
for (auto r = debugScriptMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
MOZ_ASSERT(script->realm() == this);
CheckGCThingAfterMovingGC(script);
DebugScript* ds = r.front().value().get();
DebugAPI::checkDebugScriptAfterMovingGC(ds);
auto ptr = debugScriptMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
# ifdef MOZ_VTUNE
if (scriptVTuneIdMap) {
for (auto r = scriptVTuneIdMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
MOZ_ASSERT(script->realm() == this);
CheckGCThingAfterMovingGC(script);
auto ptr = scriptVTuneIdMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
# endif // MOZ_VTUNE
}
#endif
void Realm::purge() {
dtoaCache.purge();
newProxyCache.purge();
@ -843,22 +720,9 @@ bool Realm::collectCoverageForDebug() const {
return debuggerObservesCoverage() || coverage::IsLCovEnabled();
}
void Realm::clearScriptCounts() {
if (!scriptCountsMap) {
return;
}
void Realm::clearScriptCounts() { zone()->clearScriptCounts(this); }
// Clear all hasScriptCounts_ flags of JSScript, in order to release all
// ScriptCounts entries of the current realm.
for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty();
r.popFront()) {
r.front().key()->clearHasScriptCounts();
}
scriptCountsMap.reset();
}
void Realm::clearScriptNames() { scriptNameMap.reset(); }
void Realm::clearScriptNames() { zone()->clearScriptNames(this); }
void ObjectRealm::addSizeOfExcludingThis(
mozilla::MallocSizeOf mallocSizeOf, size_t* innerViewsArg,
@ -887,7 +751,7 @@ void Realm::addSizeOfIncludingThis(
size_t* realmTables, size_t* innerViewsArg, size_t* lazyArrayBuffersArg,
size_t* objectMetadataTablesArg, size_t* savedStacksSet,
size_t* varNamesSet, size_t* nonSyntacticLexicalEnvironmentsArg,
size_t* jitRealm, size_t* scriptCountsMapArg) {
size_t* jitRealm) {
*realmObject += mallocSizeOf(this);
objectGroups_.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
tiArrayTypeTables, tiObjectTypeTables,
@ -904,15 +768,6 @@ void Realm::addSizeOfIncludingThis(
if (jitRealm_) {
*jitRealm += jitRealm_->sizeOfIncludingThis(mallocSizeOf);
}
if (scriptCountsMap) {
*scriptCountsMapArg +=
scriptCountsMap->shallowSizeOfIncludingThis(mallocSizeOf);
for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
*scriptCountsMapArg +=
r.front().value()->sizeOfIncludingThis(mallocSizeOf);
}
}
}
mozilla::HashCodeScrambler Realm::randomHashCodeScrambler() {

View File

@ -416,13 +416,6 @@ class JS::Realm : public JS::shadow::Realm {
js::ArraySpeciesLookup arraySpeciesLookup;
js::PromiseLookup promiseLookup;
js::UniquePtr<js::ScriptCountsMap> scriptCountsMap;
js::UniquePtr<js::ScriptNameMap> scriptNameMap;
js::UniquePtr<js::DebugScriptMap> debugScriptMap;
#ifdef MOZ_VTUNE
js::UniquePtr<js::ScriptVTuneIdMap> scriptVTuneIdMap;
#endif
/*
* Lazily initialized script source object to use for scripts cloned
* from the self-hosting global.
@ -465,16 +458,13 @@ class JS::Realm : public JS::shadow::Realm {
void destroy(JSFreeOp* fop);
void clearTables();
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t* tiAllocationSiteTables,
size_t* tiArrayTypeTables,
size_t* tiObjectTypeTables, size_t* realmObject,
size_t* realmTables, size_t* innerViews,
size_t* lazyArrayBuffers,
size_t* objectMetadataTables,
size_t* savedStacksSet, size_t* varNamesSet,
size_t* nonSyntacticLexicalScopes,
size_t* jitRealm, size_t* scriptCountsMapArg);
void addSizeOfIncludingThis(
mozilla::MallocSizeOf mallocSizeOf, size_t* tiAllocationSiteTables,
size_t* tiArrayTypeTables, size_t* tiObjectTypeTables,
size_t* realmObject, size_t* realmTables, size_t* innerViewsArg,
size_t* lazyArrayBuffersArg, size_t* objectMetadataTablesArg,
size_t* savedStacksSet, size_t* varNamesSet,
size_t* nonSyntacticLexicalEnvironmentsArg, size_t* jitRealm);
JS::Zone* zone() { return zone_; }
const JS::Zone* zone() const { return zone_; }
@ -563,13 +553,11 @@ class JS::Realm : public JS::shadow::Realm {
void purge();
void fixupAfterMovingGC(JSTracer* trc);
void fixupScriptMapsAfterMovingGC(JSTracer* trc);
#ifdef JSGC_HASH_TABLE_CHECKS
void checkObjectGroupTablesAfterMovingGC() {
objectGroups_.checkTablesAfterMovingGC();
}
void checkScriptMapsAfterMovingGC();
#endif
// Add a name to [[VarNames]]. Reports OOM on failure.

View File

@ -1496,6 +1496,10 @@ static void ReportZoneStats(const JS::ZoneStats& zStats,
zStats.cachedCFG,
"The cached CFG to construct Ion code out of it.");
ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("script-counts-map"),
zStats.scriptCountsMap,
"Profiling-related information for scripts.");
size_t stringsNotableAboutMemoryGCHeap = 0;
size_t stringsNotableAboutMemoryMallocHeap = 0;
@ -1888,10 +1892,6 @@ static void ReportRealmStats(const JS::RealmStats& realmStats,
ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("jit-realm"),
realmStats.jitRealm, "The JIT realm.");
ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("script-counts-map"),
realmStats.scriptCountsMap,
"Profiling-related information for scripts.");
if (sundriesGCHeap > 0) {
// We deliberately don't use ZRREPORT_GC_BYTES here.
REPORT_GC_BYTES(