Bug 1560375 - Share string wrappers between all comparments in a zone r=jandem?

This moves the string wrapper map to the zone where it's shared by all compartments in the zone.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jon Coppeard 2019-08-09 14:55:30 +00:00
parent 420708d31b
commit d74716c7d8
8 changed files with 152 additions and 90 deletions

View File

@ -2987,7 +2987,7 @@ void GCRuntime::updateRuntimePointersToRelocatedCells(AutoGCSession& session) {
gcstats::AutoPhase ap1(stats(), gcstats::PhaseKind::COMPACT_UPDATE);
MovingTracer trc(rt);
Compartment::fixupCrossCompartmentWrappersAfterMovingGC(&trc);
Zone::fixupAllCrossCompartmentWrappersAfterMovingGC(&trc);
rt->geckoProfiler().fixupStringsMapAfterMovingGC();
@ -5013,8 +5013,8 @@ static void DropStringWrappers(JSRuntime* rt) {
* us to sweep the wrappers in all compartments every time we sweep a
* compartment group.
*/
for (CompartmentsIter c(rt); !c.done(); c.next()) {
c->dropStringWrappersOnGC();
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
zone->dropStringWrappersOnGC();
}
}
@ -5583,8 +5583,8 @@ static void UpdateAtomsBitmap(JSRuntime* runtime) {
static void SweepCCWrappers(GCParallelTask* task) {
AutoSetThreadIsSweeping threadIsSweeping;
JSRuntime* runtime = task->runtime();
for (SweepGroupCompartmentsIter c(runtime); !c.done(); c.next()) {
c->sweepCrossCompartmentWrappers();
for (SweepGroupZonesIter zone(runtime); !zone.done(); zone.next()) {
zone->sweepAllCrossCompartmentWrappers();
}
}
@ -8636,6 +8636,7 @@ void js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt) {
zone->checkUniqueIdTableAfterMovingGC();
zone->checkInitialShapesTableAfterMovingGC();
zone->checkBaseShapeTableAfterMovingGC();
zone->checkAllCrossCompartmentWrappersAfterMovingGC();
JS::AutoCheckCannotGC nogc;
for (auto baseShape = zone->cellIterUnsafe<BaseShape>(); !baseShape.done();
@ -8646,8 +8647,6 @@ void js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt) {
}
for (CompartmentsIter c(rt); !c.done(); c.next()) {
c->checkWrapperMapAfterMovingGC();
for (RealmsInCompartmentIter r(c); !r.done(); r.next()) {
r->checkObjectGroupTablesAfterMovingGC();
r->dtoaCache.checkCacheAfterMovingGC();

View File

@ -1224,7 +1224,7 @@ void js::Nursery::sweep(JSTracer* trc) {
}
for (ZonesIter zone(trc->runtime(), SkipAtoms); !zone.done(); zone.next()) {
zone->sweepAfterMinorGC();
zone->sweepAfterMinorGC(trc);
}
sweepDictionaryModeObjects();

View File

@ -95,6 +95,7 @@ JS::Zone::Zone(JSRuntime* rt)
types(this),
gcWeakMapList_(this),
compartments_(),
crossZoneStringWrappers_(this),
gcGrayRoots_(this),
weakCaches_(this),
gcWeakKeys_(this, SystemAllocPolicy(), rt->randomHashCodeScrambler()),
@ -212,7 +213,12 @@ static void SweepWeakEntryVectorWhileMinorSweeping(
});
}
void Zone::sweepAfterMinorGC() {
void Zone::sweepAfterMinorGC(JSTracer* trc) {
sweepWeakKeysAfterMinorGC();
crossZoneStringWrappers().sweepAfterMinorGC(trc);
}
void Zone::sweepWeakKeysAfterMinorGC() {
for (WeakKeyTable::Range r = gcNurseryWeakKeys().all(); !r.empty();
r.popFront()) {
// Sweep gcNurseryWeakKeys to move live (forwarded) keys to gcWeakKeys,
@ -281,6 +287,57 @@ void Zone::sweepAfterMinorGC() {
}
}
void Zone::sweepAllCrossCompartmentWrappers() {
crossZoneStringWrappers().sweep();
for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) {
comp->sweepCrossCompartmentObjectWrappers();
}
}
/* static */
void Zone::fixupAllCrossCompartmentWrappersAfterMovingGC(JSTracer* trc) {
MOZ_ASSERT(trc->runtime()->gc.isHeapCompacting());
for (ZonesIter zone(trc->runtime(), WithAtoms); !zone.done(); zone.next()) {
// Sweep the wrapper map to update keys (wrapped values) in other
// compartments that may have been moved.
zone->crossZoneStringWrappers().sweep();
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
comp->fixupCrossCompartmentObjectWrappersAfterMovingGC(trc);
}
}
}
void Zone::dropStringWrappersOnGC() {
MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
crossZoneStringWrappers().clear();
}
#ifdef JSGC_HASH_TABLE_CHECKS
void Zone::checkAllCrossCompartmentWrappersAfterMovingGC() {
checkStringWrappersAfterMovingGC();
for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) {
comp->checkObjectWrappersAfterMovingGC();
}
}
void Zone::checkStringWrappersAfterMovingGC() {
for (StringWrapperMap::Enum e(crossZoneStringWrappers()); !e.empty();
e.popFront()) {
// Assert that the postbarriers have worked and that nothing is left in the
// wrapper map that points into the nursery, and that the hash table entries
// are discoverable.
auto key = e.front().key();
CheckGCThingAfterMovingGC(key);
auto ptr = crossZoneStringWrappers().lookup(key);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
}
}
#endif
void Zone::sweepWeakMaps() {
/* Finalize unreachable (key,value) pairs in all weak maps. */
WeakMapBase::sweepZone(this);
@ -543,6 +600,32 @@ void Zone::traceAtomCache(JSTracer* trc) {
}
}
void Zone::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) {
*typePool += types.typeLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
*regexpZone += regExps().sizeOfExcludingThis(mallocSizeOf);
if (jitZone_) {
jitZone_->addSizeOfIncludingThis(mallocSizeOf, jitZone,
baselineStubsOptimized, cachedCFG);
}
*uniqueIdMap += uniqueIds().shallowSizeOfExcludingThis(mallocSizeOf);
*shapeCaches += baseShapes().sizeOfExcludingThis(mallocSizeOf) +
initialShapes().sizeOfExcludingThis(mallocSizeOf);
*atomsMarkBitmaps += markedAtoms().sizeOfExcludingThis(mallocSizeOf);
*crossCompartmentWrappersTables +=
crossZoneStringWrappers().sizeOfExcludingThis(mallocSizeOf);
for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) {
comp->addSizeOfIncludingThis(mallocSizeOf, compartmentObjects,
crossCompartmentWrappersTables,
compartmentsPrivateData);
}
}
void* ZoneAllocator::onOutOfMemory(js::AllocFunction allocFunc,
arena_id_t arena, size_t nbytes,
void* reallocPtr) {

View File

@ -12,6 +12,7 @@
#include "mozilla/SegmentedVector.h"
#include "gc/FindSCCs.h"
#include "gc/NurseryAwareHashMap.h"
#include "gc/ZoneAllocator.h"
#include "js/GCHashTable.h"
#include "vm/MallocProvider.h"
@ -49,6 +50,10 @@ class ZoneCellIter;
} // namespace gc
using StringWrapperMap =
NurseryAwareHashMap<JSString*, JSString*, DefaultHasher<JSString*>,
ZoneAllocPolicy>;
class MOZ_NON_TEMPORARY_CLASS ExternalStringCache {
static const size_t NumEntries = 4;
mozilla::Array<JSString*, NumEntries> entries_;
@ -306,7 +311,7 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
unsigned lastSweepGroupIndex() { return gcSweepGroupIndex; }
#endif
void sweepAfterMinorGC();
void sweepAfterMinorGC(JSTracer* trc);
void sweepBreakpoints(js::FreeOp* fop);
void sweepUniqueIds();
void sweepWeakMaps();
@ -381,9 +386,29 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
// The set of compartments in this zone.
js::MainThreadOrGCTaskData<CompartmentVector> compartments_;
// All cross-zone string wrappers in the zone.
js::MainThreadOrGCTaskData<js::StringWrapperMap> crossZoneStringWrappers_;
public:
CompartmentVector& compartments() { return compartments_.ref(); }
js::StringWrapperMap& crossZoneStringWrappers() {
return crossZoneStringWrappers_.ref();
}
const js::StringWrapperMap& crossZoneStringWrappers() const {
return crossZoneStringWrappers_.ref();
}
void dropStringWrappersOnGC();
#ifdef JSGC_HASH_TABLE_CHECKS
void checkAllCrossCompartmentWrappersAfterMovingGC();
void checkStringWrappersAfterMovingGC();
#endif
void sweepAllCrossCompartmentWrappers();
static void fixupAllCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
// This zone's gray roots.
using GrayRootVector =
mozilla::SegmentedVector<js::gc::Cell*, 1024 * sizeof(js::gc::Cell*),
@ -421,6 +446,10 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
js::gc::WeakKeyTable& gcWeakKeys() { return gcWeakKeys_.ref(); }
js::gc::WeakKeyTable& gcNurseryWeakKeys() { return gcNurseryWeakKeys_.ref(); }
private:
void sweepWeakKeysAfterMinorGC();
public:
// A set of edges from this zone to other zones used during GC to calculate
// sweep groups.
NodeSet& gcSweepGroupEdges() {

View File

@ -23,6 +23,11 @@
#include "vm/JSContext-inl.h"
inline js::StringWrapperMap::Ptr JS::Compartment::lookupWrapper(
JSString* str) const {
return zone()->crossZoneStringWrappers().lookup(str);
}
inline bool JS::Compartment::wrap(JSContext* cx, JS::MutableHandleValue vp) {
/* Only GC things have to be wrapped or copied. */
if (!vp.isGCThing()) {

View File

@ -15,6 +15,7 @@
#include "debugger/DebugAPI.h"
#include "gc/Policy.h"
#include "gc/PublicIterators.h"
#include "gc/Zone.h"
#include "js/Date.h"
#include "js/Proxy.h"
#include "js/RootingAPI.h"
@ -42,31 +43,20 @@ Compartment::Compartment(Zone* zone, bool invisibleToDebugger)
runtime_(zone->runtimeFromAnyThread()),
invisibleToDebugger_(invisibleToDebugger),
crossCompartmentObjectWrappers(zone, 0),
crossCompartmentStringWrappers(zone),
realms_(zone) {}
#ifdef JSGC_HASH_TABLE_CHECKS
template <typename Map, typename Entry>
static inline void CheckWrapperMapEntry(const Map& map, Entry& entry) {
/*
* Assert that the postbarriers have worked and that nothing is left in
* wrapperMap that points into the nursery, and that the hash table entries
* are discoverable.
*/
auto key = entry.front().key();
CheckGCThingAfterMovingGC(key);
auto ptr = map.lookup(key);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &entry.front());
}
void Compartment::checkWrapperMapAfterMovingGC() {
for (StringWrapperEnum e(this); !e.empty(); e.popFront()) {
CheckWrapperMapEntry(crossCompartmentStringWrappers, e);
}
void Compartment::checkObjectWrappersAfterMovingGC() {
for (ObjectWrapperEnum e(this); !e.empty(); e.popFront()) {
CheckWrapperMapEntry(crossCompartmentObjectWrappers, e);
// Assert that the postbarriers have worked and that nothing is left in the
// wrapper map that points into the nursery, and that the hash table entries
// are discoverable.
auto key = e.front().key();
CheckGCThingAfterMovingGC(key);
auto ptr = crossCompartmentObjectWrappers.lookup(key);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
}
}
@ -87,7 +77,7 @@ bool Compartment::putWrapper(JSContext* cx, JSObject* wrapped,
bool Compartment::putWrapper(JSContext* cx, JSString* wrapped,
JSString* wrapper) {
if (!crossCompartmentStringWrappers.put(wrapped, wrapper)) {
if (!zone()->crossZoneStringWrappers().put(wrapped, wrapper)) {
ReportOutOfMemory(cx);
return false;
}
@ -459,14 +449,8 @@ void Compartment::traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc) {
DebugAPI::traceCrossCompartmentEdges(trc);
}
void Compartment::dropStringWrappersOnGC() {
MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
crossCompartmentStringWrappers.clear();
}
void Compartment::sweepAfterMinorGC(JSTracer* trc) {
crossCompartmentObjectWrappers.sweepAfterMinorGC(trc);
crossCompartmentStringWrappers.sweepAfterMinorGC(trc);
for (RealmsInCompartmentIter r(this); !r.done(); r.next()) {
r->sweepAfterMinorGC();
@ -478,23 +462,21 @@ void Compartment::sweepAfterMinorGC(JSTracer* trc) {
* string entries in the crossCompartmentWrappers table are not marked during
* markCrossCompartmentWrappers.
*/
void Compartment::sweepCrossCompartmentWrappers() {
void Compartment::sweepCrossCompartmentObjectWrappers() {
crossCompartmentObjectWrappers.sweep();
crossCompartmentStringWrappers.sweep();
}
/* static */
void Compartment::fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc) {
void Compartment::fixupCrossCompartmentObjectWrappersAfterMovingGC(
JSTracer* trc) {
MOZ_ASSERT(trc->runtime()->gc.isHeapCompacting());
for (CompartmentsIter comp(trc->runtime()); !comp.done(); comp.next()) {
// Sweep the wrapper map to update keys (wrapped values) in other
// compartments that may have been moved.
comp->sweepCrossCompartmentWrappers();
// Trace the wrappers in the map to update their cross-compartment edges
// to wrapped values in other compartments that may have been moved.
comp->traceOutgoingCrossCompartmentWrappers(trc);
}
// Sweep the wrapper map to update keys (wrapped values) in other
// compartments that may have been moved.
sweepCrossCompartmentObjectWrappers();
// Trace the wrappers in the map to update their cross-compartment edges
// to wrapped values in other compartments that may have been moved.
traceOutgoingCrossCompartmentWrappers(trc);
}
void Compartment::fixupAfterMovingGC(JSTracer* trc) {
@ -506,7 +488,7 @@ void Compartment::fixupAfterMovingGC(JSTracer* trc) {
// Sweep the wrapper map to update values (wrapper objects) in this
// compartment that may have been moved.
sweepCrossCompartmentWrappers();
sweepCrossCompartmentObjectWrappers();
}
void Compartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
@ -516,8 +498,6 @@ void Compartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
*compartmentObjects += mallocSizeOf(this);
*crossCompartmentWrappersTables +=
crossCompartmentObjectWrappers.sizeOfExcludingThis(mallocSizeOf);
*crossCompartmentWrappersTables +=
crossCompartmentStringWrappers.sizeOfExcludingThis(mallocSizeOf);
if (auto callback = runtime_->sizeOfIncludingThisCompartmentCallback) {
*compartmentsPrivateData += callback(mallocSizeOf, this);

View File

@ -233,7 +233,6 @@ class JS::Compartment {
bool invisibleToDebugger_;
js::ObjectWrapperMap crossCompartmentObjectWrappers;
js::StringWrapperMap crossCompartmentStringWrappers;
using RealmVector = js::Vector<JS::Realm*, 1, js::ZoneAllocPolicy>;
RealmVector realms_;
@ -304,7 +303,6 @@ class JS::Compartment {
void assertNoCrossCompartmentWrappers() {
MOZ_ASSERT(crossCompartmentObjectWrappers.empty());
MOZ_ASSERT(crossCompartmentStringWrappers.empty());
}
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
@ -313,7 +311,7 @@ class JS::Compartment {
size_t* compartmentsPrivateData);
#ifdef JSGC_HASH_TABLE_CHECKS
void checkWrapperMapAfterMovingGC();
void checkObjectWrappersAfterMovingGC();
#endif
private:
@ -350,9 +348,7 @@ class JS::Compartment {
return crossCompartmentObjectWrappers.lookup(obj);
}
js::StringWrapperMap::Ptr lookupWrapper(JSString* str) const {
return crossCompartmentStringWrappers.lookup(str);
}
inline js::StringWrapperMap::Ptr lookupWrapper(JSString* str) const;
void removeWrapper(js::ObjectWrapperMap::Ptr p) {
crossCompartmentObjectWrappers.remove(p);
@ -375,11 +371,6 @@ class JS::Compartment {
}
};
struct StringWrapperEnum : public js::StringWrapperMap::Enum {
explicit StringWrapperEnum(JS::Compartment* c)
: js::StringWrapperMap::Enum(c->crossCompartmentStringWrappers) {}
};
/*
* These methods mark pointers that cross compartment boundaries. They are
* called in per-zone GCs to prevent the wrappers' outgoing edges from
@ -388,14 +379,13 @@ class JS::Compartment {
*/
void traceOutgoingCrossCompartmentWrappers(JSTracer* trc);
static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc);
void dropStringWrappersOnGC();
void sweepRealms(js::FreeOp* fop, bool keepAtleastOne,
bool destroyingRuntime);
void sweepAfterMinorGC(JSTracer* trc);
void sweepCrossCompartmentWrappers();
void sweepCrossCompartmentObjectWrappers();
static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
void fixupCrossCompartmentObjectWrappersAfterMovingGC(JSTracer* trc);
void fixupAfterMovingGC(JSTracer* trc);
MOZ_MUST_USE bool findSweepGroupEdges();

View File

@ -4438,30 +4438,6 @@ void JitScript::sweepTypes(const js::AutoSweepJitScript& sweep, Zone* zone) {
}
}
void Zone::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) {
*typePool += types.typeLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
*regexpZone += regExps().sizeOfExcludingThis(mallocSizeOf);
if (jitZone_) {
jitZone_->addSizeOfIncludingThis(mallocSizeOf, jitZone,
baselineStubsOptimized, cachedCFG);
}
*uniqueIdMap += uniqueIds().shallowSizeOfExcludingThis(mallocSizeOf);
*shapeCaches += baseShapes().sizeOfExcludingThis(mallocSizeOf) +
initialShapes().sizeOfExcludingThis(mallocSizeOf);
*atomsMarkBitmaps += markedAtoms().sizeOfExcludingThis(mallocSizeOf);
for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) {
comp->addSizeOfIncludingThis(mallocSizeOf, compartmentObjects,
crossCompartmentWrappersTables,
compartmentsPrivateData);
}
}
TypeZone::TypeZone(Zone* zone)
: zone_(zone),
typeLifoAlloc_(zone, (size_t)TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),