Bug 1160535 part 1 - Give JSFunction its own AllocKind. r=terrence
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 06 May 2015 16:52:46 +0200
changeset 273980 1c6a191fead0dcecf7b80c4f339169dd0d4df02f
parent 273979 53e602f840091e79970050b830f83285b2e2daf9
child 273981 ed3aed8b899ffe9559226d33836886dbb7669068
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1160535
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1160535 part 1 - Give JSFunction its own AllocKind. r=terrence
js/src/asmjs/AsmJSLink.cpp
js/src/asmjs/AsmJSValidate.cpp
js/src/builtin/Object.cpp
js/src/frontend/Parser.cpp
js/src/gc/Heap.h
js/src/jit-test/tests/heap-analysis/byteSize-of-object.js
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jscompartment.cpp
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jsobj.cpp
js/src/jsobjinlines.h
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
js/src/vm/RegExpObject.cpp
js/src/vm/SavedStacks.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/SharedTypedArrayObject.cpp
js/src/vm/TypedArrayObject.cpp
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -794,17 +794,17 @@ CallAsmJS(JSContext* cx, unsigned argc, 
 static JSFunction*
 NewExportedFunction(JSContext* cx, const AsmJSModule::ExportedFunction& func,
                     HandleObject moduleObj, unsigned exportIndex)
 {
     RootedPropertyName name(cx, func.name());
     unsigned numArgs = func.isChangeHeap() ? 1 : func.numArgs();
     JSFunction* fun =
         NewNativeConstructor(cx, CallAsmJS, numArgs, name,
-                             JSFunction::ExtendedFinalizeKind, GenericObject,
+                             gc::AllocKind::FUNCTION_EXTENDED, GenericObject,
                              JSFunction::ASMJS_CTOR);
     if (!fun)
         return nullptr;
 
     fun->setExtendedSlot(ASM_MODULE_SLOT, ObjectValue(*moduleObj));
     fun->setExtendedSlot(ASM_EXPORT_INDEX_SLOT, Int32Value(exportIndex));
     return fun;
 }
@@ -827,17 +827,17 @@ HandleDynamicLinkFailure(JSContext* cx, 
 
     uint32_t begin = module.srcBodyStart();  // starts right after 'use asm'
     uint32_t end = module.srcEndBeforeCurly();
     Rooted<JSFlatString*> src(cx, module.scriptSource()->substringDontDeflate(cx, begin, end));
     if (!src)
         return false;
 
     RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED,
-                                               name, JSFunction::FinalizeKind,
+                                               name, gc::AllocKind::FUNCTION,
                                                TenuredObject));
     if (!fun)
         return false;
 
     AutoNameVector formals(cx);
     if (!formals.reserve(3))
         return false;
 
@@ -1090,17 +1090,17 @@ JSFunction*
 js::NewAsmJSModuleFunction(ExclusiveContext* cx, JSFunction* origFun, HandleObject moduleObj)
 {
     RootedPropertyName name(cx, origFun->name());
 
     JSFunction::Flags flags = origFun->isLambda() ? JSFunction::ASMJS_LAMBDA_CTOR
                                                   : JSFunction::ASMJS_CTOR;
     JSFunction* moduleFun =
         NewNativeConstructor(cx, LinkAsmJS, origFun->nargs(), name,
-                             JSFunction::ExtendedFinalizeKind, TenuredObject,
+                             gc::AllocKind::FUNCTION_EXTENDED, TenuredObject,
                              flags);
     if (!moduleFun)
         return nullptr;
 
     moduleFun->setExtendedSlot(MODULE_FUN_SLOT, ObjectValue(*moduleObj));
     return moduleFun;
 }
 
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -7580,17 +7580,17 @@ ParseFunction(ModuleCompiler& m, ParseNo
 
     ParseNode* fn = m.parser().handler.newFunctionDefinition();
     if (!fn)
         return false;
 
     // This flows into FunctionBox, so must be tenured.
     RootedFunction fun(m.cx(),
                        NewScriptedFunction(m.cx(), 0, JSFunction::INTERPRETED,
-                                           name, JSFunction::FinalizeKind,
+                                           name, gc::AllocKind::FUNCTION,
                                            TenuredObject));
     if (!fun)
         return false;
 
     AsmJSParseContext* outerpc = m.parser().pc;
 
     Directives directives(outerpc);
     FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator);
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -1091,17 +1091,17 @@ static JSObject*
 CreateObjectConstructor(JSContext* cx, JSProtoKey key)
 {
     Rooted<GlobalObject*> self(cx, cx->global());
     if (!GlobalObject::ensureConstructor(cx, self, JSProto_Function))
         return nullptr;
 
     /* Create the Object function now that we have a [[Prototype]] for it. */
     return NewNativeConstructor(cx, obj_construct, 1, HandlePropertyName(cx->names().Object),
-                                JSFunction::FinalizeKind, SingletonObject);
+                                gc::AllocKind::FUNCTION, SingletonObject);
 }
 
 static JSObject*
 CreateObjectPrototype(JSContext* cx, JSProtoKey key)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     MOZ_ASSERT(cx->global()->isNative());
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1223,20 +1223,20 @@ Parser<ParseHandler>::newFunction(Handle
         break;
       case Method:
         flags = JSFunction::INTERPRETED_METHOD;
         break;
       default:
         flags = JSFunction::INTERPRETED;
         break;
     }
-    
-    gc::AllocKind allocKind = JSFunction::FinalizeKind;
+
+    gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
     if (kind == Arrow || kind == Method)
-        allocKind = JSFunction::ExtendedFinalizeKind;
+        allocKind = gc::AllocKind::FUNCTION_EXTENDED;
     fun = NewFunctionWithProto(context, nullptr, 0, flags, NullPtr(), atom, proto,
                                allocKind, TenuredObject);
     if (!fun)
         return nullptr;
     if (options().selfHostingMode)
         fun->setIsSelfHostedBuiltin();
     return fun;
 }
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -74,17 +74,20 @@ enum InitialHeap {
     TenuredHeap
 };
 
 /* The GC allocation kinds. */
 // FIXME: uint8_t would make more sense for the underlying type, but causes
 // miscompilations in GCC (fixed in 4.8.5 and 4.9.3). See also bug 1143966.
 enum class AllocKind {
     FIRST,
-    OBJECT0 = FIRST,
+    OBJECT_FIRST = FIRST,
+    FUNCTION = FIRST,
+    FUNCTION_EXTENDED,
+    OBJECT0,
     OBJECT0_BACKGROUND,
     OBJECT2,
     OBJECT2_BACKGROUND,
     OBJECT4,
     OBJECT4_BACKGROUND,
     OBJECT8,
     OBJECT8_BACKGROUND,
     OBJECT12,
@@ -105,23 +108,23 @@ enum class AllocKind {
     SYMBOL,
     JITCODE,
     LIMIT,
     LAST = LIMIT - 1
 };
 
 static_assert(int(AllocKind::FIRST) == 0, "Various places depend on AllocKind starting at 0, "
                                           "please audit them carefully!");
-static_assert(int(AllocKind::OBJECT0) == 0, "Various places depend on AllocKind::OBJECT0 being 0, "
-                                            "please audit them carefully!");
+static_assert(int(AllocKind::OBJECT_FIRST) == 0, "Various places depend on AllocKind::OBJECT_FIRST "
+                                                 "being 0, please audit them carefully!");
 
 inline bool
 IsObjectAllocKind(AllocKind kind)
 {
-    return kind >= AllocKind::OBJECT0 && kind <= AllocKind::OBJECT_LAST;
+    return kind >= AllocKind::OBJECT_FIRST && kind <= AllocKind::OBJECT_LAST;
 }
 
 inline bool
 IsValidAllocKind(AllocKind kind)
 {
     return kind >= AllocKind::FIRST && kind <= AllocKind::LAST;
 }
 
@@ -135,20 +138,20 @@ inline bool IsAllocKind(AllocKind kind)
 inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT))
 AllAllocKinds()
 {
     return mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT);
 }
 
 // Returns a sequence for use in a range-based for loop,
 // to iterate over all object alloc kinds.
-inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT0, AllocKind::OBJECT_LIMIT))
+inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT))
 ObjectAllocKinds()
 {
-    return mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT0, AllocKind::OBJECT_LIMIT);
+    return mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT);
 }
 
 // Returns a sequence for use in a range-based for loop,
 // to iterate over alloc kinds from |first| to |limit|, exclusive.
 inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT))
 SomeAllocKinds(AllocKind first = AllocKind::FIRST, AllocKind limit = AllocKind::LIMIT)
 {
     MOZ_ASSERT(IsAllocKind(first), "|first| is not a valid AllocKind!");
@@ -165,16 +168,18 @@ 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 JSGCTraceKind
 MapAllocToTraceKind(AllocKind kind)
 {
     static const JSGCTraceKind map[] = {
+        JSTRACE_OBJECT,       /* AllocKind::FUNCTION */
+        JSTRACE_OBJECT,       /* AllocKind::FUNCTION_EXTENDED */
         JSTRACE_OBJECT,       /* AllocKind::OBJECT0 */
         JSTRACE_OBJECT,       /* AllocKind::OBJECT0_BACKGROUND */
         JSTRACE_OBJECT,       /* AllocKind::OBJECT2 */
         JSTRACE_OBJECT,       /* AllocKind::OBJECT2_BACKGROUND */
         JSTRACE_OBJECT,       /* AllocKind::OBJECT4 */
         JSTRACE_OBJECT,       /* AllocKind::OBJECT4_BACKGROUND */
         JSTRACE_OBJECT,       /* AllocKind::OBJECT8 */
         JSTRACE_OBJECT,       /* AllocKind::OBJECT8_BACKGROUND */
--- a/js/src/jit-test/tests/heap-analysis/byteSize-of-object.js
+++ b/js/src/jit-test/tests/heap-analysis/byteSize-of-object.js
@@ -74,10 +74,10 @@ assertEq(tByteSize([1, 2, 3, 4]),       
 assertEq(tByteSize([1, 2, 3, 4, 5]),                    s(80,  96));
 assertEq(tByteSize([1, 2, 3, 4, 5, 6]),                 s(80,  96));
 assertEq(tByteSize([1, 2, 3, 4, 5, 6, 7]),              s(112, 128));
 assertEq(tByteSize([1, 2, 3, 4, 5, 6, 7, 8]),           s(112, 128));
 
 // Various forms of functions.
 assertEq(tByteSize(function () {}),                     s(32,  64));
 assertEq(tByteSize(function () {}.bind()),              s(96,  128));
-assertEq(tByteSize(() => 1),                            s(48,  96));
+assertEq(tByteSize(() => 1),                            s(48,  80));
 assertEq(tByteSize(Math.sin),                           s(32,  64));
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3477,17 +3477,17 @@ JS_DefineFunctions(JSContext* cx, Handle
             JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
             MOZ_ASSERT(obj == &obj->global().getPrototype(key).toObject());
             RootedObject ctor(cx, &obj->global().getConstructor(key).toObject());
 
             flags &= ~JSFUN_GENERIC_NATIVE;
             JSFunction* fun = DefineFunction(cx, ctor, id,
                                              GenericNativeMethodDispatcher,
                                              fs->nargs + 1, flags,
-                                             JSFunction::ExtendedFinalizeKind);
+                                             gc::AllocKind::FUNCTION_EXTENDED);
             if (!fun)
                 return false;
 
             /*
              * As jsapi.h notes, fs must point to storage that lives as long
              * as fun->object lives.
              */
             fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
@@ -4036,17 +4036,17 @@ CompileFunction(JSContext* cx, const Rea
     AutoNameVector formals(cx);
     for (unsigned i = 0; i < nargs; i++) {
         RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
         if (!argAtom || !formals.append(argAtom->asPropertyName()))
             return false;
     }
 
     fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED, funAtom,
-                                JSFunction::FinalizeKind, TenuredObject,
+                                gc::AllocKind::FUNCTION, TenuredObject,
                                 enclosingDynamicScope));
     if (!fun)
         return false;
 
     // Make sure to handle cases when we have a polluted scopechain.
     CompileOptions options(cx, optionsArg);
     if (!enclosingDynamicScope->is<GlobalObject>())
         options.setHasPollutedScope(true);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3257,17 +3257,17 @@ const Class ArrayObject::class_ = {
     nullptr, /* mayResolve */
     nullptr, /* convert */
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     nullptr, /* trace */
     {
-        GenericCreateConstructor<ArrayConstructor, 1, JSFunction::FinalizeKind>,
+        GenericCreateConstructor<ArrayConstructor, 1, gc::AllocKind::FUNCTION>,
         CreateArrayPrototype,
         array_static_methods,
         nullptr,
         array_methods
     }
 };
 
 /*
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -760,30 +760,28 @@ CreateLazyScriptsForCompartment(JSContex
     // script. The last condition is so that we don't compile lazy scripts
     // whose enclosing scripts failed to compile, indicating that the lazy
     // script did not escape the script.
     //
     // Note that while we ideally iterate over LazyScripts, LazyScripts do not
     // currently stand in 1-1 relation with JSScripts; JSFunctions with the
     // same LazyScript may create different JSScripts due to relazification of
     // clones. See bug 1105306.
-    for (gc::ZoneCellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) {
-        JSObject* obj = i.get<JSObject>();
+    for (gc::ZoneCellIter i(cx->zone(), AllocKind::FUNCTION); !i.done(); i.next()) {
+        JSFunction* fun = &i.get<JSObject>()->as<JSFunction>();
 
         // Sweeping is incremental; take care to not delazify functions that
         // are about to be finalized. GC things referenced by objects that are
         // about to be finalized (e.g., in slots) may already be freed.
-        if (gc::IsAboutToBeFinalizedUnbarriered(&obj) ||
-            obj->compartment() != cx->compartment() ||
-            !obj->is<JSFunction>())
+        if (gc::IsAboutToBeFinalizedUnbarriered(&fun) ||
+            fun->compartment() != cx->compartment())
         {
             continue;
         }
 
-        JSFunction* fun = &obj->as<JSFunction>();
         if (fun->isInterpretedLazy()) {
             LazyScript* lazy = fun->lazyScriptOrNull();
             if (lazy && lazy->sourceObject() && !lazy->maybeScript() &&
                 !lazy->hasUncompiledEnclosingScript())
             {
                 if (!lazyFunctions.append(fun))
                     return false;
             }
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3158,17 +3158,17 @@ const Class DateObject::class_ = {
     nullptr, /* mayResolve */
     date_convert,
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     nullptr, /* trace */
     {
-        GenericCreateConstructor<DateConstructor, 7, JSFunction::FinalizeKind>,
+        GenericCreateConstructor<DateConstructor, 7, gc::AllocKind::FUNCTION>,
         GenericCreatePrototype,
         date_static_methods,
         nullptr,
         date_methods,
         nullptr,
         FinishDateClassInit
     }
 };
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -485,17 +485,17 @@ ErrorObject::createProto(JSContext* cx, 
 
     return errorProto;
 }
 
 /* static */ JSObject*
 ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
 {
     RootedObject ctor(cx);
-    ctor = GenericCreateConstructor<Error, 1, JSFunction::ExtendedFinalizeKind>(cx, key);
+    ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key);
     if (!ctor)
         return nullptr;
 
     ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(ExnTypeFromProtoKey(key)));
     return ctor;
 }
 
 JS_FRIEND_API(JSFlatString*)
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -419,17 +419,17 @@ js::DefineFunctionWithReserved(JSContext
     RootedObject obj(cx, objArg);
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAtom* atom = Atomize(cx, name, strlen(name));
     if (!atom)
         return nullptr;
     Rooted<jsid> id(cx, AtomToId(atom));
-    return DefineFunction(cx, obj, id, call, nargs, attrs, JSFunction::ExtendedFinalizeKind);
+    return DefineFunction(cx, obj, id, call, nargs, attrs, gc::AllocKind::FUNCTION_EXTENDED);
 }
 
 JS_FRIEND_API(JSFunction*)
 js::NewFunctionWithReserved(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
                             const char* name)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
 
@@ -438,32 +438,32 @@ js::NewFunctionWithReserved(JSContext* c
     RootedAtom atom(cx);
     if (name) {
         atom = Atomize(cx, name, strlen(name));
         if (!atom)
             return nullptr;
     }
 
     return (flags & JSFUN_CONSTRUCTOR) ?
-        NewNativeConstructor(cx, native, nargs, atom, JSFunction::ExtendedFinalizeKind) :
-        NewNativeFunction(cx, native, nargs, atom, JSFunction::ExtendedFinalizeKind);
+        NewNativeConstructor(cx, native, nargs, atom, gc::AllocKind::FUNCTION_EXTENDED) :
+        NewNativeFunction(cx, native, nargs, atom, gc::AllocKind::FUNCTION_EXTENDED);
 }
 
 JS_FRIEND_API(JSFunction*)
 js::NewFunctionByIdWithReserved(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
                                 jsid id)
 {
     MOZ_ASSERT(JSID_IS_STRING(id));
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     CHECK_REQUEST(cx);
 
     RootedAtom atom(cx, JSID_TO_ATOM(id));
     return (flags & JSFUN_CONSTRUCTOR) ?
-        NewNativeConstructor(cx, native, nargs, atom, JSFunction::ExtendedFinalizeKind) :
-        NewNativeFunction(cx, native, nargs, atom, JSFunction::ExtendedFinalizeKind);
+        NewNativeConstructor(cx, native, nargs, atom, gc::AllocKind::FUNCTION_EXTENDED) :
+        NewNativeFunction(cx, native, nargs, atom, gc::AllocKind::FUNCTION_EXTENDED);
 }
 
 JS_FRIEND_API(const Value&)
 js::GetFunctionNativeReserved(JSObject* fun, size_t which)
 {
     MOZ_ASSERT(fun->as<JSFunction>().isNative());
     return fun->as<JSFunction>().getExtendedSlot(which);
 }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -591,19 +591,19 @@ js::XDRInterpretedFunction(XDRState<mode
     if (mode == XDR_DECODE) {
         RootedObject proto(cx);
         if (firstword & IsStarGenerator) {
             proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
             if (!proto)
                 return false;
         }
 
-        gc::AllocKind allocKind = JSFunction::FinalizeKind;
+        gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
         if (uint16_t(flagsword) & JSFunction::EXTENDED)
-            allocKind = JSFunction::ExtendedFinalizeKind;
+            allocKind = gc::AllocKind::FUNCTION_EXTENDED;
         fun = NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
                                    /* enclosingDynamicScope = */ NullPtr(), NullPtr(), proto,
                                    allocKind, TenuredObject);
         if (!fun)
             return false;
         script = nullptr;
     }
 
@@ -649,19 +649,17 @@ js::CloneFunctionAndScript(JSContext* cx
     /* NB: Keep this in sync with XDRInterpretedFunction. */
     RootedObject cloneProto(cx);
     if (srcFun->isStarGenerator()) {
         cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
         if (!cloneProto)
             return nullptr;
     }
 
-    gc::AllocKind allocKind = JSFunction::FinalizeKind;
-    if (srcFun->isExtended())
-        allocKind = JSFunction::ExtendedFinalizeKind;
+    gc::AllocKind allocKind = srcFun->getAllocKind();
     RootedFunction clone(cx, NewFunctionWithProto(cx, nullptr, 0,
                                                   JSFunction::INTERPRETED, NullPtr(), NullPtr(),
                                                   cloneProto, allocKind, TenuredObject));
     if (!clone)
         return nullptr;
 
     JSScript::AutoDelazify srcScript(cx, srcFun);
     if (!srcScript)
@@ -779,17 +777,17 @@ static JSObject*
 CreateFunctionConstructor(JSContext* cx, JSProtoKey key)
 {
     Rooted<GlobalObject*> global(cx, cx->global());
     RootedObject functionProto(cx, &global->getPrototype(JSProto_Function).toObject());
 
     RootedObject functionCtor(cx,
       NewFunctionWithProto(cx, Function, 1, JSFunction::NATIVE_CTOR,
                            NullPtr(), HandlePropertyName(cx->names().Function),
-                           functionProto, JSFunction::FinalizeKind, SingletonObject));
+                           functionProto, AllocKind::FUNCTION, SingletonObject));
     if (!functionCtor)
         return nullptr;
 
     return functionCtor;
 
 }
 
 static JSObject*
@@ -799,17 +797,17 @@ CreateFunctionPrototype(JSContext* cx, J
 
     RootedObject objectProto(cx, &self->getPrototype(JSProto_Object).toObject());
     /*
      * Bizarrely, |Function.prototype| must be an interpreted function, so
      * give it the guts to be one.
      */
     JSObject* functionProto_ =
         NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
-                             self, NullPtr(), objectProto, JSFunction::FinalizeKind,
+                             self, NullPtr(), objectProto, AllocKind::FUNCTION,
                              SingletonObject);
     if (!functionProto_)
         return nullptr;
 
     RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
     functionProto->setIsFunctionPrototype();
 
     const char* rawSource = "() {\n}";
@@ -867,17 +865,17 @@ CreateFunctionPrototype(JSContext* cx, J
     // |Function.prototype| right now.)
     //
     // Note that we can't use NewFunction here, even though we want the normal
     // Function.prototype for our proto, because we're still in the middle of
     // creating that as far as the world is concerned, so things will get all
     // confused.
     RootedFunction throwTypeError(cx,
       NewFunctionWithProto(cx, ThrowTypeError, 0, JSFunction::NATIVE_FUN,
-                           NullPtr(), NullPtr(), functionProto, JSFunction::FinalizeKind,
+                           NullPtr(), NullPtr(), functionProto, AllocKind::FUNCTION,
                            SingletonObject));
     if (!throwTypeError || !PreventExtensions(cx, throwTypeError))
         return nullptr;
 
     self->setThrowTypeError(throwTypeError);
 
     return functionProto;
 }
@@ -1949,17 +1947,17 @@ FunctionConstructor(JSContext* cx, unsig
     if (isStarGenerator) {
         proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
         if (!proto)
             return false;
     }
     RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
                                                 JSFunction::INTERPRETED_LAMBDA, global,
                                                 anonymousAtom, proto,
-                                                JSFunction::FinalizeKind, TenuredObject));
+                                                AllocKind::FUNCTION, TenuredObject));
     if (!fun)
         return false;
 
     if (!JSFunction::setTypeForScriptedFunction(cx, fun))
         return false;
 
     if (hasRest)
         fun->setHasRest();
@@ -1998,56 +1996,54 @@ js::Generator(JSContext* cx, unsigned ar
 bool
 JSFunction::isBuiltinFunctionConstructor()
 {
     return maybeNative() == Function || maybeNative() == Generator;
 }
 
 JSFunction*
 js::NewNativeFunction(ExclusiveContext* cx, Native native, unsigned nargs, HandleAtom atom,
-                      gc::AllocKind allocKind /* = JSFunction::FinalizeKind */,
+                      gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
                       NewObjectKind newKind /* = GenericObject */)
 {
     return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_FUN,
                                 NullPtr(), atom, NullPtr(), allocKind, newKind);
 }
 
 JSFunction*
 js::NewNativeConstructor(ExclusiveContext* cx, Native native, unsigned nargs, HandleAtom atom,
-                         gc::AllocKind allocKind /* = JSFunction::FinalizeKind */,
+                         gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
                          NewObjectKind newKind /* = GenericObject */,
                          JSFunction::Flags flags /* = JSFunction::NATIVE_CTOR */)
 {
     MOZ_ASSERT(flags & JSFunction::NATIVE_CTOR);
     return NewFunctionWithProto(cx, native, nargs, flags, NullPtr(), atom,
                                 NullPtr(), allocKind, newKind);
 }
 
 JSFunction*
 js::NewScriptedFunction(ExclusiveContext* cx, unsigned nargs,
                         JSFunction::Flags flags, HandleAtom atom,
-                        gc::AllocKind allocKind /* = JSFunction::FinalizeKind */,
+                        gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
                         NewObjectKind newKind /* = GenericObject */,
                         HandleObject enclosingDynamicScope /* = NullPtr() */)
 {
     return NewFunctionWithProto(cx, nullptr, nargs, flags,
                                 enclosingDynamicScope ? enclosingDynamicScope : cx->global(),
                                 atom, NullPtr(), allocKind, newKind);
 }
 
 JSFunction*
 js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
                          unsigned nargs, JSFunction::Flags flags, HandleObject enclosingDynamicScope,
                          HandleAtom atom, HandleObject proto,
-                         gc::AllocKind allocKind /* = JSFunction::FinalizeKind */,
+                         gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
                          NewObjectKind newKind /* = GenericObject */)
 {
-    MOZ_ASSERT(allocKind == JSFunction::FinalizeKind || allocKind == JSFunction::ExtendedFinalizeKind);
-    MOZ_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind));
-    MOZ_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind));
+    MOZ_ASSERT(allocKind == AllocKind::FUNCTION || allocKind == AllocKind::FUNCTION_EXTENDED);
     MOZ_ASSERT_IF(native, !enclosingDynamicScope);
 
     RootedObject funobj(cx);
     // Don't mark asm.js module functions as singleton since they are
     // cloned (via CloneFunctionObjectIfNotSingleton) which assumes that
     // isSingleton implies isInterpreted.
     if (native && !IsAsmJSModuleNative(native))
         newKind = SingletonObject;
@@ -2064,17 +2060,17 @@ js::NewFunctionWithProto(ExclusiveContex
 #endif
     funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind,
                                      newKind);
     if (!funobj)
         return nullptr;
 
     RootedFunction fun(cx, &funobj->as<JSFunction>());
 
-    if (allocKind == JSFunction::ExtendedFinalizeKind)
+    if (allocKind == AllocKind::FUNCTION_EXTENDED)
         flags = JSFunction::Flags(flags | JSFunction::EXTENDED);
 
     /* Initialize all function members. */
     fun->setArgCount(uint16_t(nargs));
     fun->setFlags(flags);
     if (fun->isInterpreted()) {
         MOZ_ASSERT(!native);
         if (fun->isInterpretedLazy())
@@ -2082,17 +2078,17 @@ js::NewFunctionWithProto(ExclusiveContex
         else
             fun->initScript(nullptr);
         fun->initEnvironment(enclosingDynamicScope);
     } else {
         MOZ_ASSERT(fun->isNative());
         MOZ_ASSERT(native);
         fun->initNative(native, nullptr);
     }
-    if (allocKind == JSFunction::ExtendedFinalizeKind)
+    if (allocKind == AllocKind::FUNCTION_EXTENDED)
         fun->initializeExtended();
     fun->initAtom(atom);
 
     return fun;
 }
 
 bool
 js::CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction fun,
@@ -2164,17 +2160,17 @@ js::CloneFunctionObject(JSContext* cx, H
                                                  allocKind, newKind);
     if (!cloneobj)
         return nullptr;
     RootedFunction clone(cx, &cloneobj->as<JSFunction>());
 
     MOZ_ASSERT(useSameScript || !fun->isInterpretedLazy());
 
     uint16_t flags = fun->flags() & ~JSFunction::EXTENDED;
-    if (allocKind == JSFunction::ExtendedFinalizeKind)
+    if (allocKind == AllocKind::FUNCTION_EXTENDED)
         flags |= JSFunction::EXTENDED;
 
     clone->setArgCount(fun->nargs());
     clone->setFlags(flags);
     if (fun->hasScript()) {
         clone->initScript(fun->nonLazyScript());
         clone->initEnvironment(parent);
     } else if (fun->isInterpretedLazy()) {
@@ -2183,17 +2179,17 @@ js::CloneFunctionObject(JSContext* cx, H
         LazyScript* lazy = fun->lazyScriptOrNull();
         clone->initLazyScript(lazy);
         clone->initEnvironment(parent);
     } else {
         clone->initNative(fun->native(), fun->jitInfo());
     }
     clone->initAtom(fun->displayAtom());
 
-    if (allocKind == JSFunction::ExtendedFinalizeKind) {
+    if (allocKind == AllocKind::FUNCTION_EXTENDED) {
         if (fun->isExtended() && fun->compartment() == cx->compartment()) {
             for (unsigned i = 0; i < FunctionExtended::NUM_EXTENDED_SLOTS; i++)
                 clone->initExtendedSlot(i, fun->getExtendedSlot(i));
         } else {
             clone->initializeExtended();
         }
     }
 
@@ -2251,17 +2247,17 @@ js::IdToFunctionName(JSContext* cx, Hand
     }
 
     RootedValue idv(cx, IdToValue(id));
     return ToAtom<CanGC>(cx, idv);
 }
 
 JSFunction*
 js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native,
-                   unsigned nargs, unsigned flags, AllocKind allocKind /* = FinalizeKind */,
+                   unsigned nargs, unsigned flags, AllocKind allocKind /* = AllocKind::FUNCTION */,
                    NewObjectKind newKind /* = GenericObject */)
 {
     GetterOp gop;
     SetterOp sop;
     if (flags & JSFUN_STUB_GSOPS) {
         /*
          * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
          * the defined property's attributes. This allows us to encode another,
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -449,24 +449,16 @@ class JSFunction : public js::NativeObje
                       "for offsetOfNativeOrScript() have any sense");
         static_assert(offsetof(U, n.native) == offsetof(U, nativeOrScript),
                       "U::nativeOrScript must be at the same offset as "
                       "native");
 
         return offsetof(JSFunction, u.nativeOrScript);
     }
 
-#if JS_BITS_PER_WORD == 32
-    static const js::gc::AllocKind FinalizeKind = js::gc::AllocKind::OBJECT2_BACKGROUND;
-    static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::AllocKind::OBJECT4_BACKGROUND;
-#else
-    static const js::gc::AllocKind FinalizeKind = js::gc::AllocKind::OBJECT4_BACKGROUND;
-    static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::AllocKind::OBJECT8_BACKGROUND;
-#endif
-
     inline void trace(JSTracer* trc);
 
     /* Bound function accessors. */
 
     inline bool initBoundFunction(JSContext* cx, js::HandleObject target, js::HandleValue thisArg,
                                   const js::Value* args, unsigned argslen);
 
     JSObject* getBoundFunctionTarget() const;
@@ -480,18 +472,20 @@ class JSFunction : public js::NativeObje
         return *(js::HeapPtrScript*)&u.i.s.script_;
     }
 
     inline js::FunctionExtended* toExtended();
     inline const js::FunctionExtended* toExtended() const;
 
   public:
     inline bool isExtended() const {
-        MOZ_ASSERT_IF(isTenured(), !!(flags() & EXTENDED) == (asTenured().getAllocKind() == ExtendedFinalizeKind));
-        return !!(flags() & EXTENDED);
+        bool extended = !!(flags() & EXTENDED);
+        MOZ_ASSERT_IF(isTenured(),
+                      extended == (asTenured().getAllocKind() == js::gc::AllocKind::FUNCTION_EXTENDED));
+        return extended;
     }
 
     /*
      * Accessors for data stored in extended functions. Use setExtendedSlot if
      * the function has already been initialized. Otherwise use
      * initExtendedSlot.
      */
     inline void initializeExtended();
@@ -500,23 +494,23 @@ class JSFunction : public js::NativeObje
     inline const js::Value& getExtendedSlot(size_t which) const;
 
     /* Constructs a new type for the function if necessary. */
     static bool setTypeForScriptedFunction(js::ExclusiveContext* cx, js::HandleFunction fun,
                                            bool singleton = false);
 
     /* GC support. */
     js::gc::AllocKind getAllocKind() const {
-        static_assert(FinalizeKind != ExtendedFinalizeKind,
+        static_assert(js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED,
                       "extended/non-extended AllocKinds have to be different "
                       "for getAllocKind() to have a reason to exist");
 
-        js::gc::AllocKind kind = FinalizeKind;
+        js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION;
         if (isExtended())
-            kind = ExtendedFinalizeKind;
+            kind = js::gc::AllocKind::FUNCTION_EXTENDED;
         MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
         return kind;
     }
 };
 
 static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function),
               "shadow interface must match actual interface");
 
@@ -529,52 +523,52 @@ extern bool
 Function(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 Generator(JSContext* cx, unsigned argc, Value* vp);
 
 // Allocate a new function backed by a JSNative.
 extern JSFunction*
 NewNativeFunction(ExclusiveContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
-                  gc::AllocKind allocKind = JSFunction::FinalizeKind,
+                  gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
                   NewObjectKind newKind = GenericObject);
 
 // Allocate a new constructor backed by a JSNative.
 extern JSFunction*
 NewNativeConstructor(ExclusiveContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
-                     gc::AllocKind allocKind = JSFunction::FinalizeKind,
+                     gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
                      NewObjectKind newKind = GenericObject,
                      JSFunction::Flags flags = JSFunction::NATIVE_CTOR);
 
 // Allocate a new scripted function.  If enclosingDynamicScope is null, the
 // global will be used.  In all cases the parent of the resulting object will be
 // the global.
 extern JSFunction*
 NewScriptedFunction(ExclusiveContext* cx, unsigned nargs, JSFunction::Flags flags,
-                    HandleAtom atom, gc::AllocKind allocKind = JSFunction::FinalizeKind,
+                    HandleAtom atom, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
                     NewObjectKind newKind = GenericObject,
                     HandleObject enclosingDynamicScope = NullPtr());
 
 // If proto is nullptr, Function.prototype is used instead.  If
 // enclosingDynamicScope is null, the function will have a null environment()
 // (yes, null, not the global).  In all cases, the global will be used as the
 // parent.
 extern JSFunction*
 NewFunctionWithProto(ExclusiveContext* cx, JSNative native, unsigned nargs,
                      JSFunction::Flags flags, HandleObject enclosingDynamicScope, HandleAtom atom,
-                     HandleObject proto, gc::AllocKind allocKind = JSFunction::FinalizeKind,
+                     HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
                      NewObjectKind newKind = GenericObject);
 
 extern JSAtom*
 IdToFunctionName(JSContext* cx, HandleId id);
 
 extern JSFunction*
 DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
                unsigned nargs, unsigned flags,
-               gc::AllocKind allocKind = JSFunction::FinalizeKind,
+               gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
                NewObjectKind newKind = GenericObject);
 
 bool
 FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
 
 extern bool
 fun_toString(JSContext* cx, unsigned argc, Value* vp);
 
@@ -612,17 +606,17 @@ class FunctionExtended : public JSFuncti
 };
 
 extern bool
 CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction fun,
                                  HandleObject newParent);
 
 extern JSFunction*
 CloneFunctionObject(JSContext* cx, HandleFunction fun, HandleObject parent,
-                    gc::AllocKind kind = JSFunction::FinalizeKind,
+                    gc::AllocKind kind = gc::AllocKind::FUNCTION,
                     NewObjectKind newKindArg = GenericObject,
                     HandleObject proto = NullPtr());
 
 extern bool
 FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart,
          size_t* bodyEnd);
 
 } // namespace js
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -75,18 +75,18 @@ CloneFunctionObjectIfNotSingleton(JSCont
             return nullptr;
         MOZ_ASSERT(!proto || succeeded);
         fun->setEnvironment(parent);
         return fun;
     }
 
     // These intermediate variables are needed to avoid link errors on some
     // platforms.  Sigh.
-    gc::AllocKind finalizeKind = JSFunction::FinalizeKind;
-    gc::AllocKind extendedFinalizeKind = JSFunction::ExtendedFinalizeKind;
+    gc::AllocKind finalizeKind = gc::AllocKind::FUNCTION;
+    gc::AllocKind extendedFinalizeKind = gc::AllocKind::FUNCTION_EXTENDED;
     gc::AllocKind kind = fun->isExtended()
                          ? extendedFinalizeKind
                          : finalizeKind;
     return CloneFunctionObject(cx, fun, parent, kind, newKind, proto);
 }
 
 } /* namespace js */
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -265,16 +265,18 @@ static_assert(JS_ARRAY_LENGTH(slotsToThi
 // Assert that SortedArenaList::MinThingSize is <= the real minimum thing size.
 #define CHECK_MIN_THING_SIZE_INNER(x_)                                         \
     static_assert(x_ >= SortedArenaList::MinThingSize,                         \
     #x_ " is less than SortedArenaList::MinThingSize!");
 #define CHECK_MIN_THING_SIZE(...) { __VA_ARGS__ }; /* Define the array. */     \
     MOZ_FOR_EACH(CHECK_MIN_THING_SIZE_INNER, (), (__VA_ARGS__ UINT32_MAX))
 
 const uint32_t Arena::ThingSizes[] = CHECK_MIN_THING_SIZE(
+    sizeof(JSFunction),         /* AllocKind::FUNCTION            */
+    sizeof(FunctionExtended),   /* AllocKind::FUNCTION_EXTENDED   */
     sizeof(JSObject_Slots0),    /* AllocKind::OBJECT0             */
     sizeof(JSObject_Slots0),    /* AllocKind::OBJECT0_BACKGROUND  */
     sizeof(JSObject_Slots2),    /* AllocKind::OBJECT2             */
     sizeof(JSObject_Slots2),    /* AllocKind::OBJECT2_BACKGROUND  */
     sizeof(JSObject_Slots4),    /* AllocKind::OBJECT4             */
     sizeof(JSObject_Slots4),    /* AllocKind::OBJECT4_BACKGROUND  */
     sizeof(JSObject_Slots8),    /* AllocKind::OBJECT8             */
     sizeof(JSObject_Slots8),    /* AllocKind::OBJECT8_BACKGROUND  */
@@ -296,16 +298,18 @@ const uint32_t Arena::ThingSizes[] = CHE
 );
 
 #undef CHECK_MIN_THING_SIZE_INNER
 #undef CHECK_MIN_THING_SIZE
 
 #define OFFSET(type) uint32_t(sizeof(ArenaHeader) + (ArenaSize - sizeof(ArenaHeader)) % sizeof(type))
 
 const uint32_t Arena::FirstThingOffsets[] = {
+    OFFSET(JSFunction),         /* AllocKind::FUNCTION            */
+    OFFSET(FunctionExtended),   /* AllocKind::FUNCTION_EXTENDED   */
     OFFSET(JSObject_Slots0),    /* AllocKind::OBJECT0             */
     OFFSET(JSObject_Slots0),    /* AllocKind::OBJECT0_BACKGROUND  */
     OFFSET(JSObject_Slots2),    /* AllocKind::OBJECT2             */
     OFFSET(JSObject_Slots2),    /* AllocKind::OBJECT2_BACKGROUND  */
     OFFSET(JSObject_Slots4),    /* AllocKind::OBJECT4             */
     OFFSET(JSObject_Slots4),    /* AllocKind::OBJECT4_BACKGROUND  */
     OFFSET(JSObject_Slots8),    /* AllocKind::OBJECT8             */
     OFFSET(JSObject_Slots8),    /* AllocKind::OBJECT8_BACKGROUND  */
@@ -360,16 +364,18 @@ static const FinalizePhase IncrementalFi
     PHASE(IncrementalPhaseJitCode, gcstats::PHASE_SWEEP_JITCODE)
 };
 
 /*
  * Finalization order for things swept in the background.
  */
 
 static const AllocKind BackgroundPhaseObjects[] = {
+    AllocKind::FUNCTION,
+    AllocKind::FUNCTION_EXTENDED,
     AllocKind::OBJECT0_BACKGROUND,
     AllocKind::OBJECT2_BACKGROUND,
     AllocKind::OBJECT4_BACKGROUND,
     AllocKind::OBJECT8_BACKGROUND,
     AllocKind::OBJECT12_BACKGROUND,
     AllocKind::OBJECT16_BACKGROUND
 };
 
@@ -583,16 +589,18 @@ static bool
 FinalizeArenas(FreeOp* fop,
                ArenaHeader** src,
                SortedArenaList& dest,
                AllocKind thingKind,
                SliceBudget& budget,
                ArenaLists::KeepArenasEnum keepArenas)
 {
     switch (thingKind) {
+      case AllocKind::FUNCTION:
+      case AllocKind::FUNCTION_EXTENDED:
       case AllocKind::OBJECT0:
       case AllocKind::OBJECT0_BACKGROUND:
       case AllocKind::OBJECT2:
       case AllocKind::OBJECT2_BACKGROUND:
       case AllocKind::OBJECT4:
       case AllocKind::OBJECT4_BACKGROUND:
       case AllocKind::OBJECT8:
       case AllocKind::OBJECT8_BACKGROUND:
@@ -2281,16 +2289,18 @@ UpdateCellPointersTyped(MovingTracer* tr
  */
 static void
 UpdateCellPointers(MovingTracer* trc, ArenaHeader* arena)
 {
     AllocKind kind = arena->getAllocKind();
     JSGCTraceKind traceKind = MapAllocToTraceKind(kind);
 
     switch (kind) {
+      case AllocKind::FUNCTION:
+      case AllocKind::FUNCTION_EXTENDED:
       case AllocKind::OBJECT0:
       case AllocKind::OBJECT0_BACKGROUND:
       case AllocKind::OBJECT2:
       case AllocKind::OBJECT2_BACKGROUND:
       case AllocKind::OBJECT4:
       case AllocKind::OBJECT4_BACKGROUND:
       case AllocKind::OBJECT8:
       case AllocKind::OBJECT8_BACKGROUND:
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -91,16 +91,18 @@ template <typename T> struct Participate
 FOR_EACH_GC_LAYOUT(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 */
@@ -124,16 +126,18 @@ IsNurseryAllocable(AllocKind kind)
     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 */
@@ -282,19 +286,21 @@ GetBackgroundAllocKind(AllocKind kind)
 }
 
 /* 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:
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -14,17 +14,17 @@
 
 namespace js {
 namespace gc {
 
 static inline AllocKind
 GetGCObjectKind(const Class* clasp)
 {
     if (clasp == FunctionClassPtr)
-        return JSFunction::FinalizeKind;
+        return AllocKind::FUNCTION;
     uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
     if (clasp->flags & JSCLASS_HAS_PRIVATE)
         nslots++;
     return GetGCObjectKind(nslots);
 }
 
 inline JSGCTraceKind
 GetGCThingTraceKind(const void* thing)
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1080,17 +1080,17 @@ NewObjectGCKind(const js::Class* clasp)
 static inline JSObject*
 NewObject(ExclusiveContext* cx, HandleObjectGroup group, gc::AllocKind kind,
           NewObjectKind newKind)
 {
     const Class* clasp = group->clasp();
 
     MOZ_ASSERT(clasp != &ArrayObject::class_);
     MOZ_ASSERT_IF(clasp == &JSFunction::class_,
-                  kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
+                  kind == AllocKind::FUNCTION || kind == AllocKind::FUNCTION_EXTENDED);
 
     // For objects which can have fixed data following the object, only use
     // enough fixed slots to cover the number of reserved slots in the object,
     // regardless of the allocation kind specified.
     size_t nfixed = ClassCanHaveFixedData(clasp)
                     ? GetGCKindSlots(gc::GetGCObjectKind(clasp), clasp)
                     : GetGCKindSlots(kind, clasp);
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -818,13 +818,13 @@ Unbox(JSContext* cx, HandleObject obj, M
 }
 
 extern NativeObject*
 InitClass(JSContext* cx, HandleObject obj, HandleObject parent_proto,
           const Class* clasp, JSNative constructor, unsigned nargs,
           const JSPropertySpec* ps, const JSFunctionSpec* fs,
           const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
           NativeObject** ctorp = nullptr,
-          gc::AllocKind ctorKind = JSFunction::FinalizeKind);
+          gc::AllocKind ctorKind = gc::AllocKind::FUNCTION);
 
 } /* namespace js */
 
 #endif /* jsobjinlines_h */
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -5996,17 +5996,17 @@ DebuggerFrame_getArguments(JSContext* cx
         {
             return false;
         }
 
         Rooted<jsid> id(cx);
         for (unsigned i = 0; i < fargc; i++) {
             RootedFunction getobj(cx);
             getobj = NewNativeFunction(cx, DebuggerArguments_getArg, 0, js::NullPtr(),
-                                       JSFunction::ExtendedFinalizeKind);
+                                       gc::AllocKind::FUNCTION_EXTENDED);
             if (!getobj)
                 return false;
             id = INT_TO_JSID(i);
             if (!getobj ||
                 !NativeDefineProperty(cx, argsobj, id, UndefinedHandleValue,
                                       JS_DATA_TO_FUNC_PTR(GetterOp, getobj.get()), nullptr,
                                       JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_GETTER))
             {
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -602,17 +602,17 @@ GlobalObject::getSelfHostedFunction(JSCo
     RootedId shId(cx, AtomToId(selfHostedName));
     RootedObject holder(cx, cx->global()->intrinsicsHolder());
 
     if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address()))
         return true;
 
     JSFunction* fun =
         NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY,
-                            name, JSFunction::ExtendedFinalizeKind, SingletonObject);
+                            name, gc::AllocKind::FUNCTION_EXTENDED, SingletonObject);
     if (!fun)
         return false;
     fun->setIsSelfHostedBuiltin();
     fun->setExtendedSlot(0, StringValue(selfHostedName));
     funVal.setObject(*fun);
 
     return cx->global()->addIntrinsicValue(cx, shId, funVal);
 }
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -294,17 +294,17 @@ class GlobalObject : public NativeObject
          JS::OnNewGlobalHookOption hookOption, const JS::CompartmentOptions& options);
 
     /*
      * Create a constructor function with the specified name and length using
      * ctor, a method which creates objects with the given class.
      */
     JSFunction*
     createConstructor(JSContext* cx, JSNative ctor, JSAtom* name, unsigned length,
-                      gc::AllocKind kind = JSFunction::FinalizeKind);
+                      gc::AllocKind kind = gc::AllocKind::FUNCTION);
 
     /*
      * Create an object to serve as [[Prototype]] for instances of the given
      * class, using |Object.prototype| as its [[Prototype]].  Users creating
      * prototype objects with particular internal structure (e.g. reserved
      * slots guaranteed to contain values of particular types) must immediately
      * complete the minimal initialization to make the returned object safe to
      * touch.
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -274,17 +274,17 @@ const Class RegExpObject::class_ = {
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     RegExpObject::trace,
 
     // ClassSpec
     {
-        GenericCreateConstructor<js::regexp_construct, 2, JSFunction::FinalizeKind>,
+        GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>,
         CreateRegExpPrototype,
         nullptr,
         js::regexp_static_props,
         js::regexp_methods,
         js::regexp_properties
     }
 };
 
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -191,17 +191,17 @@ SavedFrame::finishSavedFrameInit(JSConte
     SavedFrame::finalize,       // finalize
     nullptr,                    // call
     nullptr,                    // hasInstance
     nullptr,                    // construct
     nullptr,                    // trace
 
     // ClassSpec
     {
-        GenericCreateConstructor<SavedFrame::construct, 0, JSFunction::FinalizeKind>,
+        GenericCreateConstructor<SavedFrame::construct, 0, gc::AllocKind::FUNCTION>,
         GenericCreatePrototype,
         SavedFrame::staticFunctions,
         nullptr,
         SavedFrame::protoFunctions,
         SavedFrame::protoAccessors,
         SavedFrame::finishSavedFrameInit,
         ClassSpec::DontDefineConstructor
     }
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1776,17 +1776,17 @@ CloneObject(JSContext* cx, HandleNativeO
 
     RootedObject clone(cx);
     if (selfHostedObject->is<JSFunction>()) {
         RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
         bool hasName = selfHostedFunction->atom() != nullptr;
         // Arrow functions use the first extended slot for their lexical |this| value.
         MOZ_ASSERT(!selfHostedFunction->isArrow());
         js::gc::AllocKind kind = hasName
-                                 ? JSFunction::ExtendedFinalizeKind
+                                 ? gc::AllocKind::FUNCTION_EXTENDED
                                  : selfHostedFunction->getAllocKind();
         clone = CloneFunctionObject(cx, selfHostedFunction, cx->global(), kind, TenuredObject);
         // To be able to re-lazify the cloned function, its name in the
         // self-hosting compartment has to be stored on the clone.
         if (clone && hasName)
             clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom()));
     } else if (selfHostedObject->is<RegExpObject>()) {
         RegExpObject& reobj = selfHostedObject->as<RegExpObject>();
--- a/js/src/vm/SharedTypedArrayObject.cpp
+++ b/js/src/vm/SharedTypedArrayObject.cpp
@@ -685,17 +685,17 @@ IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPP
 IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int32, int32_t, int32_t)
 IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32, uint32_t, uint32_t)
 IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32, float, float)
 IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
 
 #define SHARED_TYPED_ARRAY_CLASS_SPEC(_typedArray)                             \
 {                                                                              \
     GenericCreateConstructor<Shared##_typedArray##Object::class_constructor, 3, \
-                             JSFunction::FinalizeKind>,                        \
+                             gc::AllocKind::FUNCTION>,                         \
     Shared##_typedArray##Object::CreatePrototype,                              \
     nullptr,                                                                   \
     nullptr,                                                                   \
     Shared##_typedArray##Object::jsfuncs,                                      \
     Shared##_typedArray##Object::jsprops,                                      \
     Shared##_typedArray##Object::FinishClassInit                               \
 }
 
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -230,17 +230,17 @@ class TypedArrayObjectTemplate : public 
         Handle<GlobalObject*> global = cx->global();
         RootedFunction ctorProto(cx, GlobalObject::getOrCreateTypedArrayConstructor(cx, global));
         if (!ctorProto)
             return nullptr;
 
         return NewFunctionWithProto(cx, class_constructor, 3,
                                     JSFunction::NATIVE_CTOR, NullPtr(),
                                     ClassName(key, cx),
-                                    ctorProto, JSFunction::FinalizeKind,
+                                    ctorProto, gc::AllocKind::FUNCTION,
                                     SingletonObject);
     }
 
     static bool
     finishClassInit(JSContext* cx, HandleObject ctor, HandleObject proto)
     {
         RootedValue bytesValue(cx, Int32Value(BYTES_PER_ELEMENT));
         if (!DefineProperty(cx, ctor, cx->names().BYTES_PER_ELEMENT, bytesValue,
@@ -842,17 +842,17 @@ TypedArrayObject::sharedTypedArrayProtot
     nullptr,                /* mayResolve */
     nullptr,                /* convert */
     nullptr,                /* finalize */
     nullptr,                /* call */
     nullptr,                /* hasInstance */
     nullptr,                /* construct */
     nullptr,                /* trace */
     {
-        GenericCreateConstructor<TypedArrayConstructor, 3, JSFunction::FinalizeKind>,
+        GenericCreateConstructor<TypedArrayConstructor, 3, gc::AllocKind::FUNCTION>,
         GenericCreatePrototype,
         TypedArrayObject::staticFunctions,
         nullptr,
         TypedArrayObject::protoFunctions,
         TypedArrayObject::protoAccessors,
         FinishTypedArrayInit,
         ClassSpec::DontDefineConstructor
     }