Bug 1350760 part 6 - Add a Zone cache for recently atomized strings. r=jonco

This commit is contained in:
Jan de Mooij 2017-03-31 10:54:16 +02:00
parent 35bd8c0bf9
commit 1ad92e7cc7
5 changed files with 56 additions and 4 deletions

View File

@ -199,6 +199,10 @@ class HashMap
// using the finish() method.
void clear() { impl.clear(); }
// Remove all entries. Unlike clear() this method tries to shrink the table.
// Unlike finish() it does not require the map to be initialized again.
void clearAndShrink() { impl.clearAndShrink(); }
// Remove all the entries and release all internal buffers. The map must
// be initialized again before any use.
void finish() { impl.finish(); }
@ -442,6 +446,10 @@ class HashSet
// using the finish() method.
void clear() { impl.clear(); }
// Remove all entries. Unlike clear() this method tries to shrink the table.
// Unlike finish() it does not require the set to be initialized again.
void clearAndShrink() { impl.clearAndShrink(); }
// Remove all the entries and release all internal buffers. The set must
// be initialized again before any use.
void finish() { impl.finish(); }
@ -1676,6 +1684,12 @@ class HashTable : private AllocPolicy
#endif
}
void clearAndShrink()
{
clear();
compactIfUnderloaded();
}
void finish()
{
#ifdef JS_DEBUG

View File

@ -41,6 +41,7 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group)
hasDeadProxies_(group),
typeDescrObjects_(group, this, SystemAllocPolicy()),
markedAtoms_(group),
atomCache_(group),
usage(&rt->gc.usage),
threshold(),
gcDelayBytes(0),
@ -93,7 +94,8 @@ bool Zone::init(bool isSystemArg)
gcSweepGroupEdges().init() &&
gcWeakKeys().init() &&
typeDescrObjects().init() &&
markedAtoms().init();
markedAtoms().init() &&
atomCache().init();
}
void

View File

@ -434,9 +434,15 @@ struct Zone : public JS::shadow::Zone,
private:
// Bitmap of atoms marked by this zone.
js::ZoneGroupOrGCTaskData<js::SparseBitmap> markedAtoms_;
// Set of atoms recently used by this Zone. Purged on GC.
js::ZoneGroupOrGCTaskData<js::AtomSet> atomCache_;
public:
js::SparseBitmap& markedAtoms() { return markedAtoms_.ref(); }
js::AtomSet& atomCache() { return atomCache_.ref(); }
// Track heap usage under this Zone.
js::gc::HeapUsage usage;

View File

@ -12,6 +12,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/RangedPtr.h"
#include "mozilla/Unused.h"
#include <string.h>
@ -304,10 +305,28 @@ static JSAtom*
AtomizeAndCopyChars(JSContext* cx, const CharT* tbchars, size_t length, PinningBehavior pin)
{
if (JSAtom* s = cx->staticStrings().lookup(tbchars, length))
return s;
return s;
AtomHasher::Lookup lookup(tbchars, length);
// Try the per-Zone cache first. If we find the atom there we can avoid the
// atoms lock, the markAtom call, and the multiple HashSet lookups below.
// We don't use the per-Zone cache if we want a pinned atom: handling that
// is more complicated and pinning atoms is relatively uncommon.
Zone* zone = cx->zone();
Maybe<AtomSet::AddPtr> zonePtr;
if (MOZ_LIKELY(zone && pin == DoNotPinAtom)) {
zonePtr.emplace(zone->atomCache().lookupForAdd(lookup));
if (zonePtr.ref()) {
// The cache is purged on GC so if we're in the middle of an
// incremental GC we should have barriered the atom when we put
// it in the cache.
JSAtom* atom = zonePtr.ref()->asPtrUnbarriered();
MOZ_ASSERT(AtomIsMarked(zone, atom));
return atom;
}
}
// Note: when this function is called while the permanent atoms table is
// being initialized (in initializeAtoms()), |permanentAtoms| is not yet
// initialized so this lookup is always skipped. Only once
@ -315,8 +334,12 @@ AtomizeAndCopyChars(JSContext* cx, const CharT* tbchars, size_t length, PinningB
// initialized and then this lookup will go ahead.
if (cx->isPermanentAtomsInitialized()) {
AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
if (pp)
return pp->asPtr(cx);
if (pp) {
JSAtom* atom = pp->asPtr(cx);
if (zonePtr)
mozilla::Unused << zone->atomCache().add(*zonePtr, AtomStateEntry(atom, false));
return atom;
}
}
AutoLockForExclusiveAccess lock(cx);
@ -327,6 +350,8 @@ AtomizeAndCopyChars(JSContext* cx, const CharT* tbchars, size_t length, PinningB
JSAtom* atom = p->asPtr(cx);
p->setPinned(bool(pin));
cx->atomMarking().inlinedMarkAtom(cx, atom);
if (zonePtr)
mozilla::Unused << zone->atomCache().add(*zonePtr, AtomStateEntry(atom, false));
return atom;
}
@ -359,6 +384,8 @@ AtomizeAndCopyChars(JSContext* cx, const CharT* tbchars, size_t length, PinningB
}
cx->atomMarking().inlinedMarkAtom(cx, atom);
if (zonePtr)
mozilla::Unused << zone->atomCache().add(*zonePtr, AtomStateEntry(atom, false));
return atom;
}

View File

@ -3635,6 +3635,9 @@ GCRuntime::purgeRuntime(AutoLockForExclusiveAccess& lock)
for (GCCompartmentsIter comp(rt); !comp.done(); comp.next())
comp->purge();
for (GCZonesIter zone(rt); !zone.done(); zone.next())
zone->atomCache().clearAndShrink();
for (const CooperatingContext& target : rt->cooperatingContexts()) {
freeUnusedLifoBlocksAfterSweeping(&target.context()->tempLifoAlloc());
target.context()->interpreterStack().purge(rt);