Bug 1480233 - Define compacting GC support in AllocKind.h. r=sfink
authorTed Campbell <tcampbell@mozilla.com>
Wed, 01 Aug 2018 17:47:44 -0400
changeset 825664 1765ed67a90a5e2afeaeb920f8b02f4ecb0c72bb
parent 825663 f150e62dcbbdc14bec93db0705470a5d9e71737e
child 825665 915862a355e959c92c9ea7fb1cd7adbcf03bfb98
push id118150
push usermaglione.k@gmail.com
push dateThu, 02 Aug 2018 04:47:08 +0000
reviewerssfink
bugs1480233
milestone63.0a1
Bug 1480233 - Define compacting GC support in AllocKind.h. r=sfink MozReview-Commit-ID: H1D21Xv21Ya
js/src/gc/AllocKind.h
js/src/gc/Allocator.cpp
js/src/gc/GC.cpp
js/src/gc/GC.h
js/src/jit/Ion.cpp
--- a/js/src/gc/AllocKind.h
+++ b/js/src/gc/AllocKind.h
@@ -29,65 +29,66 @@ namespace gc {
 // and supply the following information:
 //
 //  - the corresponding AllocKind
 //  - their JS::TraceKind
 //  - their C++ base type
 //  - a C++ type of the correct size
 //  - whether they can be finalized on the background thread
 //  - whether they can be allocated in the nursery
+//  - whether they can be compacted
 
 #define FOR_EACH_OBJECT_ALLOCKIND(D) \
- /* AllocKind              TraceKind     TypeName           SizedType          BGFinal Nursery */ \
-    D(FUNCTION,            Object,       JSObject,          JSFunction,        true,   true)  \
-    D(FUNCTION_EXTENDED,   Object,       JSObject,          FunctionExtended,  true,   true)  \
-    D(OBJECT0,             Object,       JSObject,          JSObject_Slots0,   false,  false) \
-    D(OBJECT0_BACKGROUND,  Object,       JSObject,          JSObject_Slots0,   true,   true)  \
-    D(OBJECT2,             Object,       JSObject,          JSObject_Slots2,   false,  false) \
-    D(OBJECT2_BACKGROUND,  Object,       JSObject,          JSObject_Slots2,   true,   true)  \
-    D(OBJECT4,             Object,       JSObject,          JSObject_Slots4,   false,  false) \
-    D(OBJECT4_BACKGROUND,  Object,       JSObject,          JSObject_Slots4,   true,   true)  \
-    D(OBJECT8,             Object,       JSObject,          JSObject_Slots8,   false,  false) \
-    D(OBJECT8_BACKGROUND,  Object,       JSObject,          JSObject_Slots8,   true,   true)  \
-    D(OBJECT12,            Object,       JSObject,          JSObject_Slots12,  false,  false) \
-    D(OBJECT12_BACKGROUND, Object,       JSObject,          JSObject_Slots12,  true,   true)  \
-    D(OBJECT16,            Object,       JSObject,          JSObject_Slots16,  false,  false) \
-    D(OBJECT16_BACKGROUND, Object,       JSObject,          JSObject_Slots16,  true,   true)
+ /* AllocKind              TraceKind     TypeName           SizedType          BGFinal Nursery Compact */ \
+    D(FUNCTION,            Object,       JSObject,          JSFunction,        true,   true,   true) \
+    D(FUNCTION_EXTENDED,   Object,       JSObject,          FunctionExtended,  true,   true,   true) \
+    D(OBJECT0,             Object,       JSObject,          JSObject_Slots0,   false,  false,  true) \
+    D(OBJECT0_BACKGROUND,  Object,       JSObject,          JSObject_Slots0,   true,   true,   true) \
+    D(OBJECT2,             Object,       JSObject,          JSObject_Slots2,   false,  false,  true) \
+    D(OBJECT2_BACKGROUND,  Object,       JSObject,          JSObject_Slots2,   true,   true,   true) \
+    D(OBJECT4,             Object,       JSObject,          JSObject_Slots4,   false,  false,  true) \
+    D(OBJECT4_BACKGROUND,  Object,       JSObject,          JSObject_Slots4,   true,   true,   true) \
+    D(OBJECT8,             Object,       JSObject,          JSObject_Slots8,   false,  false,  true) \
+    D(OBJECT8_BACKGROUND,  Object,       JSObject,          JSObject_Slots8,   true,   true,   true) \
+    D(OBJECT12,            Object,       JSObject,          JSObject_Slots12,  false,  false,  true) \
+    D(OBJECT12_BACKGROUND, Object,       JSObject,          JSObject_Slots12,  true,   true,   true) \
+    D(OBJECT16,            Object,       JSObject,          JSObject_Slots16,  false,  false,  true) \
+    D(OBJECT16_BACKGROUND, Object,       JSObject,          JSObject_Slots16,  true,   true,   true)
 
 #define FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(D) \
- /* AllocKind              TraceKind     TypeName           SizedType          BGFinal Nursery */ \
-    D(SCRIPT,              Script,       JSScript,          JSScript,          false,  false) \
-    D(LAZY_SCRIPT,         LazyScript,   js::LazyScript,    js::LazyScript,    true,   false) \
-    D(SHAPE,               Shape,        js::Shape,         js::Shape,         true,   false) \
-    D(ACCESSOR_SHAPE,      Shape,        js::AccessorShape, js::AccessorShape, true,   false) \
-    D(BASE_SHAPE,          BaseShape,    js::BaseShape,     js::BaseShape,     true,   false) \
-    D(OBJECT_GROUP,        ObjectGroup,  js::ObjectGroup,   js::ObjectGroup,   true,   false) \
-    D(EXTERNAL_STRING,     String,       JSExternalString,  JSExternalString,  true,   false) \
-    D(FAT_INLINE_ATOM,     String,       js::FatInlineAtom, js::FatInlineAtom, true,   false) \
-    D(ATOM,                String,       js::NormalAtom,    js::NormalAtom,    true,   false) \
-    D(SYMBOL,              Symbol,       JS::Symbol,        JS::Symbol,        true,   false) \
-    IF_BIGINT(D(BIGINT,    BigInt,       JS::BigInt,        JS::BigInt,        true,   false),) \
-    D(JITCODE,             JitCode,      js::jit::JitCode,  js::jit::JitCode,  false,  false) \
-    D(SCOPE,               Scope,        js::Scope,         js::Scope,         true,   false) \
-    D(REGEXP_SHARED,       RegExpShared, js::RegExpShared,  js::RegExpShared,  true,   false)
+ /* AllocKind              TraceKind     TypeName           SizedType          BGFinal Nursery Compact */ \
+    D(SCRIPT,              Script,       JSScript,          JSScript,          false,  false,  true) \
+    D(LAZY_SCRIPT,         LazyScript,   js::LazyScript,    js::LazyScript,    true,   false,  true) \
+    D(SHAPE,               Shape,        js::Shape,         js::Shape,         true,   false,  true) \
+    D(ACCESSOR_SHAPE,      Shape,        js::AccessorShape, js::AccessorShape, true,   false,  true) \
+    D(BASE_SHAPE,          BaseShape,    js::BaseShape,     js::BaseShape,     true,   false,  true) \
+    D(OBJECT_GROUP,        ObjectGroup,  js::ObjectGroup,   js::ObjectGroup,   true,   false,  false) \
+    D(EXTERNAL_STRING,     String,       JSExternalString,  JSExternalString,  true,   false,  true) \
+    D(FAT_INLINE_ATOM,     String,       js::FatInlineAtom, js::FatInlineAtom, true,   false,  true) \
+    D(ATOM,                String,       js::NormalAtom,    js::NormalAtom,    true,   false,  true) \
+    D(SYMBOL,              Symbol,       JS::Symbol,        JS::Symbol,        true,   false,  false) \
+    IF_BIGINT(D(BIGINT,    BigInt,       JS::BigInt,        JS::BigInt,        true,   false,  false),) \
+    D(JITCODE,             JitCode,      js::jit::JitCode,  js::jit::JitCode,  false,  false,  false) \
+    D(SCOPE,               Scope,        js::Scope,         js::Scope,         true,   false,  true) \
+    D(REGEXP_SHARED,       RegExpShared, js::RegExpShared,  js::RegExpShared,  true,   false,  true)
 
 #define FOR_EACH_NURSERY_STRING_ALLOCKIND(D) \
-    D(FAT_INLINE_STRING,   String,        JSFatInlineString, JSFatInlineString, true,   true) \
-    D(STRING,              String,        JSString,          JSString,          true,   true)
+    D(FAT_INLINE_STRING,   String,        JSFatInlineString, JSFatInlineString, true,   true,  true) \
+    D(STRING,              String,        JSString,          JSString,          true,   true,  true)
 
 #define FOR_EACH_NONOBJECT_ALLOCKIND(D) \
     FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(D) \
     FOR_EACH_NURSERY_STRING_ALLOCKIND(D)
 
 #define FOR_EACH_ALLOCKIND(D)    \
     FOR_EACH_OBJECT_ALLOCKIND(D) \
     FOR_EACH_NONOBJECT_ALLOCKIND(D)
 
 enum class AllocKind : uint8_t {
-#define DEFINE_ALLOC_KIND(allocKind, _1, _2, _3, _4, _5) allocKind,
+#define DEFINE_ALLOC_KIND(allocKind, _1, _2, _3, _4, _5, _6) allocKind,
 
     FOR_EACH_OBJECT_ALLOCKIND(DEFINE_ALLOC_KIND)
 
     OBJECT_LIMIT,
     OBJECT_LAST = OBJECT_LIMIT - 1,
 
     FOR_EACH_NONOBJECT_ALLOCKIND(DEFINE_ALLOC_KIND)
 
@@ -164,17 +165,17 @@ template<typename ValueType> using AllAl
 // with each index corresponding to a particular object alloc kind.
 template<typename ValueType> using ObjectAllocKindArray =
     mozilla::EnumeratedArray<AllocKind, AllocKind::OBJECT_LIMIT, ValueType>;
 
 static inline JS::TraceKind
 MapAllocToTraceKind(AllocKind kind)
 {
     static const JS::TraceKind map[] = {
-#define EXPAND_ELEMENT(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define EXPAND_ELEMENT(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
         JS::TraceKind::traceKind,
 FOR_EACH_ALLOCKIND(EXPAND_ELEMENT)
 #undef EXPAND_ELEMENT
     };
 
     static_assert(mozilla::ArrayLength(map) == size_t(AllocKind::LIMIT),
                   "AllocKind-to-TraceKind mapping must be in sync");
     return map[size_t(kind)];
@@ -188,38 +189,60 @@ static const size_t MAX_BACKGROUND_FINAL
     size_t(AllocKind::LIMIT) - size_t(AllocKind::OBJECT_LIMIT) / 2;
 
 static inline bool
 IsNurseryAllocable(AllocKind kind)
 {
     MOZ_ASSERT(IsValidAllocKind(kind));
 
     static const bool map[] = {
-#define DEFINE_NURSERY_ALLOCABLE(_1, _2, _3, _4, _5, nursery) nursery,
+#define DEFINE_NURSERY_ALLOCABLE(_1, _2, _3, _4, _5, nursery, _6) nursery,
         FOR_EACH_ALLOCKIND(DEFINE_NURSERY_ALLOCABLE)
 #undef DEFINE_NURSERY_ALLOCABLE
     };
 
     static_assert(mozilla::ArrayLength(map) == size_t(AllocKind::LIMIT),
                   "IsNurseryAllocable sanity check");
     return map[size_t(kind)];
 }
 
 static inline bool
 IsBackgroundFinalized(AllocKind kind)
 {
     MOZ_ASSERT(IsValidAllocKind(kind));
 
     static const bool map[] = {
-#define DEFINE_BACKGROUND_FINALIZED(_1, _2, _3, _4, bgFinal, _5) bgFinal,
+#define DEFINE_BACKGROUND_FINALIZED(_1, _2, _3, _4, bgFinal, _5, _6) bgFinal,
         FOR_EACH_ALLOCKIND(DEFINE_BACKGROUND_FINALIZED)
 #undef DEFINE_BG_FINALIZE
     };
 
     static_assert(mozilla::ArrayLength(map) == size_t(AllocKind::LIMIT),
                   "IsBackgroundFinalized sanity check");
     return map[size_t(kind)];
 }
 
+static inline bool
+IsCompactingKind(AllocKind kind)
+{
+    MOZ_ASSERT(IsValidAllocKind(kind));
+
+    static const bool map[] = {
+#define DEFINE_COMPACTING_KIND(_1, _2, _3, _4, _5, _6, compact) compact,
+        FOR_EACH_ALLOCKIND(DEFINE_COMPACTING_KIND)
+#undef DEFINE_COMPACTING_KIND
+    };
+
+    static_assert(mozilla::ArrayLength(map) == size_t(AllocKind::LIMIT),
+                  "IsCompactingKind sanity check");
+    return map[size_t(kind)];
+}
+
+static inline bool
+IsMovableKind(AllocKind kind)
+{
+    return IsNurseryAllocable(kind) || IsCompactingKind(kind);
+}
+
 } /* namespace gc */
 } /* namespace js */
 
 #endif /* gc_AllocKind_h */
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -197,17 +197,17 @@ js::AllocateString(JSContext* cx, Initia
         // get the benefit of the nursery.
         if (!allowGC)
             return nullptr;
     }
 
     return GCRuntime::tryNewTenuredThing<StringAllocT, allowGC>(cx, kind, size);
 }
 
-#define DECL_ALLOCATOR_INSTANCES(allocKind, traceKind, type, sizedType, bgfinal, nursery) \
+#define DECL_ALLOCATOR_INSTANCES(allocKind, traceKind, type, sizedType, bgfinal, nursery, compact) \
     template type* js::AllocateString<type, NoGC>(JSContext* cx, InitialHeap heap);\
     template type* js::AllocateString<type, CanGC>(JSContext* cx, InitialHeap heap);
 FOR_EACH_NURSERY_STRING_ALLOCKIND(DECL_ALLOCATOR_INSTANCES)
 #undef DECL_ALLOCATOR_INSTANCES
 
 template <typename T, AllowGC allowGC /* = CanGC */>
 T*
 js::Allocate(JSContext* cx)
@@ -223,17 +223,17 @@ js::Allocate(JSContext* cx)
     if (!cx->helperThread()) {
         if (!cx->runtime()->gc.checkAllocatorState<allowGC>(cx, kind))
             return nullptr;
     }
 
     return GCRuntime::tryNewTenuredThing<T, allowGC>(cx, kind, thingSize);
 }
 
-#define DECL_ALLOCATOR_INSTANCES(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define DECL_ALLOCATOR_INSTANCES(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
     template type* js::Allocate<type, NoGC>(JSContext* cx);\
     template type* js::Allocate<type, CanGC>(JSContext* cx);
 FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(DECL_ALLOCATOR_INSTANCES)
 #undef DECL_ALLOCATOR_INSTANCES
 
 template <typename T, AllowGC allowGC>
 /* static */ T*
 GCRuntime::tryNewTenuredThing(JSContext* cx, AllocKind kind, size_t thingSize)
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -382,55 +382,55 @@ const AllocKind gc::slotsToThingKind[] =
     /*  8 */ AllocKind::OBJECT8,  AllocKind::OBJECT12, AllocKind::OBJECT12, AllocKind::OBJECT12,
     /* 12 */ AllocKind::OBJECT12, AllocKind::OBJECT16, AllocKind::OBJECT16, AllocKind::OBJECT16,
     /* 16 */ AllocKind::OBJECT16
 };
 
 static_assert(mozilla::ArrayLength(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT,
               "We have defined a slot count for each kind.");
 
-#define CHECK_THING_SIZE(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define CHECK_THING_SIZE(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
     static_assert(sizeof(sizedType) >= SortedArenaList::MinThingSize, \
                   #sizedType " is smaller than SortedArenaList::MinThingSize!"); \
     static_assert(sizeof(sizedType) >= sizeof(FreeSpan), \
                   #sizedType " is smaller than FreeSpan"); \
     static_assert(sizeof(sizedType) % CellAlignBytes == 0, \
                   "Size of " #sizedType " is not a multiple of CellAlignBytes"); \
     static_assert(sizeof(sizedType) >= MinCellSize, \
                   "Size of " #sizedType " is smaller than the minimum size");
 FOR_EACH_ALLOCKIND(CHECK_THING_SIZE);
 #undef CHECK_THING_SIZE
 
 const uint32_t Arena::ThingSizes[] = {
-#define EXPAND_THING_SIZE(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define EXPAND_THING_SIZE(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
     sizeof(sizedType),
 FOR_EACH_ALLOCKIND(EXPAND_THING_SIZE)
 #undef EXPAND_THING_SIZE
 };
 
 FreeSpan FreeLists::emptySentinel;
 
 #undef CHECK_THING_SIZE_INNER
 #undef CHECK_THING_SIZE
 
 #define OFFSET(type) uint32_t(ArenaHeaderSize + (ArenaSize - ArenaHeaderSize) % sizeof(type))
 
 const uint32_t Arena::FirstThingOffsets[] = {
-#define EXPAND_FIRST_THING_OFFSET(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define EXPAND_FIRST_THING_OFFSET(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
     OFFSET(sizedType),
 FOR_EACH_ALLOCKIND(EXPAND_FIRST_THING_OFFSET)
 #undef EXPAND_FIRST_THING_OFFSET
 };
 
 #undef OFFSET
 
 #define COUNT(type) uint32_t((ArenaSize - ArenaHeaderSize) / sizeof(type))
 
 const uint32_t Arena::ThingsPerArena[] = {
-#define EXPAND_THINGS_PER_ARENA(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define EXPAND_THINGS_PER_ARENA(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
     COUNT(sizedType),
 FOR_EACH_ALLOCKIND(EXPAND_THINGS_PER_ARENA)
 #undef EXPAND_THINGS_PER_ARENA
 };
 
 #undef COUNT
 
 struct js::gc::FinalizePhase
@@ -685,17 +685,17 @@ static bool
 FinalizeArenas(FreeOp* fop,
                Arena** src,
                SortedArenaList& dest,
                AllocKind thingKind,
                SliceBudget& budget,
                ArenaLists::KeepArenasEnum keepArenas)
 {
     switch (thingKind) {
-#define EXPAND_CASE(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define EXPAND_CASE(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
       case AllocKind::allocKind: \
         return FinalizeTypedArenas<type>(fop, src, dest, thingKind, budget, keepArenas);
 FOR_EACH_ALLOCKIND(EXPAND_CASE)
 #undef EXPAND_CASE
 
       default:
         MOZ_CRASH("Invalid alloc kind");
     }
@@ -1227,17 +1227,17 @@ GCRuntime::parseAndSetZeal(const char* s
 
     return true;
 }
 
 static const char*
 AllocKindName(AllocKind kind)
 {
     static const char* names[] = {
-#define EXPAND_THING_NAME(allocKind, _1, _2, _3, _4, _5) \
+#define EXPAND_THING_NAME(allocKind, _1, _2, _3, _4, _5, _6) \
         #allocKind,
 FOR_EACH_ALLOCKIND(EXPAND_THING_NAME)
 #undef EXPAND_THING_NAME
     };
     static_assert(ArrayLength(names) == size_t(AllocKind::LIMIT),
                   "names array should have an entry for every AllocKind");
 
     size_t i = size_t(kind);
@@ -2165,45 +2165,16 @@ AutoDisableCompactingGC::~AutoDisableCom
 }
 
 static bool
 CanRelocateZone(Zone* zone)
 {
     return !zone->isAtomsZone() && !zone->isSelfHostingZone();
 }
 
-static const AllocKind AllocKindsToRelocate[] = {
-    AllocKind::FUNCTION,
-    AllocKind::FUNCTION_EXTENDED,
-    AllocKind::OBJECT0,
-    AllocKind::OBJECT0_BACKGROUND,
-    AllocKind::OBJECT2,
-    AllocKind::OBJECT2_BACKGROUND,
-    AllocKind::OBJECT4,
-    AllocKind::OBJECT4_BACKGROUND,
-    AllocKind::OBJECT8,
-    AllocKind::OBJECT8_BACKGROUND,
-    AllocKind::OBJECT12,
-    AllocKind::OBJECT12_BACKGROUND,
-    AllocKind::OBJECT16,
-    AllocKind::OBJECT16_BACKGROUND,
-    AllocKind::SCRIPT,
-    AllocKind::LAZY_SCRIPT,
-    AllocKind::SHAPE,
-    AllocKind::ACCESSOR_SHAPE,
-    AllocKind::BASE_SHAPE,
-    AllocKind::FAT_INLINE_STRING,
-    AllocKind::STRING,
-    AllocKind::EXTERNAL_STRING,
-    AllocKind::FAT_INLINE_ATOM,
-    AllocKind::ATOM,
-    AllocKind::SCOPE,
-    AllocKind::REGEXP_SHARED
-};
-
 Arena*
 ArenaList::removeRemainingArenas(Arena** arenap)
 {
     // This is only ever called to remove arenas that are after the cursor, so
     // we don't need to update it.
 #ifdef DEBUG
     for (Arena* arena = *arenap; arena; arena = arena->next)
         MOZ_ASSERT(cursorp_ != &arena->next);
@@ -2429,50 +2400,64 @@ ShouldRelocateZone(size_t arenaCount, si
         return false;
 
     if (IsOOMReason(reason))
         return true;
 
     return (relocCount * 100.0) / arenaCount >= MIN_ZONE_RECLAIM_PERCENT;
 }
 
+static AllocKinds
+CompactingAllocKinds()
+{
+    AllocKinds result;
+    for (AllocKind kind : AllAllocKinds()) {
+        if (IsCompactingKind(kind))
+            result += kind;
+    }
+    return result;
+}
+
 bool
 ArenaLists::relocateArenas(Arena*& relocatedListOut, JS::gcreason::Reason reason,
                            SliceBudget& sliceBudget, gcstats::Statistics& stats)
 {
     // This is only called from the main thread while we are doing a GC, so
     // there is no need to lock.
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
     MOZ_ASSERT(runtime()->gc.isHeapCompacting());
     MOZ_ASSERT(!runtime()->gc.isBackgroundSweeping());
 
+    // Relocate all compatible kinds
+    AllocKinds allocKindsToRelocate = CompactingAllocKinds();
+
     // Clear all the free lists.
     clearFreeLists();
 
     if (ShouldRelocateAllArenas(reason)) {
         zone_->prepareForCompacting();
-        for (auto kind : AllocKindsToRelocate) {
+        for (auto kind : allocKindsToRelocate) {
             ArenaList& al = arenaLists(kind);
             Arena* allArenas = al.head();
             al.clear();
             relocatedListOut = al.relocateArenas(allArenas, relocatedListOut, sliceBudget, stats);
         }
     } else {
         size_t arenaCount = 0;
         size_t relocCount = 0;
         AllAllocKindArray<Arena**> toRelocate;
 
-        for (auto kind : AllocKindsToRelocate)
+        for (auto kind : allocKindsToRelocate)
             toRelocate[kind] = arenaLists(kind).pickArenasToRelocate(arenaCount, relocCount);
 
         if (!ShouldRelocateZone(arenaCount, relocCount, reason))
             return false;
 
         zone_->prepareForCompacting();
-        for (auto kind : AllocKindsToRelocate) {
+        for (auto kind : allocKindsToRelocate) {
             if (toRelocate[kind]) {
                 ArenaList& al = arenaLists(kind);
                 Arena* arenas = al.removeRemainingArenas(toRelocate[kind]);
                 relocatedListOut = al.relocateArenas(arenas, relocatedListOut, sliceBudget, stats);
             }
         }
     }
 
@@ -2491,22 +2476,22 @@ GCRuntime::relocateArenas(Zone* zone, JS
     js::CancelOffThreadIonCompile(rt, JS::Zone::Compact);
 
     if (!zone->arenas.relocateArenas(relocatedListOut, reason, sliceBudget, stats()))
         return false;
 
 #ifdef DEBUG
     // Check that we did as much compaction as we should have. There
     // should always be less than one arena's worth of free cells.
-    for (auto i : AllocKindsToRelocate) {
-        ArenaList& al = zone->arenas.arenaLists(i);
+    for (auto kind : CompactingAllocKinds()) {
+        ArenaList& al = zone->arenas.arenaLists(kind);
         size_t freeCells = 0;
         for (Arena* arena = al.arenaAfterCursor(); arena; arena = arena->next)
             freeCells += arena->countFreeCells();
-        MOZ_ASSERT(freeCells < Arena::thingsPerArena(i));
+        MOZ_ASSERT(freeCells < Arena::thingsPerArena(kind));
     }
 #endif
 
     return true;
 }
 
 template <typename T>
 inline void
@@ -2596,17 +2581,17 @@ UpdateArenaPointersTyped(MovingTracer* t
  * Update the internal pointers for all cells in an arena.
  */
 static void
 UpdateArenaPointers(MovingTracer* trc, Arena* arena)
 {
     AllocKind kind = arena->getAllocKind();
 
     switch (kind) {
-#define EXPAND_CASE(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define EXPAND_CASE(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
       case AllocKind::allocKind: \
         UpdateArenaPointersTyped<type>(trc, arena); \
         return;
 FOR_EACH_ALLOCKIND(EXPAND_CASE)
 #undef EXPAND_CASE
 
       default:
         MOZ_CRASH("Invalid alloc kind for UpdateArenaPointers");
@@ -3947,17 +3932,17 @@ GCRuntime::sweepZones(FreeOp* fop, bool 
     zones().shrinkTo(write - zones().begin());
 }
 
 #ifdef DEBUG
 static const char*
 AllocKindToAscii(AllocKind kind)
 {
     switch(kind) {
-#define MAKE_CASE(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define MAKE_CASE(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
       case AllocKind:: allocKind: return #allocKind;
 FOR_EACH_ALLOCKIND(MAKE_CASE)
 #undef MAKE_CASE
 
       default:
         MOZ_CRASH("Unknown AllocKind in AllocKindToAscii");
     }
 }
--- a/js/src/gc/GC.h
+++ b/js/src/gc/GC.h
@@ -38,17 +38,17 @@ struct Cell;
 
 /*
  * Map from C++ type to alloc kind for non-object types. JSObject does not have
  * a 1:1 mapping, so must use Arena::thingSize.
  *
  * The AllocKind is available as MapTypeToFinalizeKind<SomeType>::kind.
  */
 template <typename T> struct MapTypeToFinalizeKind {};
-#define EXPAND_MAPTYPETOFINALIZEKIND(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
+#define EXPAND_MAPTYPETOFINALIZEKIND(allocKind, traceKind, type, sizedType, bgFinal, nursery, compact) \
     template <> struct MapTypeToFinalizeKind<type> { \
         static const AllocKind kind = AllocKind::allocKind; \
     };
 FOR_EACH_NONOBJECT_ALLOCKIND(EXPAND_MAPTYPETOFINALIZEKIND)
 #undef EXPAND_MAPTYPETOFINALIZEKIND
 
 } /* namespace gc */
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -692,16 +692,19 @@ JitRuntime::getVMWrapper(const VMFunctio
     JitRuntime::VMWrapperMap::Ptr p = functionWrappers_->readonlyThreadsafeLookup(&f);
     MOZ_ASSERT(p);
     return trampolineCode(p->value());
 }
 
 void
 JitCodeHeader::init(JitCode* jitCode)
 {
+    // As long as JitCode isn't moveable, we can avoid tracing this and
+    // mutating executable data.
+    MOZ_ASSERT(!gc::IsMovableKind(gc::AllocKind::JITCODE));
     jitCode_ = jitCode;
 
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // On AMD Bobcat processors that may have eratas, insert a NOP slide to reduce crashes
     if (CPUInfo::NeedAmdBugWorkaround())
         memset((char *)&nops_, X86Encoding::OneByteOpcodeID::OP_NOP, sizeof(nops_));
 #endif
 }