Bug 1296688 - Add JSCLASS_FOREGROUND_FINALIZE flag r=sfink r=smaug
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 24 Aug 2016 14:18:10 +0100
changeset 354499 da1819164ab50065df8beafdc465863d0132e943
parent 354498 df8d6a12b605745eead88fca245a6d8c99bf2cba
child 354500 4ae164556a2db8266115d70b7cca8966ae54e44a
push id1324
push usermtabara@mozilla.com
push dateMon, 16 Jan 2017 13:07:44 +0000
treeherdermozilla-release@a01c49833940 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink, smaug
bugs1296688
milestone51.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 1296688 - Add JSCLASS_FOREGROUND_FINALIZE flag r=sfink r=smaug
dom/bindings/Codegen.py
dom/bindings/SimpleGlobalObject.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/xbl/nsXBLBinding.cpp
js/public/Class.h
js/src/asmjs/WasmJS.cpp
js/src/builtin/Intl.cpp
js/src/builtin/MapObject.cpp
js/src/builtin/ModuleObject.cpp
js/src/builtin/TestingFunctions.cpp
js/src/builtin/WeakMapObject.cpp
js/src/ctypes/CTypes.cpp
js/src/ctypes/Library.cpp
js/src/jsapi-tests/testPersistentRooted.cpp
js/src/jsexn.cpp
js/src/jsobjinlines.h
js/src/jsscript.cpp
js/src/perf/jsperf.cpp
js/src/shell/OSObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/PIC.cpp
js/src/vm/RegExpStatics.cpp
js/src/vm/SavedStacks.cpp
js/src/vm/SharedArrayObject.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/wrappers/XrayWrapper.cpp
toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -409,17 +409,17 @@ class CGDOMJSClass(CGThing):
 
     def declare(self):
         return ""
 
     def define(self):
         callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
         objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
         slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
-        classFlags = "JSCLASS_IS_DOMJSCLASS | "
+        classFlags = "JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | "
         if self.descriptor.isGlobal():
             classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
             traceHook = "JS_GlobalObjectTraceHook"
             reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
         else:
             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
             traceHook = 'nullptr'
             reservedSlots = slotCount
--- a/dom/bindings/SimpleGlobalObject.cpp
+++ b/dom/bindings/SimpleGlobalObject.cpp
@@ -76,17 +76,20 @@ static const js::ClassOps SimpleGlobalCl
 
 static const js::ClassExtension SimpleGlobalClassExtension = {
   nullptr,
   SimpleGlobal_moved
 };
 
 const js::Class SimpleGlobalClass = {
     "",
-    JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS,
+    JSCLASS_GLOBAL_FLAGS |
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_PRIVATE_IS_NSISUPPORTS |
+    JSCLASS_FOREGROUND_FINALIZE,
     &SimpleGlobalClassOps,
     JS_NULL_CLASS_SPEC,
     &SimpleGlobalClassExtension,
     JS_NULL_OBJECT_OPS
 };
 
 // static
 JSObject*
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -250,17 +250,18 @@ const static js::ObjectOps sNPObjectJSWr
     nullptr, nullptr, // watch/unwatch
     nullptr, // getElements
     NPObjWrapper_Enumerate,
     nullptr,
 };
 
 const static js::Class sNPObjectJSWrapperClass = {
     NPRUNTIME_JSCLASS_NAME,
-    JSCLASS_HAS_PRIVATE,
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_FOREGROUND_FINALIZE,
     &sNPObjectJSWrapperClassOps,
     JS_NULL_CLASS_SPEC,
     &sNPObjectJSWrapperClassExtension,
     &sNPObjectJSWrapperObjectOps
 };
 
 typedef struct NPObjectMemberPrivate {
     JS::Heap<JSObject *> npobjWrapper;
@@ -288,17 +289,19 @@ NPObjectMember_toPrimitive(JSContext *cx
 static const JSClassOps sNPObjectMemberClassOps = {
   nullptr, nullptr, NPObjectMember_GetProperty, nullptr,
   nullptr, nullptr, nullptr,
   NPObjectMember_Finalize, NPObjectMember_Call,
   nullptr, nullptr, NPObjectMember_Trace
 };
 
 static const JSClass sNPObjectMemberClass = {
-  "NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE,
+  "NPObject Ambiguous Member class",
+  JSCLASS_HAS_PRIVATE |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sNPObjectMemberClassOps
 };
 
 static void
 OnWrapperDestroyed();
 
 static void
 TraceJSObjWrappers(JSTracer *trc, void *data)
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -91,17 +91,19 @@ static const JSClassOps gPrototypeJSClas
     nullptr, nullptr, nullptr, nullptr,
     XBLEnumerate, nullptr,
     nullptr, XBLFinalize,
     nullptr, nullptr, nullptr, nullptr
 };
 
 static const JSClass gPrototypeJSClass = {
     "XBL prototype JSClass",
-    JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_PRIVATE_IS_NSISUPPORTS |
+    JSCLASS_FOREGROUND_FINALIZE |
     // Our one reserved slot holds the relevant nsXBLPrototypeBinding
     JSCLASS_HAS_RESERVED_SLOTS(1),
     &gPrototypeJSClassOps
 };
 
 // Implementation /////////////////////////////////////////////////////////////////
 
 // Constructors/Destructors
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -762,16 +762,17 @@ struct JSClass {
 
 #define JSCLASS_SKIP_NURSERY_FINALIZE   (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5))
 
 // Reserved for embeddings.
 #define JSCLASS_USERBIT2                (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6))
 #define JSCLASS_USERBIT3                (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7))
 
 #define JSCLASS_BACKGROUND_FINALIZE     (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8))
+#define JSCLASS_FOREGROUND_FINALIZE     (1<<(JSCLASS_HIGH_FLAGS_SHIFT+9))
 
 // Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see
 // below.
 
 // ECMA-262 requires that most constructors used internally create objects
 // with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
 // member initial value.  The "original ... value" verbiage is there because
 // in ECMA-262, global properties naming class objects are read/write and
--- a/js/src/asmjs/WasmJS.cpp
+++ b/js/src/asmjs/WasmJS.cpp
@@ -349,17 +349,18 @@ const ClassOps WasmModuleObject::classOp
     nullptr, /* mayResolve */
     WasmModuleObject::finalize
 };
 
 const Class WasmModuleObject::class_ =
 {
     "WebAssembly.Module",
     JSCLASS_DELAY_METADATA_BUILDER |
-    JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS),
+    JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &WasmModuleObject::classOps_,
 };
 
 const JSPropertySpec WasmModuleObject::properties[] =
 { JS_PS_END };
 
 const JSFunctionSpec WasmModuleObject::methods[] =
 { JS_FS_END };
@@ -482,17 +483,18 @@ const ClassOps WasmInstanceObject::class
     nullptr, /* construct */
     WasmInstanceObject::trace
 };
 
 const Class WasmInstanceObject::class_ =
 {
     "WebAssembly.Instance",
     JSCLASS_DELAY_METADATA_BUILDER |
-    JSCLASS_HAS_RESERVED_SLOTS(WasmInstanceObject::RESERVED_SLOTS),
+    JSCLASS_HAS_RESERVED_SLOTS(WasmInstanceObject::RESERVED_SLOTS) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &WasmInstanceObject::classOps_,
 };
 
 const JSPropertySpec WasmInstanceObject::properties[] =
 { JS_PS_END };
 
 const JSFunctionSpec WasmInstanceObject::methods[] =
 { JS_FS_END };
@@ -828,17 +830,18 @@ const ClassOps WasmTableObject::classOps
     nullptr, /* construct */
     WasmTableObject::trace
 };
 
 const Class WasmTableObject::class_ =
 {
     "WebAssembly.Table",
     JSCLASS_DELAY_METADATA_BUILDER |
-    JSCLASS_HAS_RESERVED_SLOTS(WasmTableObject::RESERVED_SLOTS),
+    JSCLASS_HAS_RESERVED_SLOTS(WasmTableObject::RESERVED_SLOTS) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &WasmTableObject::classOps_
 };
 
 bool
 WasmTableObject::isNewborn() const
 {
     MOZ_ASSERT(is<WasmTableObject>());
     return getReservedSlot(TABLE_SLOT).isUndefined();
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -653,17 +653,18 @@ static const ClassOps CollatorClassOps =
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     collator_finalize
 };
 
 static const Class CollatorClass = {
     js_Object_str,
-    JSCLASS_HAS_RESERVED_SLOTS(COLLATOR_SLOTS_COUNT),
+    JSCLASS_HAS_RESERVED_SLOTS(COLLATOR_SLOTS_COUNT) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &CollatorClassOps
 };
 
 #if JS_HAS_TOSOURCE
 static bool
 collator_toSource(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1142,17 +1143,18 @@ static const ClassOps NumberFormatClassO
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     numberFormat_finalize
 };
 
 static const Class NumberFormatClass = {
     js_Object_str,
-    JSCLASS_HAS_RESERVED_SLOTS(NUMBER_FORMAT_SLOTS_COUNT),
+    JSCLASS_HAS_RESERVED_SLOTS(NUMBER_FORMAT_SLOTS_COUNT) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &NumberFormatClassOps
 };
 
 #if JS_HAS_TOSOURCE
 static bool
 numberFormat_toSource(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1606,17 +1608,18 @@ static const ClassOps DateTimeFormatClas
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     dateTimeFormat_finalize
 };
 
 static const Class DateTimeFormatClass = {
     js_Object_str,
-    JSCLASS_HAS_RESERVED_SLOTS(DATE_TIME_FORMAT_SLOTS_COUNT),
+    JSCLASS_HAS_RESERVED_SLOTS(DATE_TIME_FORMAT_SLOTS_COUNT) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &DateTimeFormatClassOps
 };
 
 #if JS_HAS_TOSOURCE
 static bool
 dateTimeFormat_toSource(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -112,17 +112,18 @@ static const ClassOps MapIteratorObjectC
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     MapIteratorObject::finalize
 };
 
 const Class MapIteratorObject::class_ = {
     "Map Iterator",
-    JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount),
+    JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &MapIteratorObjectClassOps
 };
 
 const JSFunctionSpec MapIteratorObject::methods[] = {
     JS_SELF_HOSTED_FN("next", "MapIteratorNext", 0, 0),
     JS_FS_END
 };
 
@@ -264,17 +265,18 @@ const ClassOps MapObject::classOps_ = {
     nullptr, // hasInstance
     nullptr, // construct
     mark
 };
 
 const Class MapObject::class_ = {
     "Map",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Map) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &MapObject::classOps_
 };
 
 const JSPropertySpec MapObject::properties[] = {
     JS_PSG("size", size, 0),
     JS_PS_END
 };
 
@@ -851,17 +853,18 @@ static const ClassOps SetIteratorObjectC
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     SetIteratorObject::finalize
 };
 
 const Class SetIteratorObject::class_ = {
     "Set Iterator",
-    JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount),
+    JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &SetIteratorObjectClassOps
 };
 
 const JSFunctionSpec SetIteratorObject::methods[] = {
     JS_FN("next", next, 0, 0),
     JS_FS_END
 };
 
@@ -996,17 +999,18 @@ const ClassOps SetObject::classOps_ = {
     nullptr, // hasInstance
     nullptr, // construct
     mark
 };
 
 const Class SetObject::class_ = {
     "Set",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Set),
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Set) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &SetObject::classOps_
 };
 
 const JSPropertySpec SetObject::properties[] = {
     JS_PSG("size", size, 0),
     JS_PS_END
 };
 
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -559,17 +559,18 @@ ModuleObject::classOps_ = {
     nullptr,        /* construct   */
     ModuleObject::trace
 };
 
 /* static */ const Class
 ModuleObject::class_ = {
     "Module",
     JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) |
-    JSCLASS_IS_ANONYMOUS,
+    JSCLASS_IS_ANONYMOUS |
+    JSCLASS_FOREGROUND_FINALIZE,
     &ModuleObject::classOps_
 };
 
 #define DEFINE_ARRAY_SLOT_ACCESSOR(cls, name, slot)                           \
     ArrayObject&                                                              \
     cls::name() const                                                         \
     {                                                                         \
         return getFixedSlot(cls::slot).toObject().as<ArrayObject>();          \
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1503,17 +1503,19 @@ static const JSClassOps FinalizeCounterC
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     finalize_counter_finalize
 };
 
 static const JSClass FinalizeCounterClass = {
-    "FinalizeCounter", JSCLASS_IS_ANONYMOUS,
+    "FinalizeCounter",
+    JSCLASS_IS_ANONYMOUS |
+    JSCLASS_FOREGROUND_FINALIZE,
     &FinalizeCounterClassOps
 };
 
 static bool
 MakeFinalizeObserver(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -2187,17 +2189,19 @@ static const ClassOps CloneBufferObjectC
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     CloneBufferObject::Finalize
 };
 
 const Class CloneBufferObject::class_ = {
-    "CloneBuffer", JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS),
+    "CloneBuffer",
+    JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &CloneBufferObjectClassOps
 };
 
 const JSPropertySpec CloneBufferObject::props_[] = {
     JS_PSGS("clonebuffer", getCloneBuffer, setCloneBuffer, 0),
     JS_PS_END
 };
 
--- a/js/src/builtin/WeakMapObject.cpp
+++ b/js/src/builtin/WeakMapObject.cpp
@@ -394,17 +394,18 @@ static const ClassOps WeakMapObjectClass
     nullptr, /* hasInstance */
     nullptr, /* construct */
     WeakMap_mark
 };
 
 const Class WeakMapObject::class_ = {
     "WeakMap",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap),
+    JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &WeakMapObjectClassOps
 };
 
 static const JSFunctionSpec weak_map_methods[] = {
     JS_FN("has",    WeakMap_has, 1, 0),
     JS_FN("get",    WeakMap_get, 1, 0),
     JS_FN("delete", WeakMap_delete, 1, 0),
     JS_FN("set",    WeakMap_set, 2, 0),
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -568,39 +568,42 @@ static const JSClass sCDataProtoClass = 
 static const JSClassOps sCTypeClassOps = {
   nullptr, nullptr, nullptr, nullptr,
   nullptr, nullptr, nullptr, CType::Finalize,
   CType::ConstructData, CType::HasInstance, CType::ConstructData,
   CType::Trace
 };
 static const JSClass sCTypeClass = {
   "CType",
-  JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS),
+  JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS) |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sCTypeClassOps
 };
 
 static const JSClassOps sCDataClassOps = {
   nullptr, nullptr, ArrayType::Getter, ArrayType::Setter,
   nullptr, nullptr, nullptr, CData::Finalize,
   FunctionType::Call, nullptr, FunctionType::Call
 };
 static const JSClass sCDataClass = {
   "CData",
-  JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS),
+  JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS) |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sCDataClassOps
 };
 
 static const JSClassOps sCClosureClassOps = {
   nullptr, nullptr, nullptr, nullptr,
   nullptr, nullptr, nullptr, CClosure::Finalize,
   nullptr, nullptr, nullptr, CClosure::Trace
 };
 static const JSClass sCClosureClass = {
   "CClosure",
-  JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS),
+  JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS) |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sCClosureClassOps
 };
 
 /*
  * Class representing the prototype of CDataFinalizer.
  */
 static const JSClass sCDataFinalizerProtoClass = {
   "CDataFinalizer",
@@ -614,17 +617,19 @@ static const JSClass sCDataFinalizerProt
  * |CDataFinalizer::Private|) and slots (see |CDataFinalizerSlots|).
  */
 static const JSClassOps sCDataFinalizerClassOps = {
   nullptr, nullptr, nullptr, nullptr,
   nullptr, nullptr, nullptr, CDataFinalizer::Finalize
 };
 static const JSClass sCDataFinalizerClass = {
   "CDataFinalizer",
-  JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS),
+  JSCLASS_HAS_PRIVATE |
+  JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS) |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sCDataFinalizerClassOps
 };
 
 
 #define CTYPESFN_FLAGS \
   (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
 
 #define CTYPESCTOR_FLAGS \
@@ -804,23 +809,25 @@ static const JSClass sUInt64ProtoClass =
 
 static const JSClassOps sInt64ClassOps = {
   nullptr, nullptr, nullptr, nullptr,
   nullptr, nullptr, nullptr, Int64Base::Finalize
 };
 
 static const JSClass sInt64Class = {
   "Int64",
-  JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
+  JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS) |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sInt64ClassOps
 };
 
 static const JSClass sUInt64Class = {
   "UInt64",
-  JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
+  JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS) |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sInt64ClassOps
 };
 
 static const JSFunctionSpec sInt64StaticFunctions[] = {
   JS_FN("compare", Int64::Compare, 2, CTYPESFN_FLAGS),
   JS_FN("lo", Int64::Lo, 1, CTYPESFN_FLAGS),
   JS_FN("hi", Int64::Hi, 1, CTYPESFN_FLAGS),
   // "join" is defined specially; see InitInt64Class.
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -34,17 +34,18 @@ typedef Rooted<JSFlatString*>    RootedF
 
 static const JSClassOps sLibraryClassOps = {
   nullptr, nullptr, nullptr, nullptr,
   nullptr, nullptr, nullptr, Library::Finalize
 };
 
 static const JSClass sLibraryClass = {
   "Library",
-  JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS),
+  JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS) |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sLibraryClassOps
 };
 
 #define CTYPESFN_FLAGS \
   (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
 
 static const JSFunctionSpec sLibraryFunctions[] = {
   JS_FN("close",   Library::Close,   0, CTYPESFN_FLAGS),
--- a/js/src/jsapi-tests/testPersistentRooted.cpp
+++ b/js/src/jsapi-tests/testPersistentRooted.cpp
@@ -32,17 +32,17 @@ static const JSClassOps BarkWhenTracedCl
     nullptr,
     nullptr,
     nullptr,
     BarkWhenTracedClass::trace
 };
 
 const JSClass BarkWhenTracedClass::class_ = {
     "BarkWhenTracedClass",
-    0,
+    JSCLASS_FOREGROUND_FINALIZE,
     &BarkWhenTracedClassClassOps
 };
 
 struct Kennel {
     PersistentRootedObject obj;
     Kennel() { }
     explicit Kennel(JSContext* cx) : obj(cx) { }
     Kennel(JSContext* cx, const HandleObject& woof) : obj(cx, woof) { }
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -79,17 +79,18 @@ static const ClassOps ErrorObjectClassOp
     nullptr,                 /* construct   */
     nullptr,                 /* trace       */
 };
 
 #define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \
     { \
         js_Error_str, /* yes, really */ \
         JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
-        JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS), \
+        JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \
+        JSCLASS_FOREGROUND_FINALIZE, \
         &ErrorObjectClassOps, \
         classSpecPtr \
     }
 
 const ClassSpec
 ErrorObject::errorClassSpec_ = {
     ErrorObject::createConstructor,
     ErrorObject::createProto,
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -318,45 +318,60 @@ SetNewObjectMetadata(ExclusiveContext* c
 }
 
 } // namespace js
 
 /* static */ inline JSObject*
 JSObject::create(js::ExclusiveContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
                  js::HandleShape shape, js::HandleObjectGroup group)
 {
+    const js::Class* clasp = group->clasp();
+
     MOZ_ASSERT(shape && group);
-    MOZ_ASSERT(group->clasp() == shape->getObjectClass());
-    MOZ_ASSERT(group->clasp() != &js::ArrayObject::class_);
-    MOZ_ASSERT_IF(!js::ClassCanHaveFixedData(group->clasp()),
-                  js::gc::GetGCKindSlots(kind, group->clasp()) == shape->numFixedSlots());
-    MOZ_ASSERT_IF(group->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE,
-                  IsBackgroundFinalized(kind));
-    MOZ_ASSERT_IF(group->clasp()->hasFinalize(),
-                  heap == js::gc::TenuredHeap ||
-                  (group->clasp()->flags & JSCLASS_SKIP_NURSERY_FINALIZE));
-    MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(),
-                  heap == js::gc::TenuredHeap);
+    MOZ_ASSERT(clasp == shape->getObjectClass());
+    MOZ_ASSERT(clasp != &js::ArrayObject::class_);
+    MOZ_ASSERT_IF(!js::ClassCanHaveFixedData(clasp),
+                  js::gc::GetGCKindSlots(kind, clasp) == shape->numFixedSlots());
+
+#ifdef DEBUG
+    static const uint32_t FinalizeMask = JSCLASS_FOREGROUND_FINALIZE | JSCLASS_BACKGROUND_FINALIZE;
+    uint32_t flags = clasp->flags;
+    uint32_t finalizeFlags = flags & FinalizeMask;
+
+    // Classes with a finalizer must specify whether instances will be finalized
+    // on the main thread or in the background, except proxies whose behaviour
+    // depends on the target object.
+    if (clasp->hasFinalize() && !clasp->isProxy()) {
+        MOZ_ASSERT(finalizeFlags == JSCLASS_FOREGROUND_FINALIZE ||
+                   finalizeFlags == JSCLASS_BACKGROUND_FINALIZE);
+        MOZ_ASSERT((finalizeFlags == JSCLASS_BACKGROUND_FINALIZE) == IsBackgroundFinalized(kind));
+    } else {
+        MOZ_ASSERT(finalizeFlags == 0);
+    }
+
+    MOZ_ASSERT_IF(clasp->hasFinalize(), heap == js::gc::TenuredHeap ||
+                                        (flags & JSCLASS_SKIP_NURSERY_FINALIZE));
+    MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(), heap == js::gc::TenuredHeap);
+#endif
+
     MOZ_ASSERT(!cx->compartment()->hasObjectPendingMetadata());
 
     // Non-native classes cannot have reserved slots or private data, and the
     // objects can't have any fixed slots, for compatibility with
     // GetReservedOrProxyPrivateSlot.
-    MOZ_ASSERT_IF(!group->clasp()->isNative(), JSCLASS_RESERVED_SLOTS(group->clasp()) == 0);
-    MOZ_ASSERT_IF(!group->clasp()->isNative(), !group->clasp()->hasPrivate());
-    MOZ_ASSERT_IF(!group->clasp()->isNative(), shape->numFixedSlots() == 0);
-    MOZ_ASSERT_IF(!group->clasp()->isNative(), shape->slotSpan() == 0);
-
-    const js::Class* clasp = group->clasp();
+    MOZ_ASSERT_IF(!clasp->isNative(), JSCLASS_RESERVED_SLOTS(clasp) == 0);
+    MOZ_ASSERT_IF(!clasp->isNative(), !clasp->hasPrivate());
+    MOZ_ASSERT_IF(!clasp->isNative(), shape->numFixedSlots() == 0);
+    MOZ_ASSERT_IF(!clasp->isNative(), shape->slotSpan() == 0);
 
     size_t nDynamicSlots = 0;
-    if (group->clasp()->isNative()) {
+    if (clasp->isNative()) {
         nDynamicSlots = js::NativeObject::dynamicSlotsCount(shape->numFixedSlots(),
                                                             shape->slotSpan(), clasp);
-    } else if (group->clasp()->isProxy()) {
+    } else if (clasp->isProxy()) {
         // Proxy objects overlay the |slots| field with a ProxyValueArray.
         MOZ_ASSERT(sizeof(js::detail::ProxyValueArray) % sizeof(js::HeapSlot) == 0);
         nDynamicSlots = sizeof(js::detail::ProxyValueArray) / sizeof(js::HeapSlot);
     }
 
     JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
     if (!obj)
         return nullptr;
@@ -375,30 +390,30 @@ JSObject::create(js::ExclusiveContext* c
 
     if (clasp->hasPrivate())
         obj->as<js::NativeObject>().privateRef(shape->numFixedSlots()) = nullptr;
 
     if (size_t span = shape->slotSpan())
         obj->as<js::NativeObject>().initializeSlotRange(0, span);
 
     // JSFunction's fixed slots expect POD-style initialization.
-    if (group->clasp()->isJSFunction()) {
+    if (clasp->isJSFunction()) {
         MOZ_ASSERT(kind == js::gc::AllocKind::FUNCTION ||
                    kind == js::gc::AllocKind::FUNCTION_EXTENDED);
         size_t size =
             kind == js::gc::AllocKind::FUNCTION ? sizeof(JSFunction) : sizeof(js::FunctionExtended);
         memset(obj->as<JSFunction>().fixedSlots(), 0, size - sizeof(js::NativeObject));
         if (kind == js::gc::AllocKind::FUNCTION_EXTENDED) {
             // SetNewObjectMetadata may gc, which will be unhappy if flags &
             // EXTENDED doesn't match the arena's AllocKind.
             obj->as<JSFunction>().setFlags(JSFunction::EXTENDED);
         }
     }
 
-    if (group->clasp()->shouldDelayMetadataBuilder())
+    if (clasp->shouldDelayMetadataBuilder())
         cx->compartment()->setObjectPendingMetadata(cx, obj);
     else
         obj = SetNewObjectMetadata(cx, obj);
 
     js::gc::TraceCreateObject(obj);
 
     return obj;
 }
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1644,17 +1644,18 @@ static const ClassOps ScriptSourceObject
     nullptr, /* hasInstance */
     nullptr, /* construct */
     ScriptSourceObject::trace
 };
 
 const Class ScriptSourceObject::class_ = {
     "ScriptSource",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
-    JSCLASS_IS_ANONYMOUS,
+    JSCLASS_IS_ANONYMOUS |
+    JSCLASS_FOREGROUND_FINALIZE,
     &ScriptSourceObjectClassOps
 };
 
 ScriptSourceObject*
 ScriptSourceObject::create(ExclusiveContext* cx, ScriptSource* source)
 {
     RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, nullptr));
     if (!object)
--- a/js/src/perf/jsperf.cpp
+++ b/js/src/perf/jsperf.cpp
@@ -167,17 +167,18 @@ static const JSClassOps pm_classOps = {
     nullptr,
     nullptr,
     nullptr,
     pm_finalize
 };
 
 static const JSClass pm_class = {
     "PerfMeasurement",
-    JSCLASS_HAS_PRIVATE,
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_FOREGROUND_FINALIZE,
     &pm_classOps
 };
 
 // Constructor and destructor
 
 static bool
 pm_construct(JSContext* cx, unsigned argc, Value* vp)
 {
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -407,17 +407,18 @@ static const js::ClassOps FileObjectClas
     nullptr,               /* call */
     nullptr,               /* hasInstance */
     nullptr,               /* construct */
     nullptr                /* trace */
 };
 
 const js::Class FileObject::class_ = {
     "File",
-    JSCLASS_HAS_RESERVED_SLOTS(FileObject::NUM_SLOTS),
+    JSCLASS_HAS_RESERVED_SLOTS(FileObject::NUM_SLOTS) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &FileObjectClassOps
 };
 
 static FileObject*
 redirect(JSContext* cx, HandleString relFilename, RCFile** globalFile)
 {
     RootedString filename(cx, ResolvePath(cx, relFilename, RootRelative));
     if (!filename)
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -89,17 +89,19 @@ const ClassOps DebuggerFrame::classOps_ 
     nullptr,    /* call        */
     nullptr,    /* hasInstance */
     nullptr,    /* construct   */
     nullptr,    /* trace   */
 };
 
 const Class DebuggerFrame::class_ = {
     "Frame",
-    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT),
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &DebuggerFrame::classOps_
 };
 
 enum {
     JSSLOT_DEBUGARGUMENTS_FRAME,
     JSSLOT_DEBUGARGUMENTS_COUNT
 };
 
@@ -3122,17 +3124,18 @@ const ClassOps Debugger::classOps_ = {
     nullptr,    /* hasInstance */
     nullptr,    /* construct   */
     Debugger::traceObject
 };
 
 const Class Debugger::class_ = {
     "Debugger",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUG_COUNT),
+    JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUG_COUNT) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &Debugger::classOps_
 };
 
 /* static */ Debugger*
 Debugger::fromThisValue(JSContext* cx, const CallArgs& args, const char* fnname)
 {
     JSObject* thisobj = NonNullObject(cx, args.thisv());
     if (!thisobj)
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -658,17 +658,19 @@ GlobalDebuggees_classOps = {
     nullptr,
     nullptr,
     nullptr,
     GlobalDebuggees_finalize
 };
 
 static const Class
 GlobalDebuggees_class = {
-    "GlobalDebuggee", JSCLASS_HAS_PRIVATE,
+    "GlobalDebuggee",
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_FOREGROUND_FINALIZE,
     &GlobalDebuggees_classOps
 };
 
 GlobalObject::DebuggerVector*
 GlobalObject::getDebuggers() const
 {
     Value debuggers = getReservedSlot(DEBUGGERS);
     if (debuggers.isUndefined())
--- a/js/src/vm/PIC.cpp
+++ b/js/src/vm/PIC.cpp
@@ -292,17 +292,19 @@ static const ClassOps ForOfPICClassOps =
     nullptr, nullptr, nullptr, ForOfPIC_finalize,
     nullptr,              /* call        */
     nullptr,              /* hasInstance */
     nullptr,              /* construct   */
     ForOfPIC_traceObject
 };
 
 const Class ForOfPIC::class_ = {
-    "ForOfPIC", JSCLASS_HAS_PRIVATE,
+    "ForOfPIC",
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_FOREGROUND_FINALIZE,
     &ForOfPICClassOps
 };
 
 /* static */ NativeObject*
 js::ForOfPIC::createForOfPICObject(JSContext* cx, Handle<GlobalObject*> global)
 {
     assertSameCompartment(cx, global);
     NativeObject* obj = NewNativeObjectWithGivenProto(cx, &ForOfPIC::class_, nullptr);
--- a/js/src/vm/RegExpStatics.cpp
+++ b/js/src/vm/RegExpStatics.cpp
@@ -46,17 +46,18 @@ static const ClassOps RegExpStaticsObjec
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     resc_trace
 };
 
 const Class RegExpStaticsObject::class_ = {
     "RegExpStatics",
-    JSCLASS_HAS_PRIVATE,
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_FOREGROUND_FINALIZE,
     &RegExpStaticsObjectClassOps
 };
 
 RegExpStaticsObject*
 RegExpStatics::create(ExclusiveContext* cx, Handle<GlobalObject*> parent)
 {
     RegExpStaticsObject* obj = NewObjectWithGivenProto<RegExpStaticsObject>(cx, nullptr);
     if (!obj)
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -329,17 +329,18 @@ const ClassSpec SavedFrame::classSpec_ =
     ClassSpec::DontDefineConstructor
 };
 
 /* static */ const Class SavedFrame::class_ = {
     "SavedFrame",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) |
-    JSCLASS_IS_ANONYMOUS,
+    JSCLASS_IS_ANONYMOUS |
+    JSCLASS_FOREGROUND_FINALIZE,
     &SavedFrameClassOps,
     &SavedFrame::classSpec_
 };
 
 /* static */ const JSFunctionSpec
 SavedFrame::staticFunctions[] = {
     JS_FS_END
 };
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -346,17 +346,18 @@ static const ClassOps SharedArrayBufferO
     nullptr, /* construct */
     nullptr, /* trace */
 };
 
 const Class SharedArrayBufferObject::class_ = {
     "SharedArrayBuffer",
     JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
+    JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &SharedArrayBufferObjectClassOps,
     JS_NULL_CLASS_SPEC,
     JS_NULL_CLASS_EXT
 };
 
 JSObject*
 js::InitSharedArrayBufferClass(JSContext* cx, HandleObject obj)
 {
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -549,17 +549,18 @@ static const js::ClassOps SandboxClassOp
 
 static const js::ClassExtension SandboxClassExtension = {
     nullptr,      /* weakmapKeyDelegateOp */
     sandbox_moved /* objectMovedOp */
 };
 
 static const js::Class SandboxClass = {
     "Sandbox",
-    XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
+    XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &SandboxClassOps,
     JS_NULL_CLASS_SPEC,
     &SandboxClassExtension,
     JS_NULL_OBJECT_OPS
 };
 
 // Note to whomever comes here to remove addProperty hooks: billm has promised
 // to do the work for this class.
@@ -568,17 +569,18 @@ static const js::ClassOps SandboxWriteTo
     JS_EnumerateStandardClasses, JS_ResolveStandardClass,
     JS_MayResolveStandardClass,
     sandbox_finalize,
     nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
 };
 
 static const js::Class SandboxWriteToProtoClass = {
     "Sandbox",
-    XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
+    XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &SandboxWriteToProtoClassOps,
     JS_NULL_CLASS_SPEC,
     &SandboxClassExtension,
     JS_NULL_OBJECT_OPS
 };
 
 static const JSFunctionSpec SandboxFunctions[] = {
     JS_FS("dump",    SandboxDump,    1,0),
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1382,40 +1382,20 @@ pre_call_clean_up:
 const char*
 nsXPCWrappedJSClass::GetInterfaceName()
 {
     if (!mName)
         mInfo->GetName(&mName);
     return mName;
 }
 
-static void
-FinalizeStub(JSFreeOp* fop, JSObject* obj)
-{
-}
-
-static const JSClassOps XPCOutParamClassOps = {
-    nullptr,   /* addProperty */
-    nullptr,   /* delProperty */
-    nullptr,   /* getProperty */
-    nullptr,   /* setProperty */
-    nullptr,   /* enumerate */
-    nullptr,   /* resolve */
-    nullptr,   /* mayResolve */
-    FinalizeStub,
-    nullptr,   /* call */
-    nullptr,   /* hasInstance */
-    nullptr,   /* construct */
-    nullptr    /* trace */
-};
-
 static const JSClass XPCOutParamClass = {
     "XPCOutParam",
     0,
-    &XPCOutParamClassOps
+    JS_NULL_CLASS_OPS
 };
 
 bool
 xpc::IsOutObject(JSContext* cx, JSObject* obj)
 {
     return js::GetObjectJSClass(obj) == &XPCOutParamClass;
 }
 
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -640,17 +640,18 @@ static const js::ClassExtension XPC_WN_J
     nullptr, // weakmapKeyDelegateOp
     WrappedNativeObjectMoved
 };
 
 const js::Class XPC_WN_NoHelper_JSClass = {
     "XPCWrappedNative_NoHelper",
     WRAPPER_FLAGS |
     JSCLASS_IS_WRAPPED_NATIVE |
-    JSCLASS_PRIVATE_IS_NSISUPPORTS,
+    JSCLASS_PRIVATE_IS_NSISUPPORTS |
+    JSCLASS_FOREGROUND_FINALIZE,
     &XPC_WN_NoHelper_JSClassOps,
     JS_NULL_CLASS_SPEC,
     &XPC_WN_JSClassExtension,
     JS_NULL_OBJECT_OPS
 };
 
 
 /***************************************************************************/
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -204,17 +204,17 @@ extern const char XPC_XPCONNECT_CONTRACT
         result = (char*) nsMemory::Clone(src,                                 \
                                          sizeof(char)*(strlen(src)+1));       \
     else                                                                      \
         result = nullptr;                                                      \
     *dest = result;                                                           \
     return (result || !src) ? NS_OK : NS_ERROR_OUT_OF_MEMORY
 
 
-#define WRAPPER_FLAGS JSCLASS_HAS_PRIVATE
+#define WRAPPER_FLAGS (JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE)
 
 // If IS_WN_CLASS for the JSClass of an object is true, the object is a
 // wrappednative wrapper, holding the XPCWrappedNative in its private slot.
 static inline bool IS_WN_CLASS(const js::Class* clazz)
 {
     return clazz->isWrappedNative();
 }
 
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1057,17 +1057,18 @@ ExpandoObjectFinalize(JSFreeOp* fop, JSO
 
 static const JSClassOps ExpandoObjectClassOps = {
     nullptr, nullptr, nullptr, nullptr,
     nullptr, nullptr, nullptr, ExpandoObjectFinalize
 };
 
 const JSClass ExpandoObjectClass = {
     "XrayExpandoObject",
-    JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_EXPANDO_COUNT),
+    JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_EXPANDO_COUNT) |
+    JSCLASS_FOREGROUND_FINALIZE,
     &ExpandoObjectClassOps
 };
 
 bool
 XrayTraits::expandoObjectMatchesConsumer(JSContext* cx,
                                          HandleObject expandoObject,
                                          nsIPrincipal* consumerOrigin,
                                          HandleObject exclusiveGlobal)
--- a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
+++ b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
@@ -124,17 +124,18 @@ static const JSClassOps sWitnessClassOps
   nullptr /* enumerate */,
   nullptr /* resolve */,
   nullptr /* mayResolve */,
   Finalize /* finalize */
 };
 
 static const JSClass sWitnessClass = {
   "FinalizationWitness",
-  JSCLASS_HAS_RESERVED_SLOTS(WITNESS_INSTANCES_SLOTS),
+  JSCLASS_HAS_RESERVED_SLOTS(WITNESS_INSTANCES_SLOTS) |
+  JSCLASS_FOREGROUND_FINALIZE,
   &sWitnessClassOps
 };
 
 bool IsWitness(JS::Handle<JS::Value> v)
 {
   return v.isObject() && JS_GetClass(&v.toObject()) == &sWitnessClass;
 }