Bug 1412912 - Split out JSObject alloc kind helper functions into ObjectKind-inl.h r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 01 Nov 2017 15:37:47 +0000
changeset 690388 45eedc2acce303672f97a8752bfccfff7e23d9a0
parent 690387 dd1780b996ee9f4b919fc457ab1972b34360cee7
child 690389 370c73377b901036c54071cd42517d6f1144b613
push id87288
push usercholler@mozilla.com
push dateWed, 01 Nov 2017 22:09:51 +0000
reviewerssfink
bugs1412912
milestone58.0a1
Bug 1412912 - Split out JSObject alloc kind helper functions into ObjectKind-inl.h r=sfink
js/src/builtin/TypedObject-inl.h
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/frontend/BytecodeEmitter.cpp
js/src/gc/AllocKind.h
js/src/gc/Allocator.cpp
js/src/gc/Allocator.h
js/src/gc/Marking.cpp
js/src/gc/ObjectKind-inl.h
js/src/jit/MIR.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jsobj.cpp
js/src/jsobjinlines.h
js/src/vm/ArrayObject-inl.h
js/src/vm/EnvironmentObject.cpp
js/src/vm/NativeObject-inl.h
js/src/vm/ObjectGroup.cpp
js/src/vm/ProxyObject.cpp
js/src/vm/Scope.cpp
js/src/vm/TypedArrayObject-inl.h
js/src/vm/TypedArrayObject.h
js/src/vm/UnboxedObject-inl.h
js/src/vm/UnboxedObject.h
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/TypedObject-inl.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef builtin_TypedObject_inl_h
+#define builtin_TypedObject_inl_h
+
+#include "builtin/TypedObject.h"
+
+#include "gc/ObjectKind-inl.h"
+
+/* static */
+js::gc::AllocKind
+js::InlineTypedObject::allocKindForTypeDescriptor(TypeDescr* descr)
+{
+    size_t nbytes = descr->size();
+    MOZ_ASSERT(nbytes <= MaximumSize);
+
+    return gc::GetGCObjectKindForBytes(nbytes + sizeof(TypedObject));
+}
+
+#endif // builtin_TypedObject_inl_h
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "builtin/TypedObject.h"
+#include "builtin/TypedObject-inl.h"
 
 #include "mozilla/Casting.h"
 #include "mozilla/CheckedInt.h"
 
 #include "jscompartment.h"
 #include "jsfun.h"
 #include "jsutil.h"
 
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -702,22 +702,17 @@ class InlineTypedObject : public TypedOb
   protected:
     uint8_t* inlineTypedMem() const {
         return (uint8_t*) &data_;
     }
 
   public:
     static const size_t MaximumSize = JSObject::MAX_BYTE_SIZE - sizeof(TypedObject);
 
-    static gc::AllocKind allocKindForTypeDescriptor(TypeDescr* descr) {
-        size_t nbytes = descr->size();
-        MOZ_ASSERT(nbytes <= MaximumSize);
-
-        return gc::GetGCObjectKindForBytes(nbytes + sizeof(TypedObject));
-    }
+    static inline gc::AllocKind allocKindForTypeDescriptor(TypeDescr* descr);
 
     uint8_t* inlineTypedMem(const JS::AutoRequireNoGC&) const {
         return inlineTypedMem();
     }
 
     uint8_t* inlineTypedMemForGC() const {
         return inlineTypedMem();
     }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -32,17 +32,16 @@
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "vm/Debugger.h"
 #include "vm/GeneratorObject.h"
 #include "vm/Stack.h"
 #include "wasm/AsmJS.h"
 
 #include "jsatominlines.h"
-#include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "frontend/ParseNode-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
--- a/js/src/gc/AllocKind.h
+++ b/js/src/gc/AllocKind.h
@@ -186,12 +186,90 @@ FOR_EACH_ALLOCKIND(EXPAND_ELEMENT)
 
 /*
  * This must be an upper bound, but we do not need the least upper bound, so
  * we just exclude non-background objects.
  */
 static const size_t MAX_BACKGROUND_FINALIZE_KINDS =
     size_t(AllocKind::LIMIT) - size_t(AllocKind::OBJECT_LIMIT) / 2;
 
+static inline bool
+IsNurseryAllocable(AllocKind kind)
+{
+    MOZ_ASSERT(IsValidAllocKind(kind));
+    static const bool map[] = {
+        true,      /* AllocKind::FUNCTION */
+        true,      /* AllocKind::FUNCTION_EXTENDED */
+        false,     /* AllocKind::OBJECT0 */
+        true,      /* AllocKind::OBJECT0_BACKGROUND */
+        false,     /* AllocKind::OBJECT2 */
+        true,      /* AllocKind::OBJECT2_BACKGROUND */
+        false,     /* AllocKind::OBJECT4 */
+        true,      /* AllocKind::OBJECT4_BACKGROUND */
+        false,     /* AllocKind::OBJECT8 */
+        true,      /* AllocKind::OBJECT8_BACKGROUND */
+        false,     /* AllocKind::OBJECT12 */
+        true,      /* AllocKind::OBJECT12_BACKGROUND */
+        false,     /* AllocKind::OBJECT16 */
+        true,      /* AllocKind::OBJECT16_BACKGROUND */
+        false,     /* AllocKind::SCRIPT */
+        false,     /* AllocKind::LAZY_SCRIPT */
+        false,     /* AllocKind::SHAPE */
+        false,     /* AllocKind::ACCESSOR_SHAPE */
+        false,     /* AllocKind::BASE_SHAPE */
+        false,     /* AllocKind::OBJECT_GROUP */
+        false,     /* AllocKind::FAT_INLINE_STRING */
+        false,     /* AllocKind::STRING */
+        false,     /* AllocKind::EXTERNAL_STRING */
+        false,     /* AllocKind::FAT_INLINE_ATOM */
+        false,     /* AllocKind::ATOM */
+        false,     /* AllocKind::SYMBOL */
+        false,     /* AllocKind::JITCODE */
+        false,     /* AllocKind::SCOPE */
+        false,     /* AllocKind::REGEXP_SHARED */
+    };
+    JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == size_t(AllocKind::LIMIT));
+    return map[size_t(kind)];
+}
+
+static inline bool
+IsBackgroundFinalized(AllocKind kind)
+{
+    MOZ_ASSERT(IsValidAllocKind(kind));
+    static const bool map[] = {
+        true,      /* AllocKind::FUNCTION */
+        true,      /* AllocKind::FUNCTION_EXTENDED */
+        false,     /* AllocKind::OBJECT0 */
+        true,      /* AllocKind::OBJECT0_BACKGROUND */
+        false,     /* AllocKind::OBJECT2 */
+        true,      /* AllocKind::OBJECT2_BACKGROUND */
+        false,     /* AllocKind::OBJECT4 */
+        true,      /* AllocKind::OBJECT4_BACKGROUND */
+        false,     /* AllocKind::OBJECT8 */
+        true,      /* AllocKind::OBJECT8_BACKGROUND */
+        false,     /* AllocKind::OBJECT12 */
+        true,      /* AllocKind::OBJECT12_BACKGROUND */
+        false,     /* AllocKind::OBJECT16 */
+        true,      /* AllocKind::OBJECT16_BACKGROUND */
+        false,     /* AllocKind::SCRIPT */
+        true,      /* AllocKind::LAZY_SCRIPT */
+        true,      /* AllocKind::SHAPE */
+        true,      /* AllocKind::ACCESSOR_SHAPE */
+        true,      /* AllocKind::BASE_SHAPE */
+        true,      /* AllocKind::OBJECT_GROUP */
+        true,      /* AllocKind::FAT_INLINE_STRING */
+        true,      /* AllocKind::STRING */
+        true,      /* AllocKind::EXTERNAL_STRING */
+        true,      /* AllocKind::FAT_INLINE_ATOM */
+        true,      /* AllocKind::ATOM */
+        true,      /* AllocKind::SYMBOL */
+        false,     /* AllocKind::JITCODE */
+        true,      /* AllocKind::SCOPE */
+        true,      /* AllocKind::REGEXP_SHARED */
+    };
+    JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == size_t(AllocKind::LIMIT));
+    return map[size_t(kind)];
+}
+
 } /* namespace gc */
 } /* namespace js */
 
 #endif /* gc_AllocKind_h */
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -3,27 +3,27 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gc/Allocator.h"
 
 #include "jscntxt.h"
 
-#include "gc/ArenaList.h"
 #include "gc/GCInternals.h"
 #include "gc/GCTrace.h"
 #include "gc/Nursery.h"
 #include "jit/JitCompartment.h"
 #include "threading/CpuCount.h"
 #include "vm/Runtime.h"
 #include "vm/String.h"
 
 #include "jsobjinlines.h"
 
+#include "gc/ArenaList-inl.h"
 #include "gc/Heap-inl.h"
 
 using namespace js;
 using namespace gc;
 
 template <typename T, AllowGC allowGC /* = CanGC */>
 JSObject*
 js::Allocate(JSContext* cx, AllocKind kind, size_t nDynamicSlots, InitialHeap heap,
--- a/js/src/gc/Allocator.h
+++ b/js/src/gc/Allocator.h
@@ -6,16 +6,17 @@
 
 #ifndef gc_Allocator_h
 #define gc_Allocator_h
 
 #include "gc/Heap.h"
 #include "js/RootingAPI.h"
 
 namespace js {
+
 struct Class;
 
 // Allocate a new GC thing. After a successful allocation the caller must
 // fully initialize the thing before calling any function that can potentially
 // trigger GC. This will ensure that GC tracing never sees junk values stored
 // in the partially initialized thing.
 //
 // Note that JSObject allocation must use the longer signature below that
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -29,17 +29,16 @@
 #include "vm/Shape.h"
 #include "vm/Symbol.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/UnboxedObject.h"
 #include "wasm/WasmJS.h"
 
 #include "jscompartmentinlines.h"
 #include "jsgcinlines.h"
-#include "jsobjinlines.h"
 
 #include "gc/Nursery-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/String-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
new file mode 100644
--- /dev/null
+++ b/js/src/gc/ObjectKind-inl.h
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * GC-internal helper functions for getting the AllocKind used to allocate a
+ * JSObject and related information.
+ */
+
+#ifndef gc_ObjectKind_inl_h
+#define gc_ObjectKind_inl_h
+
+#include "vm/NativeObject.h"
+
+namespace js {
+namespace gc {
+
+static inline bool
+CanBeFinalizedInBackground(AllocKind kind, const Class* clasp)
+{
+    MOZ_ASSERT(IsObjectAllocKind(kind));
+    /* If the class has no finalizer or a finalizer that is safe to call on
+     * a different thread, we change the alloc kind. For example,
+     * AllocKind::OBJECT0 calls the finalizer on the active thread,
+     * AllocKind::OBJECT0_BACKGROUND calls the finalizer on the gcHelperThread.
+     * IsBackgroundFinalized is called to prevent recursively incrementing
+     * the alloc kind; kind may already be a background finalize kind.
+     */
+    return (!IsBackgroundFinalized(kind) &&
+            (!clasp->hasFinalize() || (clasp->flags & JSCLASS_BACKGROUND_FINALIZE)));
+}
+
+static inline AllocKind
+GetBackgroundAllocKind(AllocKind kind)
+{
+    MOZ_ASSERT(!IsBackgroundFinalized(kind));
+    MOZ_ASSERT(IsObjectAllocKind(kind));
+    return AllocKind(size_t(kind) + 1);
+}
+
+/* Capacity for slotsToThingKind */
+const size_t SLOTS_TO_THING_KIND_LIMIT = 17;
+
+extern const AllocKind slotsToThingKind[];
+
+/* Get the best kind to use when making an object with the given slot count. */
+static inline AllocKind
+GetGCObjectKind(size_t numSlots)
+{
+    if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
+        return AllocKind::OBJECT16;
+    return slotsToThingKind[numSlots];
+}
+
+static inline AllocKind
+GetGCObjectKind(const Class* clasp)
+{
+    if (clasp == FunctionClassPtr)
+        return AllocKind::FUNCTION;
+
+    MOZ_ASSERT(!clasp->isProxy(), "Proxies should use GetProxyGCObjectKind");
+
+    uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
+    if (clasp->flags & JSCLASS_HAS_PRIVATE)
+        nslots++;
+    return GetGCObjectKind(nslots);
+}
+
+/* As for GetGCObjectKind, but for dense array allocation. */
+static inline AllocKind
+GetGCArrayKind(size_t numElements)
+{
+    /*
+     * Dense arrays can use their fixed slots to hold their elements array
+     * (less two Values worth of ObjectElements header), but if more than the
+     * maximum number of fixed slots is needed then the fixed slots will be
+     * unused.
+     */
+    JS_STATIC_ASSERT(ObjectElements::VALUES_PER_HEADER == 2);
+    if (numElements > NativeObject::MAX_DENSE_ELEMENTS_COUNT ||
+        numElements + ObjectElements::VALUES_PER_HEADER >= SLOTS_TO_THING_KIND_LIMIT)
+    {
+        return AllocKind::OBJECT2;
+    }
+    return slotsToThingKind[numElements + ObjectElements::VALUES_PER_HEADER];
+}
+
+static inline AllocKind
+GetGCObjectFixedSlotsKind(size_t numFixedSlots)
+{
+    MOZ_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT);
+    return slotsToThingKind[numFixedSlots];
+}
+
+// Get the best kind to use when allocating an object that needs a specific
+// number of bytes.
+static inline AllocKind
+GetGCObjectKindForBytes(size_t nbytes)
+{
+    MOZ_ASSERT(nbytes <= JSObject::MAX_BYTE_SIZE);
+
+    if (nbytes <= sizeof(NativeObject))
+        return AllocKind::OBJECT0;
+    nbytes -= sizeof(NativeObject);
+
+    size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
+    MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
+    return GetGCObjectKind(dataSlots);
+}
+
+/* Get the number of fixed slots and initial capacity associated with a kind. */
+static inline size_t
+GetGCKindSlots(AllocKind thingKind)
+{
+    /* Using a switch in hopes that thingKind will usually be a compile-time constant. */
+    switch (thingKind) {
+      case AllocKind::FUNCTION:
+      case AllocKind::OBJECT0:
+      case AllocKind::OBJECT0_BACKGROUND:
+        return 0;
+      case AllocKind::FUNCTION_EXTENDED:
+      case AllocKind::OBJECT2:
+      case AllocKind::OBJECT2_BACKGROUND:
+        return 2;
+      case AllocKind::OBJECT4:
+      case AllocKind::OBJECT4_BACKGROUND:
+        return 4;
+      case AllocKind::OBJECT8:
+      case AllocKind::OBJECT8_BACKGROUND:
+        return 8;
+      case AllocKind::OBJECT12:
+      case AllocKind::OBJECT12_BACKGROUND:
+        return 12;
+      case AllocKind::OBJECT16:
+      case AllocKind::OBJECT16_BACKGROUND:
+        return 16;
+      default:
+        MOZ_CRASH("Bad object alloc kind");
+    }
+}
+
+static inline size_t
+GetGCKindSlots(AllocKind thingKind, const Class* clasp)
+{
+    size_t nslots = GetGCKindSlots(thingKind);
+
+    /* An object's private data uses the space taken by its last fixed slot. */
+    if (clasp->flags & JSCLASS_HAS_PRIVATE) {
+        MOZ_ASSERT(nslots > 0);
+        nslots--;
+    }
+
+    /*
+     * Functions have a larger alloc kind than AllocKind::OBJECT to reserve
+     * space for the extra fields in JSFunction, but have no fixed slots.
+     */
+    if (clasp == FunctionClassPtr)
+        nslots = 0;
+
+    return nslots;
+}
+
+static inline size_t
+GetGCKindBytes(AllocKind thingKind)
+{
+    return sizeof(JSObject_Slots0) + GetGCKindSlots(thingKind) * sizeof(Value);
+}
+
+} // namespace gc
+} // namespace js
+
+#endif // gc_ObjectKind_inl_h
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -24,16 +24,17 @@
 #include "jit/MIRGraph.h"
 #include "jit/RangeAnalysis.h"
 #include "js/Conversions.h"
 
 #include "jsatominlines.h"
 #include "jsboolinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
+#include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using JS::ToInt32;
 
 using mozilla::CheckedInt;
 using mozilla::NumbersAreIdentical;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -79,231 +79,16 @@ FOR_EACH_NONOBJECT_ALLOCKIND(EXPAND_MAPT
 #undef EXPAND_MAPTYPETOFINALIZEKIND
 
 template <typename T> struct ParticipatesInCC {};
 #define EXPAND_PARTICIPATES_IN_CC(_, type, addToCCKind) \
     template <> struct ParticipatesInCC<type> { static const bool value = addToCCKind; };
 JS_FOR_EACH_TRACEKIND(EXPAND_PARTICIPATES_IN_CC)
 #undef EXPAND_PARTICIPATES_IN_CC
 
-static inline bool
-IsNurseryAllocable(AllocKind kind)
-{
-    MOZ_ASSERT(IsValidAllocKind(kind));
-    static const bool map[] = {
-        true,      /* AllocKind::FUNCTION */
-        true,      /* AllocKind::FUNCTION_EXTENDED */
-        false,     /* AllocKind::OBJECT0 */
-        true,      /* AllocKind::OBJECT0_BACKGROUND */
-        false,     /* AllocKind::OBJECT2 */
-        true,      /* AllocKind::OBJECT2_BACKGROUND */
-        false,     /* AllocKind::OBJECT4 */
-        true,      /* AllocKind::OBJECT4_BACKGROUND */
-        false,     /* AllocKind::OBJECT8 */
-        true,      /* AllocKind::OBJECT8_BACKGROUND */
-        false,     /* AllocKind::OBJECT12 */
-        true,      /* AllocKind::OBJECT12_BACKGROUND */
-        false,     /* AllocKind::OBJECT16 */
-        true,      /* AllocKind::OBJECT16_BACKGROUND */
-        false,     /* AllocKind::SCRIPT */
-        false,     /* AllocKind::LAZY_SCRIPT */
-        false,     /* AllocKind::SHAPE */
-        false,     /* AllocKind::ACCESSOR_SHAPE */
-        false,     /* AllocKind::BASE_SHAPE */
-        false,     /* AllocKind::OBJECT_GROUP */
-        false,     /* AllocKind::FAT_INLINE_STRING */
-        false,     /* AllocKind::STRING */
-        false,     /* AllocKind::EXTERNAL_STRING */
-        false,     /* AllocKind::FAT_INLINE_ATOM */
-        false,     /* AllocKind::ATOM */
-        false,     /* AllocKind::SYMBOL */
-        false,     /* AllocKind::JITCODE */
-        false,     /* AllocKind::SCOPE */
-        false,     /* AllocKind::REGEXP_SHARED */
-    };
-    JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == size_t(AllocKind::LIMIT));
-    return map[size_t(kind)];
-}
-
-static inline bool
-IsBackgroundFinalized(AllocKind kind)
-{
-    MOZ_ASSERT(IsValidAllocKind(kind));
-    static const bool map[] = {
-        true,      /* AllocKind::FUNCTION */
-        true,      /* AllocKind::FUNCTION_EXTENDED */
-        false,     /* AllocKind::OBJECT0 */
-        true,      /* AllocKind::OBJECT0_BACKGROUND */
-        false,     /* AllocKind::OBJECT2 */
-        true,      /* AllocKind::OBJECT2_BACKGROUND */
-        false,     /* AllocKind::OBJECT4 */
-        true,      /* AllocKind::OBJECT4_BACKGROUND */
-        false,     /* AllocKind::OBJECT8 */
-        true,      /* AllocKind::OBJECT8_BACKGROUND */
-        false,     /* AllocKind::OBJECT12 */
-        true,      /* AllocKind::OBJECT12_BACKGROUND */
-        false,     /* AllocKind::OBJECT16 */
-        true,      /* AllocKind::OBJECT16_BACKGROUND */
-        false,     /* AllocKind::SCRIPT */
-        true,      /* AllocKind::LAZY_SCRIPT */
-        true,      /* AllocKind::SHAPE */
-        true,      /* AllocKind::ACCESSOR_SHAPE */
-        true,      /* AllocKind::BASE_SHAPE */
-        true,      /* AllocKind::OBJECT_GROUP */
-        true,      /* AllocKind::FAT_INLINE_STRING */
-        true,      /* AllocKind::STRING */
-        true,      /* AllocKind::EXTERNAL_STRING */
-        true,      /* AllocKind::FAT_INLINE_ATOM */
-        true,      /* AllocKind::ATOM */
-        true,      /* AllocKind::SYMBOL */
-        false,     /* AllocKind::JITCODE */
-        true,      /* AllocKind::SCOPE */
-        true,      /* AllocKind::REGEXP_SHARED */
-    };
-    JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == size_t(AllocKind::LIMIT));
-    return map[size_t(kind)];
-}
-
-static inline bool
-CanBeFinalizedInBackground(AllocKind kind, const Class* clasp)
-{
-    MOZ_ASSERT(IsObjectAllocKind(kind));
-    /* If the class has no finalizer or a finalizer that is safe to call on
-     * a different thread, we change the alloc kind. For example,
-     * AllocKind::OBJECT0 calls the finalizer on the active thread,
-     * AllocKind::OBJECT0_BACKGROUND calls the finalizer on the gcHelperThread.
-     * IsBackgroundFinalized is called to prevent recursively incrementing
-     * the alloc kind; kind may already be a background finalize kind.
-     */
-    return (!IsBackgroundFinalized(kind) &&
-            (!clasp->hasFinalize() || (clasp->flags & JSCLASS_BACKGROUND_FINALIZE)));
-}
-
-/* Capacity for slotsToThingKind */
-const size_t SLOTS_TO_THING_KIND_LIMIT = 17;
-
-extern const AllocKind slotsToThingKind[];
-
-/* Get the best kind to use when making an object with the given slot count. */
-static inline AllocKind
-GetGCObjectKind(size_t numSlots)
-{
-    if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
-        return AllocKind::OBJECT16;
-    return slotsToThingKind[numSlots];
-}
-
-/* As for GetGCObjectKind, but for dense array allocation. */
-static inline AllocKind
-GetGCArrayKind(size_t numElements)
-{
-    /*
-     * Dense arrays can use their fixed slots to hold their elements array
-     * (less two Values worth of ObjectElements header), but if more than the
-     * maximum number of fixed slots is needed then the fixed slots will be
-     * unused.
-     */
-    JS_STATIC_ASSERT(ObjectElements::VALUES_PER_HEADER == 2);
-    if (numElements > NativeObject::MAX_DENSE_ELEMENTS_COUNT ||
-        numElements + ObjectElements::VALUES_PER_HEADER >= SLOTS_TO_THING_KIND_LIMIT)
-    {
-        return AllocKind::OBJECT2;
-    }
-    return slotsToThingKind[numElements + ObjectElements::VALUES_PER_HEADER];
-}
-
-static inline AllocKind
-GetGCObjectFixedSlotsKind(size_t numFixedSlots)
-{
-    MOZ_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT);
-    return slotsToThingKind[numFixedSlots];
-}
-
-// Get the best kind to use when allocating an object that needs a specific
-// number of bytes.
-static inline AllocKind
-GetGCObjectKindForBytes(size_t nbytes)
-{
-    MOZ_ASSERT(nbytes <= JSObject::MAX_BYTE_SIZE);
-
-    if (nbytes <= sizeof(NativeObject))
-        return AllocKind::OBJECT0;
-    nbytes -= sizeof(NativeObject);
-
-    size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
-    MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
-    return GetGCObjectKind(dataSlots);
-}
-
-static inline AllocKind
-GetBackgroundAllocKind(AllocKind kind)
-{
-    MOZ_ASSERT(!IsBackgroundFinalized(kind));
-    MOZ_ASSERT(IsObjectAllocKind(kind));
-    return AllocKind(size_t(kind) + 1);
-}
-
-/* Get the number of fixed slots and initial capacity associated with a kind. */
-static inline size_t
-GetGCKindSlots(AllocKind thingKind)
-{
-    /* Using a switch in hopes that thingKind will usually be a compile-time constant. */
-    switch (thingKind) {
-      case AllocKind::FUNCTION:
-      case AllocKind::OBJECT0:
-      case AllocKind::OBJECT0_BACKGROUND:
-        return 0;
-      case AllocKind::FUNCTION_EXTENDED:
-      case AllocKind::OBJECT2:
-      case AllocKind::OBJECT2_BACKGROUND:
-        return 2;
-      case AllocKind::OBJECT4:
-      case AllocKind::OBJECT4_BACKGROUND:
-        return 4;
-      case AllocKind::OBJECT8:
-      case AllocKind::OBJECT8_BACKGROUND:
-        return 8;
-      case AllocKind::OBJECT12:
-      case AllocKind::OBJECT12_BACKGROUND:
-        return 12;
-      case AllocKind::OBJECT16:
-      case AllocKind::OBJECT16_BACKGROUND:
-        return 16;
-      default:
-        MOZ_CRASH("Bad object alloc kind");
-    }
-}
-
-static inline size_t
-GetGCKindSlots(AllocKind thingKind, const Class* clasp)
-{
-    size_t nslots = GetGCKindSlots(thingKind);
-
-    /* An object's private data uses the space taken by its last fixed slot. */
-    if (clasp->flags & JSCLASS_HAS_PRIVATE) {
-        MOZ_ASSERT(nslots > 0);
-        nslots--;
-    }
-
-    /*
-     * Functions have a larger alloc kind than AllocKind::OBJECT to reserve
-     * space for the extra fields in JSFunction, but have no fixed slots.
-     */
-    if (clasp == FunctionClassPtr)
-        nslots = 0;
-
-    return nslots;
-}
-
-static inline size_t
-GetGCKindBytes(AllocKind thingKind)
-{
-    return sizeof(JSObject_Slots0) + GetGCKindSlots(thingKind) * sizeof(Value);
-}
-
 /* The number of GC cycles an empty chunk can survive before been released. */
 const size_t MAX_EMPTY_CHUNK_AGE = 4;
 
 extern bool
 InitializeStaticData();
 
 } /* namespace gc */
 
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -24,30 +24,16 @@ inline void
 MakeAccessibleAfterMovingGC(void* anyp) {}
 
 inline void
 MakeAccessibleAfterMovingGC(JSObject* obj) {
     if (obj->isNative())
         obj->as<NativeObject>().updateShapeAfterMovingGC();
 }
 
-static inline AllocKind
-GetGCObjectKind(const Class* clasp)
-{
-    if (clasp == FunctionClassPtr)
-        return AllocKind::FUNCTION;
-
-    MOZ_ASSERT(!clasp->isProxy(), "Proxies should use GetProxyGCObjectKind");
-
-    uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
-    if (clasp->flags & JSCLASS_HAS_PRIVATE)
-        nslots++;
-    return GetGCObjectKind(nslots);
-}
-
 class ArenaIter
 {
     Arena* arena;
     Arena* unsweptArena;
     Arena* sweptArena;
     mozilla::DebugOnly<bool> initialized;
 
   public:
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -53,24 +53,27 @@
 #include "vm/Shape.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jsatominlines.h"
 #include "jsboolinlines.h"
 #include "jscntxtinlines.h"
 #include "jscompartmentinlines.h"
 
+#include "builtin/TypedObject-inl.h"
 #include "vm/ArrayObject-inl.h"
 #include "vm/BooleanObject-inl.h"
 #include "vm/Caches-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/Shape-inl.h"
 #include "vm/StringObject-inl.h"
+#include "vm/TypedArrayObject-inl.h"
+#include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::DebugOnly;
 using mozilla::Maybe;
 
 void
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -24,16 +24,17 @@
 #include "vm/Probes.h"
 #include "vm/StringObject.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jsatominlines.h"
 #include "jscompartmentinlines.h"
 #include "jsgcinlines.h"
 
+#include "gc/ObjectKind-inl.h"
 #include "vm/ShapedObject-inl.h"
 #include "vm/TypeInference-inl.h"
 
 namespace js {
 
 // This is needed here for ensureShape() below.
 inline bool
 MaybeConvertUnboxedObjectToNative(JSContext* cx, JSObject* obj)
--- a/js/src/vm/ArrayObject-inl.h
+++ b/js/src/vm/ArrayObject-inl.h
@@ -7,17 +7,16 @@
 #ifndef vm_ArrayObject_inl_h
 #define vm_ArrayObject_inl_h
 
 #include "vm/ArrayObject.h"
 
 #include "gc/GCTrace.h"
 #include "vm/String.h"
 
-#include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/TypeInference-inl.h"
 
 namespace js {
 
 inline void
 ArrayObject::setLength(JSContext* cx, uint32_t length)
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -18,17 +18,16 @@
 #include "vm/AsyncFunction.h"
 #include "vm/GlobalObject.h"
 #include "vm/ProxyObject.h"
 #include "vm/Shape.h"
 #include "vm/Xdr.h"
 #include "wasm/WasmInstance.h"
 
 #include "jsatominlines.h"
-#include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/NativeObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -7,23 +7,25 @@
 #ifndef vm_NativeObject_inl_h
 #define vm_NativeObject_inl_h
 
 #include "vm/NativeObject.h"
 
 #include "jscntxt.h"
 
 #include "builtin/TypedObject.h"
+#include "gc/GCTrace.h"
 #include "proxy/Proxy.h"
 #include "vm/ProxyObject.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jsobjinlines.h"
 
 #include "gc/Heap-inl.h"
+#include "gc/ObjectKind-inl.h"
 
 namespace js {
 
 inline uint8_t*
 NativeObject::fixedData(size_t nslots) const
 {
     MOZ_ASSERT(ClassCanHaveFixedData(getClass()));
     MOZ_ASSERT(nslots == numFixedSlots() + (hasPrivate() ? 1 : 0));
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -15,19 +15,16 @@
 #include "gc/Policy.h"
 #include "gc/StoreBuffer.h"
 #include "gc/Zone.h"
 #include "js/CharacterEncoding.h"
 #include "vm/ArrayObject.h"
 #include "vm/RegExpObject.h"
 #include "vm/Shape.h"
 #include "vm/TaggedProto.h"
-#include "vm/UnboxedObject.h"
-
-#include "jsobjinlines.h"
 
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 using mozilla::DebugOnly;
 using mozilla::PodZero;
 
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -3,20 +3,25 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/ProxyObject.h"
 
 #include "jscompartment.h"
 
+#include "gc/Allocator.h"
+#include "gc/GCTrace.h"
 #include "proxy/DeadObjectProxy.h"
 
 #include "jsobjinlines.h"
 
+#include "gc/ObjectKind-inl.h"
+#include "vm/TypeInference-inl.h"
+
 using namespace js;
 
 static gc::AllocKind
 GetProxyGCObjectKind(const Class* clasp, const BaseProxyHandler* handler, const Value& priv)
 {
     MOZ_ASSERT(clasp->isProxy());
 
     uint32_t nreserved = JSCLASS_RESERVED_SLOTS(clasp);
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -11,16 +11,17 @@
 #include "jsscript.h"
 #include "builtin/ModuleObject.h"
 #include "gc/Allocator.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/Runtime.h"
 #include "vm/StringBuffer.h"
 #include "wasm/WasmInstance.h"
 
+#include "gc/ObjectKind-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
 
 using mozilla::Maybe;
 using mozilla::MakeScopeExit;
 using mozilla::Move;
 using mozilla::Nothing;
--- a/js/src/vm/TypedArrayObject-inl.h
+++ b/js/src/vm/TypedArrayObject-inl.h
@@ -23,16 +23,18 @@
 
 #include "jit/AtomicOperations.h"
 
 #include "js/Conversions.h"
 #include "js/Value.h"
 
 #include "vm/NativeObject.h"
 
+#include "gc/ObjectKind-inl.h"
+
 namespace js {
 
 template<typename To, typename From>
 inline To
 ConvertNumber(From src);
 
 template<>
 inline int8_t
@@ -603,11 +605,23 @@ class ElementSpecific
         if (TypeIDOfType<T>::id == Scalar::Uint8Clamped)
             return T(d);
         if (TypeIsUnsigned<T>())
             return T(JS::ToUint32(d));
         return T(JS::ToInt32(d));
     }
 };
 
+
+/* static */ gc::AllocKind
+js::TypedArrayObject::AllocKindForLazyBuffer(size_t nbytes)
+{
+    MOZ_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
+    if (nbytes == 0)
+        nbytes += sizeof(uint8_t);
+    size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
+    MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
+    return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
+}
+
 } // namespace js
 
 #endif // vm_TypedArrayObject_inl_h
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -110,26 +110,17 @@ class TypedArrayObject : public NativeOb
 
     static const size_t FIXED_DATA_START = DATA_SLOT + 1;
 
     // For typed arrays which can store their data inline, the array buffer
     // object is created lazily.
     static const uint32_t INLINE_BUFFER_LIMIT =
         (NativeObject::MAX_FIXED_SLOTS - FIXED_DATA_START) * sizeof(Value);
 
-    static gc::AllocKind
-    AllocKindForLazyBuffer(size_t nbytes)
-    {
-        MOZ_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
-        if (nbytes == 0)
-            nbytes += sizeof(uint8_t);
-        size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
-        MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
-        return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
-    }
+    static inline gc::AllocKind AllocKindForLazyBuffer(size_t nbytes);
 
     inline Scalar::Type type() const;
     inline size_t bytesPerElement() const;
 
     static Value bufferValue(TypedArrayObject* tarr) {
         return tarr->getFixedSlot(BUFFER_SLOT);
     }
     static Value byteOffsetValue(TypedArrayObject* tarr) {
--- a/js/src/vm/UnboxedObject-inl.h
+++ b/js/src/vm/UnboxedObject-inl.h
@@ -163,11 +163,22 @@ SetUnboxedValue(JSContext* cx, JSObject*
 /////////////////////////////////////////////////////////////////////
 
 inline const UnboxedLayout&
 UnboxedPlainObject::layout() const
 {
     return group()->unboxedLayout();
 }
 
+/////////////////////////////////////////////////////////////////////
+// UnboxedLayout
+/////////////////////////////////////////////////////////////////////
+
+gc::AllocKind
+js::UnboxedLayout::getAllocKind() const
+{
+    MOZ_ASSERT(size());
+    return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
+}
+
 } // namespace js
 
 #endif // vm_UnboxedObject_inl_h
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -312,23 +312,16 @@ class UnboxedPlainObject : public Unboxe
 
 // Try to construct an UnboxedLayout for each of the preliminary objects,
 // provided they all match the template shape. If successful, converts the
 // preliminary objects and their group to the new unboxed representation.
 bool
 TryConvertToUnboxedLayout(JSContext* cx, AutoEnterAnalysis& enter, Shape* templateShape,
                           ObjectGroup* group, PreliminaryObjectArray* objects);
 
-inline gc::AllocKind
-UnboxedLayout::getAllocKind() const
-{
-    MOZ_ASSERT(size());
-    return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
-}
-
 } // namespace js
 
 namespace JS {
 
 template <>
 struct DeletePolicy<js::UnboxedLayout> : public js::GCManagedDeletePolicy<js::UnboxedLayout>
 {};