Bug 1081952 - Explicitly set the background finalize state as the last step. r=terrence
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2567,24 +2567,32 @@ ArenaLists::backgroundFinalize(FreeOp *f
// arenas may be allocated before background finalization finishes; now that
// finalization is complete, we want to merge these lists back together.
ArenaLists *lists = &zone->allocator.arenas;
ArenaList *al = &lists->arenaLists[thingKind];
// Flatten |finalizedSorted| into a regular ArenaList.
ArenaList finalized = finalizedSorted.toArenaList();
- AutoLockGC lock(fop->runtime());
- MOZ_ASSERT(lists->backgroundFinalizeState[thingKind] == BFS_RUN);
-
- // Join |al| and |finalized| into a single list.
- *al = finalized.insertListWithCursorAtEnd(*al);
+ // We must take the GC lock to be able to safely modify the ArenaList;
+ // however, this does not by itself make the changes visible to all threads,
+ // as not all threads take the GC lock to read the ArenaLists.
+ // That safety is provided by the ReleaseAcquire memory ordering of the
+ // background finalize state, which we explicitly set as the final step.
+ {
+ AutoLockGC lock(fop->runtime());
+ MOZ_ASSERT(lists->backgroundFinalizeState[thingKind] == BFS_RUN);
+
+ // Join |al| and |finalized| into a single list.
+ *al = finalized.insertListWithCursorAtEnd(*al);
+
+ lists->arenaListsToSweep[thingKind] = nullptr;
+ }
lists->backgroundFinalizeState[thingKind] = BFS_DONE;
- lists->arenaListsToSweep[thingKind] = nullptr;
}
void
ArenaLists::queueObjectsForSweep(FreeOp *fop)
{
gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_OBJECT);
finalizeNow(fop, FINALIZE_OBJECT0);