mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 16:22:00 +00:00
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:
parent
d8ffcbc0d8
commit
52eacd2891
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>;
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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.
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user