Bug 1034225 - Avoid purging the free lists every iteration in PJS by checking if the current arena is in use. r=terrence
--- a/js/src/gc/ForkJoinNursery.cpp
+++ b/js/src/gc/ForkJoinNursery.cpp
@@ -414,42 +414,42 @@ ForkJoinNursery::forwardFromStack(ForkJo
{
MarkForkJoinStack(trc);
}
void
ForkJoinNursery::forwardFromTenured(ForkJoinNurseryCollectionTracer *trc)
{
JSObject *objs[ArenaCellCount];
+ ArenaLists &lists = tenured_->arenas;
for (size_t k=0; k < FINALIZE_LIMIT; k++) {
AllocKind kind = (AllocKind)k;
if (!IsFJNurseryAllocable(kind))
continue;
// When non-JSObject types become nursery-allocable the assumptions in the
// loops below will no longer hold; other types than JSObject must be
// handled.
JS_ASSERT(kind <= FINALIZE_OBJECT_LAST);
+ // Clear the free list that we're currently allocating out of.
+ lists.purge(kind);
+
+ // Since we only purge once, there must not currently be any partially
+ // full arenas left to allocate out of, or we would break out early.
+ JS_ASSERT(!lists.getArenaAfterCursor(kind));
+
ArenaIter ai;
ai.init(const_cast<Allocator *>(tenured_), kind);
for (; !ai.done(); ai.next()) {
- // Do the walk in two steps to avoid problems resulting from allocating
- // into the arena that's being walked: ArenaCellIter is not safe for that.
- // It can happen during evacuation.
- //
- // ArenaCellIterUnderFinalize requires any free list to be flushed into
- // its arena, and since we may allocate within traceObject() we must
- // purge before each arena scan. This is probably not very expensive,
- // it's constant work, and inlined.
- //
+ if (isEvacuating_ && lists.arenaIsInUse(ai.get(), kind))
+ break;
// Use ArenaCellIterUnderFinalize, not ...UnderGC, because that side-steps
// some assertions in the latter that are wrong for PJS collection.
size_t numObjs = 0;
- tenured_->arenas.purge(kind);
for (ArenaCellIterUnderFinalize i(ai.get()); !i.done(); i.next())
objs[numObjs++] = i.get<JSObject>();
for (size_t i=0; i < numObjs; i++)
traceObject(trc, objs[i]);
}
}
}
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -662,16 +662,20 @@ class ArenaLists
ArenaHeader *getFirstArena(AllocKind thingKind) const {
return arenaLists[thingKind].head();
}
ArenaHeader *getFirstArenaToSweep(AllocKind thingKind) const {
return arenaListsToSweep[thingKind];
}
+ ArenaHeader *getArenaAfterCursor(AllocKind thingKind) const {
+ return arenaLists[thingKind].arenaAfterCursor();
+ }
+
bool arenaListsAreEmpty() const {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
/*
* The arena cannot be empty if the background finalization is not yet
* done.
*/
if (backgroundFinalizeState[i] != BFS_DONE)
return false;
@@ -775,16 +779,25 @@ class ArenaLists
* lists.
*/
JS_ASSERT(freeList->isSameNonEmptySpan(aheader->getFirstFreeSpan()));
return true;
}
return false;
}
+ /* Check if |aheader|'s arena is in use. */
+ bool arenaIsInUse(ArenaHeader *aheader, AllocKind kind) const {
+ JS_ASSERT(aheader);
+ const FreeList &freeList = freeLists[kind];
+ if (freeList.isEmpty())
+ return false;
+ return aheader == freeList.arenaHeader();
+ }
+
MOZ_ALWAYS_INLINE void *allocateFromFreeList(AllocKind thingKind, size_t thingSize) {
return freeLists[thingKind].allocate(thingSize);
}
template <AllowGC allowGC>
static void *refillFreeList(ThreadSafeContext *cx, AllocKind thingKind);
/*