Bug 1103152 - Remove JS_DeletePropertyStub, JS_EnumerateStub, JS_ResolveStub, and JS_ConvertStub. Make five mandatory JSClass hooks optional (nullable). r=bhackett.
☠☠ backed out by 63f71ff39bbc ☠ ☠
authorJason Orendorff <jorendorff@mozilla.com>
Fri, 21 Nov 2014 15:14:58 -0600
changeset 217286 b3f742c00ba1395e499d859b6374ca6864d4f522
parent 217285 c69e27e865656ccd9180a82e5ca761e32140860c
child 217287 64aa4c4d0691c200eedf8ef98d697c3d0e17ae8d
push id27877
push usercbook@mozilla.com
push dateTue, 25 Nov 2014 11:48:25 +0000
treeherderautoland@4631a7474d8a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs1103152
milestone36.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 1103152 - Remove JS_DeletePropertyStub, JS_EnumerateStub, JS_ResolveStub, and JS_ConvertStub. Make five mandatory JSClass hooks optional (nullable). r=bhackett.
dom/base/nsDOMClassInfo.cpp
dom/bindings/Codegen.py
dom/indexedDB/ActorsParent.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/xbl/nsXBLBinding.cpp
js/src/asmjs/AsmJSModule.cpp
js/src/builtin/AtomicsObject.cpp
js/src/builtin/Intl.cpp
js/src/builtin/MapObject.cpp
js/src/builtin/SIMD.cpp
js/src/builtin/SymbolObject.cpp
js/src/builtin/TestingFunctions.cpp
js/src/builtin/TypedObject.cpp
js/src/builtin/WeakSetObject.cpp
js/src/ctypes/CTypes.cpp
js/src/ctypes/Library.cpp
js/src/gdb/gdb-tests.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonCaches.cpp
js/src/jsapi-tests/testAddPropertyPropcache.cpp
js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
js/src/jsapi-tests/testChromeBuffer.cpp
js/src/jsapi-tests/testClassGetter.cpp
js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
js/src/jsapi-tests/testLookup.cpp
js/src/jsapi-tests/testNewObject.cpp
js/src/jsapi-tests/testObjectEmulatingUndefined.cpp
js/src/jsapi-tests/testOps.cpp
js/src/jsapi-tests/testPersistentRooted.cpp
js/src/jsapi-tests/testProfileStrings.cpp
js/src/jsapi-tests/testPropCache.cpp
js/src/jsapi-tests/testResolveRecursion.cpp
js/src/jsapi-tests/testSetProperty.cpp
js/src/jsapi-tests/testWeakMap.cpp
js/src/jsapi-tests/tests.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jscntxtinlines.h
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsinfer.cpp
js/src/jsiter.cpp
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/json.cpp
js/src/jsscript.cpp
js/src/jsstr.cpp
js/src/jsweakmap.cpp
js/src/perf/jsperf.cpp
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/ArrayBufferObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/DebuggerMemory.cpp
js/src/vm/GeneratorObject.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/HelperThreads.cpp
js/src/vm/Interpreter.cpp
js/src/vm/NativeObject-inl.h
js/src/vm/NativeObject.cpp
js/src/vm/PIC.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpStatics.cpp
js/src/vm/SavedStacks.cpp
js/src/vm/ScopeObject.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/SharedArrayObject.cpp
js/src/vm/SharedTypedArrayObject.cpp
js/src/vm/TypedArrayObject.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCShellImpl.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
netwerk/base/src/ProxyAutoConfig.cpp
toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
toolkit/components/telemetry/Telemetry.cpp
xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -426,18 +426,17 @@ NS_INTERFACE_MAP_BEGIN(nsDOMClassInfo)
   NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
   NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClassInfo)
 NS_INTERFACE_MAP_END
 
 
 static const JSClass sDOMConstructorProtoClass = {
   "DOM Constructor.prototype", 0,
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 
 static const char *
 CutPrefix(const char *aName) {
   static const char prefix_nsIDOM[] = "nsIDOM";
   static const char prefix_nsI[]    = "nsI";
 
@@ -2048,18 +2047,17 @@ nsWindowSH::NameStructEnabled(JSContext*
 
 #ifdef RELEASE_BUILD
 #define USE_CONTROLLERS_SHIM
 #endif
 
 #ifdef USE_CONTROLLERS_SHIM
 static const JSClass ControllersShimClass = {
     "XULControllers", 0,
-    JS_PropertyStub,   JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 #endif
 
 // static
 nsresult
 nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
                           JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                           JS::MutableHandle<JSPropertyDescriptor> desc)
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -420,31 +420,31 @@ class CGDOMJSClass(CGThing):
             reservedSlots = slotCount
         if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
             resolveHook = RESOLVE_HOOK_NAME
             enumerateHook = ENUMERATE_HOOK_NAME
         elif self.descriptor.isGlobal():
             resolveHook = "mozilla::dom::ResolveGlobal"
             enumerateHook = "mozilla::dom::EnumerateGlobal"
         else:
-            resolveHook = "JS_ResolveStub"
-            enumerateHook = "JS_EnumerateStub"
+            resolveHook = "nullptr"
+            enumerateHook = "nullptr"
 
         return fill(
             """
             static const DOMJSClass Class = {
               { "${name}",
                 ${flags},
                 ${addProperty}, /* addProperty */
-                JS_DeletePropertyStub, /* delProperty */
+                nullptr,               /* delProperty */
                 JS_PropertyStub,       /* getProperty */
                 JS_StrictPropertyStub, /* setProperty */
                 ${enumerate}, /* enumerate */
                 ${resolve}, /* resolve */
-                JS_ConvertStub,
+                nullptr,               /* convert */
                 ${finalize}, /* finalize */
                 ${call}, /* call */
                 nullptr,               /* hasInstance */
                 nullptr,               /* construct */
                 ${trace}, /* trace */
                 JS_NULL_CLASS_SPEC,
                 $*{classExtensionAndObjectOps}
               },
@@ -452,17 +452,17 @@ class CGDOMJSClass(CGThing):
             };
             static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
                           "Must have the right minimal number of reserved slots.");
             static_assert(${reservedSlots} >= ${slotCount},
                           "Must have enough reserved slots.");
             """,
             name=self.descriptor.interface.identifier.name,
             flags=classFlags,
-            addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'JS_PropertyStub',
+            addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'nullptr',
             enumerate=enumerateHook,
             resolve=resolveHook,
             finalize=FINALIZE_HOOK_NAME,
             call=callHook,
             trace=traceHook,
             classExtensionAndObjectOps=classExtensionAndObjectOps,
             descriptor=DOMClass(self.descriptor),
             instanceReservedSlots=INSTANCE_RESERVED_SLOTS,
@@ -644,23 +644,23 @@ class CGPrototypeJSClass(CGThing):
         (protoGetter, _) = InterfacePrototypeObjectProtoGetter(self.descriptor)
         type = "eGlobalInterfacePrototype" if self.descriptor.isGlobal() else "eInterfacePrototype"
         return fill(
             """
             static const DOMIfaceAndProtoJSClass PrototypeClass = {
               {
                 "${name}Prototype",
                 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
-                JS_PropertyStub,       /* addProperty */
-                JS_DeletePropertyStub, /* delProperty */
+                nullptr,               /* addProperty */
+                nullptr,               /* delProperty */
                 JS_PropertyStub,       /* getProperty */
                 JS_StrictPropertyStub, /* setProperty */
-                JS_EnumerateStub,
-                JS_ResolveStub,
-                JS_ConvertStub,
+                nullptr,               /* enumerate */
+                nullptr,               /* resolve */
+                nullptr,               /* convert */
                 nullptr,               /* finalize */
                 nullptr,               /* call */
                 nullptr,               /* hasInstance */
                 nullptr,               /* construct */
                 nullptr,               /* trace */
                 JS_NULL_CLASS_SPEC,
                 JS_NULL_CLASS_EXT,
                 JS_NULL_OBJECT_OPS
@@ -740,23 +740,23 @@ class CGInterfaceObjectJSClass(CGThing):
         (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor)
 
         return fill(
             """
             static const DOMIfaceAndProtoJSClass InterfaceObjectClass = {
               {
                 "Function",
                 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
-                JS_PropertyStub,       /* addProperty */
-                JS_DeletePropertyStub, /* delProperty */
+                nullptr,               /* addProperty */
+                nullptr,               /* delProperty */
                 JS_PropertyStub,       /* getProperty */
                 JS_StrictPropertyStub, /* setProperty */
-                JS_EnumerateStub,
-                JS_ResolveStub,
-                JS_ConvertStub,
+                nullptr,               /* enumerate */
+                nullptr,               /* resolve */
+                nullptr,               /* convert */
                 nullptr,               /* finalize */
                 ${ctorname}, /* call */
                 ${hasInstance}, /* hasInstance */
                 ${ctorname}, /* construct */
                 nullptr,               /* trace */
                 JS_NULL_CLASS_SPEC,
                 JS_NULL_CLASS_EXT,
                 JS_NULL_OBJECT_OPS
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -14188,23 +14188,23 @@ CreateIndexOp::DoDatabaseWork(Transactio
   }
 
   return NS_OK;
 }
 
 const JSClass CreateIndexOp::ThreadLocalJSRuntime::kGlobalClass = {
   "IndexedDBTransactionThreadGlobal",
   JSCLASS_GLOBAL_FLAGS,
-  /* addProperty*/ JS_PropertyStub,
-  /* delProperty */ JS_DeletePropertyStub,
+  /* addProperty */ nullptr,
+  /* delProperty */ nullptr,
   /* getProperty */ JS_PropertyStub,
   /* setProperty */ JS_StrictPropertyStub,
-  /* enumerate */ JS_EnumerateStub,
-  /* resolve */ JS_ResolveStub,
-  /* convert */ JS_ConvertStub,
+  /* enumerate */ nullptr,
+  /* resolve */ nullptr,
+  /* convert */ nullptr,
   /* finalize */ nullptr,
   /* call */ nullptr,
   /* hasInstance */ nullptr,
   /* construct */ nullptr,
   /* trace */ JS_GlobalObjectTraceHook
 };
 
 // static
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -838,24 +838,20 @@ ClearStructuredCloneBuffer(JSAutoStructu
   }
 }
 
 } // anonymous namespace
 
 const JSClass IDBObjectStore::sDummyPropJSClass = {
   "IDBObjectStore Dummy",
   0 /* flags */,
-  JS_PropertyStub /* addProperty */,
-  JS_DeletePropertyStub /* delProperty */,
+  nullptr /* addProperty */,
+  nullptr /* delProperty */,
   JS_PropertyStub /* getProperty */,
-  JS_StrictPropertyStub /* setProperty */,
-  JS_EnumerateStub /* enumerate */,
-  JS_ResolveStub /* resolve */,
-  JS_ConvertStub /* convert */,
-  JSCLASS_NO_OPTIONAL_MEMBERS
+  JS_StrictPropertyStub /* setProperty */
 };
 
 IDBObjectStore::IDBObjectStore(IDBTransaction* aTransaction,
                                const ObjectStoreSpec* aSpec)
   : mTransaction(aTransaction)
   , mCachedKeyPath(JSVAL_VOID)
   , mSpec(aSpec)
   , mId(aSpec->metadata().id())
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -224,19 +224,19 @@ static bool
 NPObjectMember_Call(JSContext *cx, unsigned argc, JS::Value *vp);
 
 static void
 NPObjectMember_Trace(JSTracer *trc, JSObject *obj);
 
 static const JSClass sNPObjectMemberClass =
   {
     "NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
-    JS_PropertyStub, JS_DeletePropertyStub,
-    JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub,
-    JS_ResolveStub, NPObjectMember_Convert,
+    nullptr, nullptr,
+    JS_PropertyStub, JS_StrictPropertyStub, nullptr,
+    nullptr, NPObjectMember_Convert,
     NPObjectMember_Finalize, NPObjectMember_Call,
     nullptr, nullptr, NPObjectMember_Trace
   };
 
 static void
 OnWrapperDestroyed();
 
 static void
@@ -1708,26 +1708,26 @@ NPObjWrapper_Resolve(JSContext *cx, JS::
   return true;
 }
 
 static bool
 NPObjWrapper_Convert(JSContext *cx, JS::Handle<JSObject*> obj, JSType hint, JS::MutableHandle<JS::Value> vp)
 {
   MOZ_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
 
-  // Plugins do not simply use JS_ConvertStub, and the default [[DefaultValue]]
-  // behavior, because that behavior involves calling toString or valueOf on
-  // objects which weren't designed to accommodate this.  Usually this wouldn't
-  // be a problem, because the absence of either property, or the presence of
-  // either property with a value that isn't callable, will cause that property
-  // to simply be ignored.  But there is a problem in one specific case: Java,
-  // specifically java.lang.Integer.  The Integer class has static valueOf
-  // methods, none of which are nullary, so the JS-reflected method will behave
-  // poorly when called with no arguments.  We work around this problem by
-  // giving plugins a [[DefaultValue]] which uses only toString and not valueOf.
+  // Plugins do not simply use the default [[DefaultValue]] behavior, because
+  // that behavior involves calling toString or valueOf on objects which
+  // weren't designed to accommodate this.  Usually this wouldn't be a problem,
+  // because the absence of either property, or the presence of either property
+  // with a value that isn't callable, will cause that property to simply be
+  // ignored.  But there is a problem in one specific case: Java, specifically
+  // java.lang.Integer.  The Integer class has static valueOf methods, none of
+  // which are nullary, so the JS-reflected method will behave poorly when
+  // called with no arguments.  We work around this problem by giving plugins a
+  // [[DefaultValue]] which uses only toString and not valueOf.
 
   JS::Rooted<JS::Value> v(cx, JSVAL_VOID);
   if (!JS_GetProperty(cx, obj, "toString", &v))
     return false;
   if (!v.isPrimitive() && JS::IsCallable(v.toObjectOrNull())) {
     if (!JS_CallFunctionValue(cx, obj, v, JS::HandleValueArray::empty(), vp))
       return false;
     if (vp.isPrimitive())
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -87,20 +87,20 @@ XBLEnumerate(JSContext *cx, JS::Handle<J
   return protoBinding->ResolveAllFields(cx, obj);
 }
 
 static const JSClass gPrototypeJSClass = {
     "XBL prototype JSClass",
     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
     // Our one reserved slot holds the relevant nsXBLPrototypeBinding
     JSCLASS_HAS_RESERVED_SLOTS(1),
-    JS_PropertyStub,  JS_DeletePropertyStub,
+    nullptr, nullptr,
     JS_PropertyStub, JS_StrictPropertyStub,
-    XBLEnumerate, JS_ResolveStub,
-    JS_ConvertStub, XBLFinalize,
+    XBLEnumerate, nullptr,
+    nullptr, XBLFinalize,
     nullptr, nullptr, nullptr, nullptr
 };
 
 // Implementation /////////////////////////////////////////////////////////////////
 
 // Constructors/Destructors
 nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
   : mMarkedForDeath(false)
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -934,23 +934,23 @@ AsmJSModuleObject_trace(JSTracer *trc, J
 {
     obj->as<AsmJSModuleObject>().module().trace(trc);
 }
 
 const Class AsmJSModuleObject::class_ = {
     "AsmJSModuleObject",
     JSCLASS_IS_ANONYMOUS | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(AsmJSModuleObject::RESERVED_SLOTS),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    nullptr,                 /* convert     */
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     AsmJSModuleObject_finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     AsmJSModuleObject_trace
 };
 
 AsmJSModuleObject *
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -141,28 +141,20 @@ MSC_FETCHBITOP(uint32_t, long, _Interloc
 
 #elif defined(ENABLE_SHARED_ARRAY_BUFFER)
 # error "Either disable JS shared memory or use a compiler that supports C++11 atomics or GCC/clang atomics"
 #endif
 
 const Class AtomicsObject::class_ = {
     "Atomics",
     JSCLASS_HAS_CACHED_PROTO(JSProto_Atomics),
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    nullptr,                 // addProperty
+    nullptr,                 // delProperty
     JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,                 // finalize
-    nullptr,                 // call
-    nullptr,                 // hasInstance
-    nullptr,                 // construct
-    nullptr                  // trace
+    JS_StrictPropertyStub
 };
 
 static bool
 ReportBadArrayType(JSContext *cx)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ATOMICS_BAD_ARRAY);
     return false;
 }
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -554,23 +554,23 @@ static const size_t INITIAL_CHAR_BUFFER_
 static void collator_finalize(FreeOp *fop, JSObject *obj);
 
 static const uint32_t UCOLLATOR_SLOT = 0;
 static const uint32_t COLLATOR_SLOTS_COUNT = 1;
 
 static const Class CollatorClass = {
     js_Object_str,
     JSCLASS_HAS_RESERVED_SLOTS(COLLATOR_SLOTS_COUNT),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     collator_finalize
 };
 
 #if JS_HAS_TOSOURCE
 static bool
 collator_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1043,23 +1043,23 @@ js::intl_CompareStrings(JSContext *cx, u
 static void numberFormat_finalize(FreeOp *fop, JSObject *obj);
 
 static const uint32_t UNUMBER_FORMAT_SLOT = 0;
 static const uint32_t NUMBER_FORMAT_SLOTS_COUNT = 1;
 
 static const Class NumberFormatClass = {
     js_Object_str,
     JSCLASS_HAS_RESERVED_SLOTS(NUMBER_FORMAT_SLOTS_COUNT),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     numberFormat_finalize
 };
 
 #if JS_HAS_TOSOURCE
 static bool
 numberFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1500,23 +1500,23 @@ js::intl_FormatNumber(JSContext *cx, uns
 static void dateTimeFormat_finalize(FreeOp *fop, JSObject *obj);
 
 static const uint32_t UDATE_FORMAT_SLOT = 0;
 static const uint32_t DATE_TIME_FORMAT_SLOTS_COUNT = 1;
 
 static const Class DateTimeFormatClass = {
     js_Object_str,
     JSCLASS_HAS_RESERVED_SLOTS(DATE_TIME_FORMAT_SLOTS_COUNT),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     dateTimeFormat_finalize
 };
 
 #if JS_HAS_TOSOURCE
 static bool
 dateTimeFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1996,23 +1996,20 @@ js::intl_FormatDateTime(JSContext *cx, u
 }
 
 
 /******************** Intl ********************/
 
 const Class js::IntlClass = {
     js_Object_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Intl),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 #if JS_HAS_TOSOURCE
 static bool
 intl_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setString(cx->names().Intl);
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -862,23 +862,23 @@ class MapIteratorObject : public NativeO
 };
 
 } /* anonymous namespace */
 
 const Class MapIteratorObject::class_ = {
     "Map Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     MapIteratorObject::finalize
 };
 
 const JSFunctionSpec MapIteratorObject::methods[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_FN("next", next, 0, 0),
     JS_FS_END
 };
@@ -1006,23 +1006,23 @@ MapIteratorObject::next(JSContext *cx, u
 
 
 /*** Map *****************************************************************************************/
 
 const Class MapObject::class_ = {
     "Map",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
-    JS_PropertyStub,         // addProperty
-    JS_DeletePropertyStub,   // delProperty
+    nullptr,                 // addProperty
+    nullptr,                 // delProperty
     JS_PropertyStub,         // getProperty
     JS_StrictPropertyStub,   // setProperty
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 // enumerate
+    nullptr,                 // resolve
+    nullptr,                 // convert
     finalize,
     nullptr,                 // call
     nullptr,                 // hasInstance
     nullptr,                 // construct
     mark
 };
 
 const JSPropertySpec MapObject::properties[] = {
@@ -1519,23 +1519,23 @@ class SetIteratorObject : public NativeO
 };
 
 } /* anonymous namespace */
 
 const Class SetIteratorObject::class_ = {
     "Set Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     SetIteratorObject::finalize
 };
 
 const JSFunctionSpec SetIteratorObject::methods[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_FN("next", next, 0, 0),
     JS_FS_END
 };
@@ -1659,23 +1659,23 @@ SetIteratorObject::next(JSContext *cx, u
 
 
 /*** Set *****************************************************************************************/
 
 const Class SetObject::class_ = {
     "Set",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Set),
-    JS_PropertyStub,         // addProperty
-    JS_DeletePropertyStub,   // delProperty
+    nullptr,                 // addProperty
+    nullptr,                 // delProperty
     JS_PropertyStub,         // getProperty
     JS_StrictPropertyStub,   // setProperty
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 // enumerate
+    nullptr,                 // resolve
+    nullptr,                 // convert
     finalize,
     nullptr,                 // call
     nullptr,                 // hasInstance
     nullptr,                 // construct
     mark
 };
 
 const JSPropertySpec SetObject::properties[] = {
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -163,27 +163,27 @@ static bool type##SignMask(JSContext *cx
 }
     SIGN_MASK(Float32x4);
     SIGN_MASK(Int32x4);
 #undef SIGN_MASK
 
 const Class SimdTypeDescr::class_ = {
     "SIMD",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,             /* finalize    */
-    call,                /* call        */
-    nullptr,             /* hasInstance */
-    nullptr,             /* construct   */
+    nullptr,                 /* enumerate   */
+    nullptr,                 /* resolve     */
+    nullptr,                 /* convert     */
+    nullptr,                 /* finalize    */
+    call,                    /* call        */
+    nullptr,                 /* hasInstance */
+    nullptr,                 /* construct   */
     nullptr
 };
 
 // These classes just exist to group together various properties and so on.
 namespace js {
 class Int32x4Defn {
   public:
     static const SimdTypeDescr::Type type = SimdTypeDescr::TYPE_INT32;
@@ -347,30 +347,22 @@ SimdTypeDescr::call(JSContext *cx, unsig
     args.rval().setObject(*result);
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // SIMD class
 
 const Class SIMDObject::class_ = {
-        "SIMD",
-        JSCLASS_HAS_CACHED_PROTO(JSProto_SIMD),
-        JS_PropertyStub,         /* addProperty */
-        JS_DeletePropertyStub,   /* delProperty */
-        JS_PropertyStub,         /* getProperty */
-        JS_StrictPropertyStub,   /* setProperty */
-        JS_EnumerateStub,
-        JS_ResolveStub,
-        JS_ConvertStub,
-        nullptr,             /* finalize    */
-        nullptr,             /* call        */
-        nullptr,             /* hasInstance */
-        nullptr,             /* construct   */
-        nullptr
+    "SIMD",
+    JSCLASS_HAS_CACHED_PROTO(JSProto_SIMD),
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 JSObject *
 SIMDObject::initClass(JSContext *cx, Handle<GlobalObject *> global)
 {
     // SIMD relies on having the TypedObject module initialized.
     // In particular, the self-hosted code for array() wants
     // to be able to call GetTypedObjectModule(). It is NOT necessary
--- a/js/src/builtin/SymbolObject.cpp
+++ b/js/src/builtin/SymbolObject.cpp
@@ -14,22 +14,22 @@
 #include "vm/Symbol-inl.h"
 
 using JS::Symbol;
 using namespace js;
 
 const Class SymbolObject::class_ = {
     "Symbol",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Symbol),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
     convert
 };
 
 SymbolObject *
 SymbolObject::create(JSContext *cx, JS::Symbol *symbol)
 {
     JSObject *obj = NewBuiltinClassInstance(cx, &class_);
     if (!obj)
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -954,23 +954,20 @@ OOMAfterAllocations(JSContext *cx, unsig
 
     OOM_maxAllocations = OOM_counter + count;
     return true;
 }
 #endif
 
 static const js::Class FakePromiseClass = {
     "Promise", JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,       /* getProperty */
-    JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub  /* setProperty */
 };
 
 static bool
 MakeFakePromise(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject scope(cx, cx->global());
     if (!scope)
@@ -1006,23 +1003,23 @@ static unsigned finalizeCount = 0;
 static void
 finalize_counter_finalize(JSFreeOp *fop, JSObject *obj)
 {
     ++finalizeCount;
 }
 
 static const JSClass FinalizeCounterClass = {
     "FinalizeCounter", JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,               /* enumerate */
+    nullptr,               /* resolve */
+    nullptr,               /* convert */
     finalize_counter_finalize
 };
 
 static bool
 MakeFinalizeObserver(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject scope(cx, JS::CurrentGlobalOrNull(cx));
@@ -1548,23 +1545,23 @@ class CloneBufferObject : public NativeO
 
     static void Finalize(FreeOp *fop, JSObject *obj) {
         obj->as<CloneBufferObject>().discard();
     }
 };
 
 const Class CloneBufferObject::class_ = {
     "CloneBuffer", JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,               /* enumerate */
+    nullptr,               /* resolve */
+    nullptr,               /* convert */
     Finalize,
     nullptr,                  /* call */
     nullptr,                  /* hasInstance */
     nullptr,                  /* construct */
     nullptr,                  /* trace */
     JS_NULL_CLASS_SPEC,
     JS_NULL_CLASS_EXT,
     JS_NULL_OBJECT_OPS
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -31,23 +31,20 @@ using mozilla::CheckedInt32;
 using mozilla::DebugOnly;
 
 using namespace js;
 
 const Class js::TypedObjectModuleObject::class_ = {
     "TypedObject",
     JSCLASS_HAS_RESERVED_SLOTS(SlotCount) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_TypedObject),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 static const JSFunctionSpec TypedObjectMethods[] = {
     JS_SELF_HOSTED_FN("objectType", "TypeOfTypedObject", 1, 0),
     JS_SELF_HOSTED_FN("storage", "StorageOfTypedObject", 1, 0),
     JS_FS_END
 };
 
@@ -204,54 +201,43 @@ GetPrototype(JSContext *cx, HandleObject
  * Every type descriptor has an associated prototype. Instances of
  * that type descriptor use this as their prototype. Per the spec,
  * typed object prototypes cannot be mutated.
  */
 
 const Class js::TypedProto::class_ = {
     "TypedProto",
     JSCLASS_HAS_RESERVED_SLOTS(JS_TYPROTO_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,       /* getProperty */
-    JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr
+    JS_StrictPropertyStub  /* setProperty */
 };
 
 /***************************************************************************
  * Scalar type objects
  *
  * Scalar type objects like `uint8`, `uint16`, are all instances of
  * the ScalarTypeDescr class. Like all type objects, they have a reserved
  * slot pointing to a TypeRepresentation object, which is used to
  * distinguish which scalar type object this actually is.
  */
 
 const Class js::ScalarTypeDescr::class_ = {
     "Scalar",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
-    ScalarTypeDescr::call,
-    nullptr,
-    nullptr,
-    nullptr
+    nullptr,               /* enumerate */
+    nullptr,               /* resolve */
+    nullptr,               /* convert */
+    nullptr,               /* finalize */
+    ScalarTypeDescr::call
 };
 
 const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_FS_END
 };
@@ -326,28 +312,25 @@ ScalarTypeDescr::call(JSContext *cx, uns
  * many instances, and each instance has a reserved slot with a
  * TypeRepresentation object, which is used to distinguish which
  * reference type object this actually is.
  */
 
 const Class js::ReferenceTypeDescr::class_ = {
     "Reference",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
-    ReferenceTypeDescr::call,
-    nullptr,
-    nullptr,
-    nullptr
+    nullptr,               /* enumerate */
+    nullptr,               /* resolve */
+    nullptr,               /* convert */
+    nullptr,               /* finalize */
+    ReferenceTypeDescr::call
 };
 
 const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = {
     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_FS_END
 };
@@ -508,24 +491,24 @@ CreatePrototypeObjectForComplexTypeInsta
 
     result->initTypeDescrSlot(*descr);
     return result;
 }
 
 const Class ArrayTypeDescr::class_ = {
     "ArrayType",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,
     JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
+    nullptr,               /* enumerate */
+    nullptr,               /* resolve */
+    nullptr,               /* convert */
+    nullptr,               /* finalize */
     nullptr,
     nullptr,
     TypedObject::construct,
     nullptr
 };
 
 const JSPropertySpec ArrayMetaTypeDescr::typeObjectProperties[] = {
     JS_PS_END
@@ -736,23 +719,23 @@ js::IsTypedObjectArray(JSObject &obj)
 
 /*********************************
  * StructType class
  */
 
 const Class StructTypeDescr::class_ = {
     "StructType",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    nullptr, /* addProperty */
+    nullptr, /* delProperty */
     JS_PropertyStub,
     JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr, /* enumerate */
+    nullptr, /* resolve */
+    nullptr, /* convert */
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     TypedObject::construct,
     nullptr  /* trace */
 };
 
 const JSPropertySpec StructMetaTypeDescr::typeObjectProperties[] = {
@@ -2415,23 +2398,23 @@ LazyArrayBufferTable::sizeOfIncludingThi
 /******************************************************************************
  * Typed object classes
  */
 
 #define DEFINE_TYPEDOBJ_CLASS(Name, Trace)        \
     const Class Name::class_ = {                         \
         # Name,                                          \
         Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS, \
-        JS_PropertyStub,                                 \
-        JS_DeletePropertyStub,                           \
+        nullptr,        /* addProperty */                \
+        nullptr,        /* delProperty */                \
         JS_PropertyStub,                                 \
         JS_StrictPropertyStub,                           \
-        JS_EnumerateStub,                                \
-        JS_ResolveStub,                                  \
-        JS_ConvertStub,                                  \
+        nullptr,        /* enumerate   */                \
+        nullptr,        /* resolve     */                \
+        nullptr,        /* convert     */                \
         nullptr,        /* finalize    */                \
         nullptr,        /* call        */                \
         nullptr,        /* hasInstance */                \
         nullptr,        /* construct   */                \
         Trace,                                           \
         JS_NULL_CLASS_SPEC,                              \
         JS_NULL_CLASS_EXT,                               \
         {                                                \
@@ -3199,9 +3182,8 @@ TypeDescr::traceInstances(JSTracer *trac
 {
     MemoryTracingVisitor visitor(trace);
 
     for (size_t i = 0; i < length; i++) {
         visitReferences(*this, mem, visitor);
         mem += size();
     }
 }
-
--- a/js/src/builtin/WeakSetObject.cpp
+++ b/js/src/builtin/WeakSetObject.cpp
@@ -18,23 +18,20 @@
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 
 const Class WeakSetObject::class_ = {
     "WeakSet",
     JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet) |
     JSCLASS_HAS_RESERVED_SLOTS(WeakSetObject::RESERVED_SLOTS),
-    JS_PropertyStub,         // addProperty
-    JS_DeletePropertyStub,   // delProperty
+    nullptr,                 // addProperty
+    nullptr,                 // delProperty
     JS_PropertyStub,         // getProperty
-    JS_StrictPropertyStub,   // setProperty
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    // setProperty
 };
 
 const JSPropertySpec WeakSetObject::properties[] = {
     JS_PS_END
 };
 
 const JSFunctionSpec WeakSetObject::methods[] = {
     JS_SELF_HOSTED_FN("add",    "WeakSet_add",    1, 0),
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -509,93 +509,89 @@ namespace UInt64 {
 ** JSClass definitions and initialization functions
 *******************************************************************************/
 
 // Class representing the 'ctypes' object itself. This exists to contain the
 // JSCTypesCallbacks set of function pointers.
 static const JSClass sCTypesGlobalClass = {
   "ctypes",
   JSCLASS_HAS_RESERVED_SLOTS(CTYPESGLOBAL_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 static const JSClass sCABIClass = {
   "CABI",
   JSCLASS_HAS_RESERVED_SLOTS(CABI_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 // Class representing ctypes.{C,Pointer,Array,Struct,Function}Type.prototype.
 // This exists to give said prototypes a class of "CType", and to provide
 // reserved slots for stashing various other prototype objects.
 static const JSClass sCTypeProtoClass = {
   "CType",
   JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+  nullptr, nullptr, nullptr, nullptr,
   ConstructAbstract, nullptr, ConstructAbstract
 };
 
 // Class representing ctypes.CData.prototype and the 'prototype' properties
 // of CTypes. This exists to give said prototypes a class of "CData".
 static const JSClass sCDataProtoClass = {
   "CData",
   0,
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 static const JSClass sCTypeClass = {
   "CType",
   JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::Finalize,
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+  nullptr, nullptr, nullptr, CType::Finalize,
   CType::ConstructData, CType::HasInstance, CType::ConstructData,
   CType::Trace
 };
 
 static const JSClass sCDataClass = {
   "CData",
   JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, ArrayType::Getter, ArrayType::Setter,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CData::Finalize,
+  nullptr, nullptr, ArrayType::Getter, ArrayType::Setter,
+  nullptr, nullptr, nullptr, CData::Finalize,
   FunctionType::Call, nullptr, FunctionType::Call
 };
 
 static const JSClass sCClosureClass = {
   "CClosure",
   JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CClosure::Finalize,
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+  nullptr, nullptr, nullptr, CClosure::Finalize,
   nullptr, nullptr, nullptr, CClosure::Trace
 };
 
 /*
  * Class representing the prototype of CDataFinalizer.
  */
 static const JSClass sCDataFinalizerProtoClass = {
   "CDataFinalizer",
   0,
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 /*
  * Class representing instances of CDataFinalizer.
  *
  * Instances of CDataFinalizer have both private data (with type
  * |CDataFinalizer::Private|) and slots (see |CDataFinalizerSlots|).
  */
 static const JSClass sCDataFinalizerClass = {
   "CDataFinalizer",
   JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CDataFinalizer::Finalize,
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+  nullptr, nullptr, nullptr, CDataFinalizer::Finalize,
 };
 
 
 #define CTYPESFN_FLAGS \
   (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
 
 #define CTYPESCTOR_FLAGS \
   (CTYPESFN_FLAGS | JSFUN_CONSTRUCTOR)
@@ -760,39 +756,37 @@ static const JSFunctionSpec sFunctionIns
   JS_FN("call", js_fun_call, 1, CDATAFN_FLAGS),
   JS_FN("apply", js_fun_apply, 2, CDATAFN_FLAGS),
   JS_FS_END
 };
 
 static const JSClass sInt64ProtoClass = {
   "Int64",
   0,
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 static const JSClass sUInt64ProtoClass = {
   "UInt64",
   0,
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 static const JSClass sInt64Class = {
   "Int64",
   JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+  nullptr, nullptr, nullptr, Int64Base::Finalize
 };
 
 static const JSClass sUInt64Class = {
   "UInt64",
   JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+  nullptr, nullptr, nullptr, Int64Base::Finalize
 };
 
 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),
   JS_FN("join", Int64::Join, 2, CTYPESFN_FLAGS),
   JS_FS_END
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -29,18 +29,18 @@ namespace Library
 ** JSObject implementation
 *******************************************************************************/
 
 typedef Rooted<JSFlatString*>    RootedFlatString;
 
 static const JSClass sLibraryClass = {
   "Library",
   JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS),
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, Library::Finalize
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+  nullptr, nullptr, nullptr, Library::Finalize
 };
 
 #define CTYPESFN_FLAGS \
   (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
 
 static const JSFunctionSpec sLibraryFunctions[] = {
   JS_FN("close",   Library::Close,   0, CTYPESFN_FLAGS),
   JS_FN("declare", Library::Declare, 0, CTYPESFN_FLAGS),
--- a/js/src/gdb/gdb-tests.cpp
+++ b/js/src/gdb/gdb-tests.cpp
@@ -10,19 +10,19 @@
 #include "jsapi.h"
 #include "jsfriendapi.h"
 
 using namespace JS;
 
 /* The class of the global object. */
 const JSClass global_class = {
     "global", JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub,  JS_DeletePropertyStub, JS_PropertyStub,  JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
     nullptr, nullptr, nullptr, nullptr,
+    nullptr, nullptr, nullptr,
     JS_GlobalObjectTraceHook
 };
 
 template<typename T>
 static inline T *
 checkPtr(T *ptr)
 {
   if (! ptr)
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3359,17 +3359,17 @@ CheckHasNoSuchProperty(JSContext *cx, Ha
 
     size_t depth = 0;
     RootedObject curObj(cx, obj);
     while (curObj) {
         if (!curObj->isNative())
             return false;
 
         // Don't handle proto chains with resolve hooks.
-        if (curObj->getClass()->resolve != JS_ResolveStub)
+        if (curObj->getClass()->resolve)
             return false;
 
         Shape *shape = curObj->as<NativeObject>().lookup(cx, NameToId(name));
         if (shape)
             return false;
 
         JSObject *proto = curObj->getTaggedProto().toObjectOrNull();
         if (!proto)
@@ -3510,18 +3510,18 @@ IsCacheableSetPropAddSlot(JSContext *cx,
 
     // Basic shape checks.
     if (shape->inDictionary() || !shape->hasSlot() || !shape->hasDefaultSetter() ||
         !shape->writable())
     {
         return false;
     }
 
-    // If object has a non-default resolve hook, don't inline
-    if (obj->getClass()->resolve != JS_ResolveStub)
+    // If object has a resolve hook, don't inline
+    if (obj->getClass()->resolve)
         return false;
 
     size_t chainDepth = 0;
     // walk up the object prototype chain and ensure that all prototypes
     // are native, and that all prototypes have setter defined on the property
     for (JSObject *proto = obj->getProto(); proto; proto = proto->getProto()) {
         chainDepth++;
         // if prototype is non-native, don't optimize
@@ -3530,17 +3530,17 @@ IsCacheableSetPropAddSlot(JSContext *cx,
 
         // if prototype defines this property in a non-plain way, don't optimize
         Shape *protoShape = proto->as<NativeObject>().lookup(cx, id);
         if (protoShape && !protoShape->hasDefaultSetter())
             return false;
 
         // Otherise, if there's no such property, watch out for a resolve hook that would need
         // to be invoked and thus prevent inlining of property addition.
-        if (proto->getClass()->resolve != JS_ResolveStub)
+        if (proto->getClass()->resolve)
              return false;
     }
 
     // Only add a IC entry if the dynamic slots didn't change when the shapes
     // changed.  Need to ensure that a shape change for a subsequent object
     // won't involve reallocating the slot array.
     if (obj->as<NativeObject>().numDynamicSlots() != oldSlots)
         return false;
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6551,17 +6551,17 @@ static bool
 ClassHasResolveHook(CompileCompartment *comp, const Class *clasp, PropertyName *name)
 {
     // While arrays do not have resolve hooks, the types of their |length|
     // properties are not reflected in type information, so pretend there is a
     // resolve hook for this property.
     if (clasp == &ArrayObject::class_)
         return name == comp->runtime()->names().length;
 
-    if (clasp->resolve == JS_ResolveStub)
+    if (!clasp->resolve)
         return false;
 
     if (clasp->resolve == str_resolve) {
         // str_resolve only resolves integers, not names.
         return false;
     }
 
     if (clasp->resolve == fun_resolve)
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -2726,23 +2726,22 @@ IsPropertyAddInlineable(NativeObject *ob
     Shape *shape = obj->lookupPure(id);
     if (!shape || shape->inDictionary() || !shape->hasSlot() || !shape->hasDefaultSetter())
         return false;
 
     // If we have a shape at this point and the object's shape changed, then
     // the shape must be the one we just added.
     MOZ_ASSERT(shape == obj->lastProperty());
 
-    // If object has a non-default resolve hook, don't inline
-    if (obj->getClass()->resolve != JS_ResolveStub)
+    // If object has a resolve hook, don't inline
+    if (obj->getClass()->resolve)
         return false;
 
-    // Likewise for a non-default addProperty hook, since we'll need
-    // to invoke it.
-    if (obj->getClass()->addProperty != JS_PropertyStub)
+    // Likewise for an addProperty hook, since we'll need to invoke it.
+    if (obj->getClass()->addProperty)
         return false;
 
     if (!obj->nonProxyIsExtensible() || !shape->writable())
         return false;
 
     // Walk up the object prototype chain and ensure that all prototypes
     // are native, and that all prototypes have no getter or setter
     // defined on the property
@@ -2754,17 +2753,17 @@ IsPropertyAddInlineable(NativeObject *ob
         // If prototype defines this property in a non-plain way, don't optimize
         Shape *protoShape = proto->as<NativeObject>().lookupPure(id);
         if (protoShape && !protoShape->hasDefaultSetter())
             return false;
 
         // Otherwise, if there's no such property, watch out for a resolve
         // hook that would need to be invoked and thus prevent inlining of
         // property addition.
-        if (proto->getClass()->resolve != JS_ResolveStub)
+        if (proto->getClass()->resolve)
              return false;
     }
 
     // Only add a IC entry if the dynamic slots didn't change when the shapes
     // changed.  Need to ensure that a shape change for a subsequent object
     // won't involve reallocating the slot array.
     if (obj->numDynamicSlots() != oldSlots)
         return false;
--- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp
+++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp
@@ -15,22 +15,19 @@ AddProperty(JSContext *cx, JS::HandleObj
     callCount++;
     return true;
 }
 
 static const JSClass AddPropertyClass = {
     "AddPropertyTester",
     0,
     AddProperty,
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 BEGIN_TEST(testAddPropertyHook)
 {
     /*
      * Do the test a bunch of times, because sometimes we seem to randomly
      * miss the propcache.
      */
--- a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
+++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
@@ -4,23 +4,20 @@
 
 #include "jsapi-tests/tests.h"
 
 using namespace JS;
 
 static const JSClass CustomClass = {
   "CustomClass",
   JSCLASS_HAS_RESERVED_SLOTS(1),
-  JS_PropertyStub,
-  JS_DeletePropertyStub,
+  nullptr,
+  nullptr,
   JS_PropertyStub,
-  JS_StrictPropertyStub,
-  JS_EnumerateStub,
-  JS_ResolveStub,
-  JS_ConvertStub
+  JS_StrictPropertyStub
 };
 
 static const uint32_t CUSTOM_SLOT = 0;
 
 static bool
 IsCustomClass(JS::Handle<JS::Value> v)
 {
   return v.isObject() && JS_GetClass(&v.toObject()) == &CustomClass;
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -6,23 +6,23 @@
 
 #include "jsapi-tests/tests.h"
 
 static TestJSPrincipals system_principals(1);
 
 static const JSClass global_class = {
     "global",
     JSCLASS_IS_GLOBAL | JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    nullptr,
+    nullptr,
     JS_PropertyStub,
     JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,
+    nullptr,
+    nullptr,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     JS_GlobalObjectTraceHook
 };
 
 static JS::Heap<JSObject *> trusted_glob;
--- a/js/src/jsapi-tests/testClassGetter.cpp
+++ b/js/src/jsapi-tests/testClassGetter.cpp
@@ -20,23 +20,20 @@ static bool test_prop_get( JSContext *cx
 
 static bool
 PTest(JSContext* cx, unsigned argc, jsval *vp);
 
 static const JSClass ptestClass = {
     "PTest",
     JSCLASS_HAS_PRIVATE,
 
-    JS_PropertyStub,       // add
-    JS_DeletePropertyStub, // delete
+    nullptr,               // add
+    nullptr,               // delete
     test_prop_get,         // get
-    JS_StrictPropertyStub, // set
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub  // set
 };
 
 static bool
 PTest(JSContext* cx, unsigned argc, jsval *vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     JSObject *obj = JS_NewObjectForConstructor(cx, &ptestClass, args);
     if (!obj)
--- a/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
+++ b/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
@@ -18,18 +18,18 @@ GlobalResolve(JSContext *cx, JS::HandleO
 {
     return JS_ResolveStandardClass(cx, obj, id, resolvedp);
 }
 
 BEGIN_TEST(testRedefineGlobalEval)
 {
     static const JSClass cls = {
         "global", JSCLASS_GLOBAL_FLAGS,
-        JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-        GlobalEnumerate, GlobalResolve, JS_ConvertStub,
+        nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+        GlobalEnumerate, GlobalResolve, nullptr,
         nullptr, nullptr, nullptr, nullptr,
         JS_GlobalObjectTraceHook
     };
 
     /* Create the global object. */
     JS::CompartmentOptions options;
     options.setVersion(JSVERSION_LATEST);
     JS::Rooted<JSObject*> g(cx, JS_NewGlobalObject(cx, &cls, nullptr, JS::FireOnNewGlobalHook, options));
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -35,23 +35,20 @@ BEGIN_TEST(testLookup_bug522590)
 
     return true;
 }
 END_TEST(testLookup_bug522590)
 
 static const JSClass DocumentAllClass = {
     "DocumentAll",
     JSCLASS_EMULATES_UNDEFINED,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    nullptr,
+    nullptr,
     JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub
 };
 
 bool
 document_resolve(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *resolvedp)
 {
     // If id is "all", resolve document.all=true.
     JS::RootedValue v(cx);
     if (!JS_IdToValue(cx, id, &v))
@@ -78,18 +75,18 @@ document_resolve(JSContext *cx, JS::Hand
     }
 
     *resolvedp = false;
     return true;
 }
 
 static const JSClass document_class = {
     "document", 0,
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, document_resolve, JS_ConvertStub
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, document_resolve, nullptr
 };
 
 BEGIN_TEST(testLookup_bug570195)
 {
     JS::RootedObject obj(cx, JS_NewObject(cx, &document_class, JS::NullPtr(), JS::NullPtr()));
     CHECK(obj);
     CHECK(JS_DefineProperty(cx, global, "document", obj, 0));
     JS::RootedValue v(cx);
--- a/js/src/jsapi-tests/testNewObject.cpp
+++ b/js/src/jsapi-tests/testNewObject.cpp
@@ -91,18 +91,18 @@ BEGIN_TEST(testNewObject_1)
     CHECK_EQUAL(len, N);
     CHECK(JS_GetElement(cx, obj, N - 1, &v));
     CHECK_SAME(v, INT_TO_JSVAL(N - 1));
 
     // With JSClass.construct.
     static const JSClass cls = {
         "testNewObject_1",
         0,
-        JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-        JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
+        nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+        nullptr, nullptr, nullptr, nullptr,
         nullptr, nullptr, constructHook
     };
     JS::RootedObject ctor(cx, JS_NewObject(cx, &cls, JS::NullPtr(), JS::NullPtr()));
     CHECK(ctor);
     JS::RootedValue rt2(cx, OBJECT_TO_JSVAL(ctor));
     obj = JS_New(cx, ctor, JS::HandleValueArray::subarray(argv, 0, 3));
     CHECK(obj);
     CHECK(JS_GetElement(cx, ctor, 0, &v));
--- a/js/src/jsapi-tests/testObjectEmulatingUndefined.cpp
+++ b/js/src/jsapi-tests/testObjectEmulatingUndefined.cpp
@@ -2,23 +2,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsapi-tests/tests.h"
 
 static const JSClass ObjectEmulatingUndefinedClass = {
     "ObjectEmulatingUndefined",
     JSCLASS_EMULATES_UNDEFINED,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    nullptr,
+    nullptr,
     JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub
 };
 
 static bool
 ObjectEmulatingUndefinedConstructor(JSContext *cx, unsigned argc, jsval *vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     JSObject *obj = JS_NewObjectForConstructor(cx, &ObjectEmulatingUndefinedClass, args);
     if (!obj)
--- a/js/src/jsapi-tests/testOps.cpp
+++ b/js/src/jsapi-tests/testOps.cpp
@@ -17,18 +17,18 @@ my_convert(JSContext* context, JS::Handl
         return true;
     }
     return false;
 }
 
 static const JSClass myClass = {
     "MyClass",
     0,
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, my_convert
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, my_convert
 };
 
 static bool
 createMyObject(JSContext* context, unsigned argc, jsval *vp)
 {
     JS_BeginRequest(context);
 
     //JS_GC(context); //<- if we make GC here, all is ok
--- a/js/src/jsapi-tests/testPersistentRooted.cpp
+++ b/js/src/jsapi-tests/testPersistentRooted.cpp
@@ -17,23 +17,23 @@ struct BarkWhenTracedClass {
     static void reset() { finalizeCount = 0; traceCount = 0; }
 };
 
 int BarkWhenTracedClass::finalizeCount;
 int BarkWhenTracedClass::traceCount;
 
 const JSClass BarkWhenTracedClass::class_ = {
   "BarkWhenTracedClass", 0,
-  JS_PropertyStub,
-  JS_DeletePropertyStub,
+  nullptr,
+  nullptr,
   JS_PropertyStub,
   JS_StrictPropertyStub,
-  JS_EnumerateStub,
-  JS_ResolveStub,
-  JS_ConvertStub,
+  nullptr,
+  nullptr,
+  nullptr,
   finalize,
   nullptr,
   nullptr,
   nullptr,
   trace
 };
 
 struct Kennel {
--- a/js/src/jsapi-tests/testProfileStrings.cpp
+++ b/js/src/jsapi-tests/testProfileStrings.cpp
@@ -21,18 +21,17 @@ reset(JSContext *cx)
     psize = max_stack = 0;
     memset(pstack, 0, sizeof(pstack));
     cx->runtime()->spsProfiler.stringsReset();
     cx->runtime()->spsProfiler.enableSlowAssertions(true);
     js::EnableRuntimeProfilingStack(cx->runtime(), true);
 }
 
 static const JSClass ptestClass = {
-    "Prof", 0, JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub,
-    JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+    "Prof", 0, nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 static bool
 test_fn(JSContext *cx, unsigned argc, jsval *vp)
 {
     max_stack = psize;
     return true;
 }
--- a/js/src/jsapi-tests/testPropCache.cpp
+++ b/js/src/jsapi-tests/testPropCache.cpp
@@ -14,18 +14,17 @@ CounterAdd(JSContext *cx, JS::HandleObje
 {
     g_counter++;
     return true;
 }
 
 static const JSClass CounterClass = {
     "Counter",  /* name */
     0,  /* flags */
-    CounterAdd, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+    CounterAdd, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 BEGIN_TEST(testPropCache_bug505798)
 {
     g_counter = 0;
     EXEC("var x = {};");
     CHECK(JS_DefineObject(cx, global, "y", &CounterClass, JS::NullPtr(), JSPROP_ENUMERATE));
     EXEC("var arr = [x, y];\n"
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -12,23 +12,22 @@
  * prevented.
  */
 
 BEGIN_TEST(testResolveRecursion)
 {
     static const JSClass my_resolve_class = {
         "MyResolve",
         JSCLASS_HAS_PRIVATE,
-        JS_PropertyStub,       // add
-        JS_DeletePropertyStub, // delete
+        nullptr,               // add
+        nullptr,               // delete
         JS_PropertyStub,       // get
         JS_StrictPropertyStub, // set
-        JS_EnumerateStub,
-        my_resolve,
-        JS_ConvertStub
+        nullptr,
+        my_resolve
     };
 
     obj1 = obj2 = nullptr;
     JS::AddObjectRoot(cx, &obj1);
     JS::AddObjectRoot(cx, &obj2);
 
     obj1 = JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr());
     CHECK(obj1);
--- a/js/src/jsapi-tests/testSetProperty.cpp
+++ b/js/src/jsapi-tests/testSetProperty.cpp
@@ -63,17 +63,17 @@ NativeGet(JSContext *cx, JS::HandleObjec
 }
 END_TEST(testSetProperty_NativeGetterStubSetter)
 
 BEGIN_TEST(testSetProperty_InheritedGlobalSetter)
 {
     // This is a JSAPI test because jsapi-test globals do not have a resolve
     // hook and therefore can use the property cache in some cases where the
     // shell can't.
-    MOZ_ASSERT(JS_GetClass(global)->resolve == &JS_ResolveStub);
+    MOZ_ASSERT(!JS_GetClass(global)->resolve);
 
     CHECK(JS_DefineProperty(cx, global, "HOTLOOP", 8, 0));
     EXEC("var n = 0;\n"
          "var global = this;\n"
          "function f() { n++; }\n"
          "Object.defineProperty(Object.prototype, 'x', {set: f});\n"
          "for (var i = 0; i < HOTLOOP; i++)\n"
          "    global.x = i;\n");
--- a/js/src/jsapi-tests/testWeakMap.cpp
+++ b/js/src/jsapi-tests/testWeakMap.cpp
@@ -133,24 +133,24 @@ static JSObject *GetKeyDelegate(JSObject
     return static_cast<JSObject*>(JS_GetPrivate(obj));
 }
 
 JSObject *newKey()
 {
     static const js::Class keyClass = {
         "keyWithDelgate",
         JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
-        JS_PropertyStub,         /* addProperty */
-        JS_DeletePropertyStub,   /* delProperty */
+        nullptr,                 /* addProperty */
+        nullptr,                 /* delProperty */
         JS_PropertyStub,         /* getProperty */
         JS_StrictPropertyStub,   /* setProperty */
-        JS_EnumerateStub,
-        JS_ResolveStub,
-        JS_ConvertStub,
-        nullptr,
+        nullptr,                 /* enumerate */
+        nullptr,                 /* resolve */
+        nullptr,                 /* convert */
+        nullptr,                 /* finalize */
         nullptr,
         nullptr,
         nullptr,
         nullptr,
         JS_NULL_CLASS_SPEC,
         {
             nullptr,
             nullptr,
@@ -195,24 +195,24 @@ JSObject *newCCW(JS::HandleObject source
     return object;
 }
 
 JSObject *newDelegate()
 {
     static const JSClass delegateClass = {
         "delegate",
         JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_RESERVED_SLOTS(1),
-        JS_PropertyStub,
-        JS_DeletePropertyStub,
+        nullptr,                 /* addProperty */
+        nullptr,                 /* delProperty */
         JS_PropertyStub,
         JS_StrictPropertyStub,
-        JS_EnumerateStub,
-        JS_ResolveStub,
-        JS_ConvertStub,
-        nullptr,
+        nullptr,                 /* enumerate */
+        nullptr,                 /* resolve */
+        nullptr,                 /* convert */
+        nullptr,                 /* finalize */
         nullptr,
         nullptr,
         nullptr,
         JS_GlobalObjectTraceHook
     };
 
     /* Create the global object. */
     JS::CompartmentOptions options;
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -223,18 +223,18 @@ class JSAPITest
         return false;
     }
 
     JSAPITestString messages() const { return msgs; }
 
     static const JSClass * basicGlobalClass() {
         static const JSClass c = {
             "global", JSCLASS_GLOBAL_FLAGS,
-            JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-            JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
+            nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+            nullptr, nullptr, nullptr, nullptr,
             nullptr, nullptr, nullptr,
             JS_GlobalObjectTraceHook
         };
         return &c;
     }
 
   protected:
     static bool
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2139,37 +2139,17 @@ JS_PropertyStub(JSContext *cx, HandleObj
 
 JS_PUBLIC_API(bool)
 JS_StrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
 {
     return true;
 }
 
 JS_PUBLIC_API(bool)
-JS_DeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
-{
-    *succeeded = true;
-    return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_EnumerateStub(JSContext *cx, HandleObject obj)
-{
-    return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_ResolveStub(JSContext *cx, HandleObject obj, HandleId id, bool *resolvedp)
-{
-    MOZ_ASSERT(*resolvedp == false);
-    return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_ConvertStub(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp)
+JS::OrdinaryToPrimitive(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp)
 {
     MOZ_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
     MOZ_ASSERT(obj);
     return DefaultValue(cx, obj, type, vp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_InitClass(JSContext *cx, HandleObject obj, HandleObject parent_proto,
@@ -2814,17 +2794,16 @@ DefinePropertyById(JSContext *cx, Handle
     // But skip doing this if our accessors are the well-known stub
     // accessors, since those are known to be JSPropertyOps.  Assert
     // some sanity about it, though.
     MOZ_ASSERT_IF(getter == JS_PropertyStub,
                   setter == JS_StrictPropertyStub || (attrs & JSPROP_PROPOP_ACCESSORS));
     MOZ_ASSERT_IF(setter == JS_StrictPropertyStub,
                   getter == JS_PropertyStub || (attrs & JSPROP_PROPOP_ACCESSORS));
 
-
     // If !(attrs & JSPROP_PROPOP_ACCESSORS), then either getter/setter are both
     // possibly-null JSNatives (or possibly-null JSFunction* if JSPROP_GETTER or
     // JSPROP_SETTER is appropriately set), or both are the well-known property
     // stubs.  The subsequent block must handle only the first of these cases,
     // so carefully exclude the latter case.
     if (!(attrs & JSPROP_PROPOP_ACCESSORS) &&
         getter != JS_PropertyStub && setter != JS_StrictPropertyStub)
     {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1154,16 +1154,27 @@ ToBoolean(HandleValue v)
 MOZ_ALWAYS_INLINE JSString*
 ToString(JSContext *cx, HandleValue v)
 {
     if (v.isString())
         return v.toString();
     return js::ToStringSlow(cx, v);
 }
 
+/*
+ * Implements ES6 draft rev 28 (2014 Oct 14) 7.1.1, second algorithm.
+ *
+ * Most users should not call this -- use JS::ToNumber, ToBoolean, or ToString
+ * instead. This should only be called from custom convert hooks. It implements
+ * the default conversion behavior shared by most objects in JS, so it's useful
+ * as a fallback.
+ */
+extern JS_PUBLIC_API(bool)
+OrdinaryToPrimitive(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp);
+
 } /* namespace JS */
 
 extern JS_PUBLIC_API(bool)
 JS_DoubleIsInt32(double d, int32_t *ip);
 
 extern JS_PUBLIC_API(int32_t)
 JS_DoubleToInt32(double d);
 
@@ -2363,30 +2374,16 @@ JS_DefaultValue(JSContext *cx, JS::Handl
 extern JS_PUBLIC_API(bool)
 JS_PropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                 JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_StrictPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict,
                       JS::MutableHandleValue vp);
 
-extern JS_PUBLIC_API(bool)
-JS_DeletePropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-                      bool *succeeded);
-
-extern JS_PUBLIC_API(bool)
-JS_EnumerateStub(JSContext *cx, JS::HandleObject obj);
-
-extern JS_PUBLIC_API(bool)
-JS_ResolveStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *resolvedp);
-
-extern JS_PUBLIC_API(bool)
-JS_ConvertStub(JSContext *cx, JS::HandleObject obj, JSType type,
-               JS::MutableHandleValue vp);
-
 template<typename T>
 struct JSConstScalarSpec {
     const char *name;
     T val;
 };
 
 typedef JSConstScalarSpec<double> JSConstDoubleSpec;
 typedef JSConstScalarSpec<int32_t> JSConstIntegerSpec;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2780,22 +2780,18 @@ GetIndexedPropertiesInRange(JSContext *c
                             Vector<uint32_t> &indexes, bool *success)
 {
     *success = false;
 
     // First, look for proxies or class hooks that can introduce extra
     // properties.
     JSObject *pobj = obj;
     do {
-        if (!pobj->isNative() ||
-            pobj->getClass()->resolve != JS_ResolveStub ||
-            pobj->getOps()->lookupGeneric)
-        {
+        if (!pobj->isNative() || pobj->getClass()->resolve || pobj->getOps()->lookupGeneric)
             return true;
-        }
     } while ((pobj = pobj->getProto()));
 
     // Collect indexed property names.
     pobj = obj;
     do {
         // Append dense elements.
         NativeObject *nativeObj = &pobj->as<NativeObject>();
         uint32_t initLen = nativeObj->getDenseInitializedLength();
@@ -3359,27 +3355,27 @@ CreateArrayPrototype(JSContext *cx, JSPr
 
     return arrayProto;
 }
 
 const Class ArrayObject::class_ = {
     "Array",
     JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
     array_addProperty,
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
-    nullptr,        /* call        */
-    nullptr,        /* hasInstance */
-    nullptr,        /* construct   */
-    nullptr,        /* trace       */
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
+    nullptr,                 /* finalize */
+    nullptr,                 /* call */
+    nullptr,                 /* hasInstance */
+    nullptr,                 /* construct */
+    nullptr,                 /* trace */
     {
         GenericCreateConstructor<js_Array, 1, JSFunction::FinalizeKind>,
         CreateArrayPrototype,
         array_static_methods,
         array_methods
     }
 };
 
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -23,23 +23,20 @@
 #include "vm/BooleanObject-inl.h"
 
 using namespace js;
 using namespace js::types;
 
 const Class BooleanObject::class_ = {
     "Boolean",
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 MOZ_ALWAYS_INLINE bool
 IsBoolean(HandleValue v)
 {
     return v.isBoolean() || (v.isObject() && v.toObject().is<BooleanObject>());
 }
 
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -317,17 +317,20 @@ CallJSPropertyOpSetter(JSContext *cx, St
 
 static inline bool
 CallJSDeletePropertyOp(JSContext *cx, JSDeletePropertyOp op, HandleObject receiver, HandleId id,
                        bool *succeeded)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     assertSameCompartment(cx, receiver, id);
-    return op(cx, receiver, id, succeeded);
+    if (op)
+        return op(cx, receiver, id, succeeded);
+    *succeeded = true;
+    return true;
 }
 
 inline bool
 CallSetter(JSContext *cx, HandleObject obj, HandleId id, StrictPropertyOp op, unsigned attrs,
            bool strict, MutableHandleValue vp)
 {
     if (attrs & JSPROP_SETTER) {
         RootedValue opv(cx, CastAsObjectJsval(op));
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3015,22 +3015,22 @@ FinishDateClassInit(JSContext *cx, Handl
            baseops::DefineGeneric(cx, proto.as<NativeObject>(), toGMTStringId, toUTCStringFun,
                                   JS_PropertyStub, JS_StrictPropertyStub, 0);
 }
 
 const Class DateObject::class_ = {
     js_Date_str,
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
     date_convert,
     nullptr,                 /* finalize */
     nullptr,                 /* call */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct */
     nullptr,                 /* trace */
     {
         GenericCreateConstructor<js_Date, MAXARGS, JSFunction::FinalizeKind>,
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -59,23 +59,23 @@ static const JSFunctionSpec exception_me
 };
 
 #define IMPLEMENT_ERROR_SUBCLASS(name) \
     { \
         js_Error_str, /* yes, really */ \
         JSCLASS_IMPLEMENTS_BARRIERS | \
         JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
         JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS), \
-        JS_PropertyStub,         /* addProperty */ \
-        JS_DeletePropertyStub,   /* delProperty */ \
+        nullptr,                 /* addProperty */ \
+        nullptr,                 /* delProperty */ \
         JS_PropertyStub,         /* getProperty */ \
         JS_StrictPropertyStub,   /* setProperty */ \
-        JS_EnumerateStub, \
-        JS_ResolveStub, \
-        JS_ConvertStub, \
+        nullptr,                 /* enumerate */ \
+        nullptr,                 /* resolve */ \
+        nullptr,                 /* convert */ \
         exn_finalize, \
         nullptr,                 /* call        */ \
         nullptr,                 /* hasInstance */ \
         nullptr,                 /* construct   */ \
         nullptr,                 /* trace       */ \
         { \
             ErrorObject::createConstructor, \
             ErrorObject::createProto, \
@@ -89,23 +89,23 @@ static const JSFunctionSpec exception_me
 
 const Class
 ErrorObject::classes[JSEXN_LIMIT] = {
     {
         js_Error_str,
         JSCLASS_IMPLEMENTS_BARRIERS |
         JSCLASS_HAS_CACHED_PROTO(JSProto_Error) |
         JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS),
-        JS_PropertyStub,         /* addProperty */
-        JS_DeletePropertyStub,   /* delProperty */
+        nullptr,                 /* addProperty */
+        nullptr,                 /* delProperty */
         JS_PropertyStub,         /* getProperty */
         JS_StrictPropertyStub,   /* setProperty */
-        JS_EnumerateStub,
-        JS_ResolveStub,
-        JS_ConvertStub,
+        nullptr,                 /* enumerate */
+        nullptr,                 /* resolve */
+        nullptr,                 /* convert */
         exn_finalize,
         nullptr,                 /* call        */
         nullptr,                 /* hasInstance */
         nullptr,                 /* construct   */
         nullptr,                 /* trace       */
         {
             ErrorObject::createConstructor,
             ErrorObject::createProto,
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -272,22 +272,22 @@ namespace js {
 
 #define PROXY_CLASS_WITH_EXT(name, flags, ext)                                          \
     {                                                                                   \
         name,                                                                           \
         js::Class::NON_NATIVE |                                                         \
             JSCLASS_IS_PROXY |                                                          \
             JSCLASS_IMPLEMENTS_BARRIERS |                                               \
             flags,                                                                      \
-        JS_PropertyStub,         /* addProperty */                                      \
-        JS_DeletePropertyStub,   /* delProperty */                                      \
+        nullptr,                 /* addProperty */                                      \
+        nullptr,                 /* delProperty */                                      \
         JS_PropertyStub,         /* getProperty */                                      \
         JS_StrictPropertyStub,   /* setProperty */                                      \
-        JS_EnumerateStub,                                                               \
-        JS_ResolveStub,                                                                 \
+        nullptr,                 /* enumerate */                                        \
+        nullptr,                 /* resolve */                                          \
         js::proxy_Convert,                                                              \
         js::proxy_Finalize,      /* finalize    */                                      \
         nullptr,                  /* call        */                                     \
         js::proxy_HasInstance,   /* hasInstance */                                      \
         nullptr,             /* construct   */                                          \
         js::proxy_Trace,         /* trace       */                                      \
         JS_NULL_CLASS_SPEC,                                                             \
         ext,                                                                            \
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -889,23 +889,23 @@ CreateFunctionPrototype(JSContext *cx, J
 
     return functionProto;
 }
 
 const Class JSFunction::class_ = {
     js_Function_str,
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     fun_enumerate,
     js::fun_resolve,
-    JS_ConvertStub,
+    nullptr,                 /* convert     */
     nullptr,                 /* finalize    */
     nullptr,                 /* call        */
     fun_hasInstance,
     nullptr,                 /* construct   */
     fun_trace,
     {
         CreateFunctionConstructor,
         CreateFunctionPrototype,
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2358,18 +2358,17 @@ NewObjectKind
 types::UseNewTypeForInitializer(JSScript *script, jsbytecode *pc, const Class *clasp)
 {
     return UseNewTypeForInitializer(script, pc, JSCLASS_CACHED_PROTO_KEY(clasp));
 }
 
 static inline bool
 ClassCanHaveExtraProperties(const Class *clasp)
 {
-    MOZ_ASSERT(clasp->resolve);
-    return clasp->resolve != JS_ResolveStub
+    return clasp->resolve
         || clasp->ops.lookupGeneric
         || clasp->ops.getGeneric
         || IsAnyTypedArrayClass(clasp);
 }
 
 static inline bool
 PrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSObject *obj)
 {
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -281,18 +281,20 @@ Snapshot(JSContext *cx, HandleObject pob
     RootedObject pobj(cx, pobj_);
 
     do {
         const Class *clasp = pobj->getClass();
         if (pobj->isNative() &&
             !pobj->getOps()->enumerate &&
             !(clasp->flags & JSCLASS_NEW_ENUMERATE))
         {
-            if (!clasp->enumerate(cx, pobj.as<NativeObject>()))
-                return false;
+            if (JSEnumerateOp enumerate = clasp->enumerate) {
+                if (!enumerate(cx, pobj.as<NativeObject>()))
+                    return false;
+            }
             if (!EnumerateNativeProperties(cx, pobj.as<NativeObject>(), flags, ht, props))
                 return false;
         } else {
             if (pobj->is<ProxyObject>()) {
                 AutoIdVector proxyProps(cx);
                 if (flags & JSITER_OWNONLY) {
                     if (flags & JSITER_HIDDEN) {
                         // This gets all property keys, both strings and
@@ -718,17 +720,17 @@ js::GetIterator(JSContext *cx, HandleObj
         {
             JSObject *pobj = obj;
             do {
                 if (!pobj->isNative() ||
                     !pobj->as<NativeObject>().hasEmptyElements() ||
                     IsAnyTypedArray(pobj) ||
                     pobj->hasUncacheableProto() ||
                     pobj->getOps()->enumerate ||
-                    pobj->getClass()->enumerate != JS_EnumerateStub ||
+                    pobj->getClass()->enumerate ||
                     pobj->as<NativeObject>().containsPure(cx->names().iteratorIntrinsic))
                 {
                     shapes.clear();
                     goto miss;
                 }
                 Shape *shape = pobj->lastProperty();
                 key = (key + (key << 16)) ^ (uintptr_t(shape) >> 3);
                 if (!shapes.append(shape))
@@ -916,23 +918,23 @@ PropertyIteratorObject::finalize(FreeOp 
 }
 
 const Class PropertyIteratorObject::class_ = {
     "Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) |
     JSCLASS_HAS_PRIVATE |
     JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     trace,
 };
 
 enum {
@@ -941,63 +943,51 @@ enum {
     ArrayIteratorSlotItemKind,
     ArrayIteratorSlotCount
 };
 
 const Class ArrayIteratorObject::class_ = {
     "Array Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(ArrayIteratorSlotCount),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr                  /* finalize    */
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 static const JSFunctionSpec array_iterator_methods[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "ArrayIteratorIdentity", 0, 0),
     JS_SELF_HOSTED_FN("next", "ArrayIteratorNext", 0, 0),
     JS_FS_END
 };
 
 static const Class StringIteratorPrototypeClass = {
     "String Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS,
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr                  /* finalize    */
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 enum {
     StringIteratorSlotIteratedObject,
     StringIteratorSlotNextIndex,
     StringIteratorSlotCount
 };
 
 const Class StringIteratorObject::class_ = {
     "String Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(StringIteratorSlotCount),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr                  /* finalize    */
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 static const JSFunctionSpec string_iterator_methods[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "StringIteratorIdentity", 0, 0),
     JS_SELF_HOSTED_FN("next", "StringIteratorNext", 0, 0),
     JS_FS_END
 };
 
@@ -1314,23 +1304,23 @@ stopiter_hasInstance(JSContext *cx, Hand
 {
     *bp = JS_IsStopIteration(v);
     return true;
 }
 
 const Class StopIterationObject::class_ = {
     "StopIteration",
     JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     nullptr,                 /* finalize    */
     nullptr,                 /* call        */
     stopiter_hasInstance,
     nullptr                  /* construct   */
 };
 
 /* static */ bool
 GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -74,23 +74,20 @@ size_t
 MathCache::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     return mallocSizeOf(this);
 }
 
 const Class js::MathClass = {
     js_Math_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 bool
 js::math_abs_handle(JSContext *cx, js::HandleValue v, js::MutableHandleValue r)
 {
     double x;
     if (!ToNumber(cx, v, &x))
         return false;
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -459,23 +459,20 @@ static const JSFunctionSpec number_funct
     JS_FN(js_parseFloat_str,    num_parseFloat,      1,0),
     JS_FN(js_parseInt_str,      num_parseInt,        2,0),
     JS_FS_END
 };
 
 const Class NumberObject::class_ = {
     js_Number_str,
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 static bool
 Number(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Sample JS_CALLEE before clobbering. */
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -172,23 +172,23 @@ FinishObjectClassInit(JSContext *cx, JS:
         return false;
     return true;
 }
 
 
 const Class JSObject::class_ = {
     js_Object_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     nullptr,                 /* finalize */
     nullptr,                 /* call */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct */
     nullptr,                 /* trace */
     {
         CreateObjectConstructor,
         CreateObjectPrototype,
@@ -2719,24 +2719,20 @@ NativeObject *
 js_InitClass(JSContext *cx, HandleObject obj, JSObject *protoProto_,
              const Class *clasp, Native constructor, unsigned nargs,
              const JSPropertySpec *ps, const JSFunctionSpec *fs,
              const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs,
              NativeObject **ctorp, AllocKind ctorKind)
 {
     RootedObject protoProto(cx, protoProto_);
 
-    /* Assert mandatory function pointer members. */
-    MOZ_ASSERT(clasp->addProperty);
-    MOZ_ASSERT(clasp->delProperty);
+    /* Check function pointer members. */
+    MOZ_ASSERT(clasp->addProperty != JS_PropertyStub);  // (use null instead)
     MOZ_ASSERT(clasp->getProperty);
     MOZ_ASSERT(clasp->setProperty);
-    MOZ_ASSERT(clasp->enumerate);
-    MOZ_ASSERT(clasp->resolve);
-    MOZ_ASSERT(clasp->convert);
 
     RootedAtom atom(cx, Atomize(cx, clasp->name, strlen(clasp->name)));
     if (!atom)
         return nullptr;
 
     /*
      * All instances of the class will inherit properties from the prototype
      * object we are about to create (in DefineConstructorAndPrototype), which
@@ -3282,18 +3278,17 @@ LookupPropertyPureInline(ThreadSafeConte
             *propp = shape;
             return true;
         }
 
         // Fail if there's a resolve hook. We allow the JSFunction resolve hook
         // if we know it will never add a property with this name.
         do {
             const Class *clasp = current->getClass();
-            MOZ_ASSERT(clasp->resolve);
-            if (clasp->resolve == JS_ResolveStub)
+            if (!clasp->resolve)
                 break;
             if (clasp->resolve == fun_resolve && !FunctionHasResolveHook(cx->names(), id))
                 break;
             return false;
         } while (0);
 
         JSObject *proto = current->getProto();
 
@@ -3653,24 +3648,24 @@ js::DefaultValue(JSContext *cx, HandleOb
 
 JS_FRIEND_API(bool)
 JS_EnumerateState(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
                   MutableHandleValue statep, JS::MutableHandleId idp)
 {
     /* If the class has a custom JSCLASS_NEW_ENUMERATE hook, call it. */
     const Class *clasp = obj->getClass();
     JSEnumerateOp enumerate = clasp->enumerate;
-    if (clasp->flags & JSCLASS_NEW_ENUMERATE) {
-        MOZ_ASSERT(enumerate != JS_EnumerateStub);
-        return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
+    if (enumerate) {
+        if (clasp->flags & JSCLASS_NEW_ENUMERATE)
+            return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
+
+        if (!enumerate(cx, obj))
+            return false;
     }
 
-    if (!enumerate(cx, obj))
-        return false;
-
     /* Tell InitNativeIterator to treat us like a native object. */
     MOZ_ASSERT(enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL);
     statep.setMagic(JS_NATIVE_ENUMERATE);
     return true;
 }
 
 bool
 js::IsDelegate(JSContext *cx, HandleObject obj, const js::Value &v, bool *result)
@@ -4240,17 +4235,17 @@ JSObject::hasIdempotentProtoChain() cons
     // Return false if obj (or an object on its proto chain) is non-native or
     // has a resolve or lookup hook.
     JSObject *obj = const_cast<JSObject *>(this);
     while (true) {
         if (!obj->isNative())
             return false;
 
         JSResolveOp resolve = obj->getClass()->resolve;
-        if (resolve != JS_ResolveStub && resolve != js::fun_resolve)
+        if (resolve && resolve != js::fun_resolve)
             return false;
 
         if (obj->getOps()->lookupProperty || obj->getOps()->lookupGeneric || obj->getOps()->lookupElement)
             return false;
 
         obj = obj->getProto();
         if (!obj)
             return true;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -683,17 +683,17 @@ class JSObject : public js::gc::Cell
         return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp);
     }
 
     static bool defaultValue(JSContext *cx, js::HandleObject obj, JSType hint,
                              js::MutableHandleValue vp)
     {
         JSConvertOp op = obj->getClass()->convert;
         bool ok;
-        if (op == JS_ConvertStub)
+        if (!op)
             ok = js::DefaultValue(cx, obj, hint, vp);
         else
             ok = op(cx, obj, hint, vp);
         MOZ_ASSERT_IF(ok, vp.isPrimitive());
         return ok;
     }
 
     static JSObject *thisObject(JSContext *cx, js::HandleObject obj)
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -33,23 +33,20 @@ using namespace js::types;
 
 using mozilla::IsFinite;
 using mozilla::Maybe;
 using mozilla::RangedPtr;
 
 const Class js::JSONClass = {
     js_JSON_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_JSON),
-    JS_PropertyStub,        /* addProperty */
-    JS_DeletePropertyStub,  /* delProperty */
+    nullptr,                /* addProperty */
+    nullptr,                /* delProperty */
     JS_PropertyStub,        /* getProperty */
-    JS_StrictPropertyStub,  /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub   /* setProperty */
 };
 
 static inline bool
 IsQuoteSpecialCharacter(char16_t c)
 {
     static_assert('\b' < ' ', "'\\b' must be treated as special below");
     static_assert('\f' < ' ', "'\\f' must be treated as special below");
     static_assert('\n' < ' ', "'\\n' must be treated as special below");
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1343,23 +1343,23 @@ ScriptSourceObject::finalize(FreeOp *fop
     sso->source()->decref();
     sso->setReservedSlot(SOURCE_SLOT, PrivateValue(nullptr));
 }
 
 const Class ScriptSourceObject::class_ = {
     "ScriptSource",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,        /* addProperty */
-    JS_DeletePropertyStub,  /* delProperty */
+    nullptr,                /* addProperty */
+    nullptr,                /* delProperty */
     JS_PropertyStub,        /* getProperty */
     JS_StrictPropertyStub,  /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                /* enumerate */
+    nullptr,                /* resolve */
+    nullptr,                /* convert */
     finalize,
     nullptr,                /* call        */
     nullptr,                /* hasInstance */
     nullptr,                /* construct   */
     trace
 };
 
 ScriptSourceObject *
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -421,23 +421,22 @@ js::str_resolve(JSContext *cx, HandleObj
     }
     return true;
 }
 
 const Class StringObject::class_ = {
     js_String_str,
     JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_String),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     str_enumerate,
-    str_resolve,
-    JS_ConvertStub
+    str_resolve
 };
 
 /*
  * Returns a JSString * for the |this| value associated with 'call', or throws
  * a TypeError if |this| is null or undefined.  This algorithm is the same as
  * calling CheckObjectCoercible(this), then returning ToString(this), as all
  * String.prototype.* methods do (other than toString and valueOf).
  */
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -580,23 +580,23 @@ WeakMap_construct(JSContext *cx, unsigne
     args.rval().setObject(*obj);
     return true;
 }
 
 const Class WeakMapObject::class_ = {
     "WeakMap",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     WeakMap_finalize,
     nullptr,                 /* call        */
     nullptr,                 /* construct   */
     nullptr,                 /* xdrObject   */
     WeakMap_mark
 };
 
 static const JSFunctionSpec weak_map_methods[] = {
--- a/js/src/perf/jsperf.cpp
+++ b/js/src/perf/jsperf.cpp
@@ -156,18 +156,18 @@ static const struct pm_const {
 
 #undef CONSTANT
 
 static bool pm_construct(JSContext* cx, unsigned argc, jsval* vp);
 static void pm_finalize(JSFreeOp* fop, JSObject* obj);
 
 static const JSClass pm_class = {
     "PerfMeasurement", JSCLASS_HAS_PRIVATE,
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, pm_finalize
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, pm_finalize
 };
 
 // Constructor and destructor
 
 static bool
 pm_construct(JSContext* cx, unsigned argc, jsval* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1015,23 +1015,23 @@ my_LargeAllocFailCallback(void *data)
     rt->gc.gc(GC_NORMAL, JS::gcreason::SHARED_MEMORY_LIMIT);
 }
 
 static const uint32_t CacheEntry_SOURCE = 0;
 static const uint32_t CacheEntry_BYTECODE = 1;
 
 static const JSClass CacheEntry_class = {
     "CacheEntryObject", JSCLASS_HAS_RESERVED_SLOTS(2),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,               /* enumerate */
+    nullptr,               /* resolve */
+    nullptr,               /* convert */
     nullptr,               /* finalize */
     nullptr,               /* call */
     nullptr,               /* hasInstance */
     nullptr,               /* construct */
     nullptr,               /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
 };
 
@@ -2564,20 +2564,20 @@ sandbox_resolve(JSContext *cx, HandleObj
     if (ToBoolean(v))
         return JS_ResolveStandardClass(cx, obj, id, resolvedp);
     return true;
 }
 
 static const JSClass sandbox_class = {
     "sandbox",
     JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub,   JS_DeletePropertyStub,
+    nullptr,           nullptr,
     JS_PropertyStub,   JS_StrictPropertyStub,
     sandbox_enumerate, sandbox_resolve,
-    JS_ConvertStub, nullptr,
+    nullptr, nullptr,
     nullptr, nullptr, nullptr,
     JS_GlobalObjectTraceHook
 };
 
 static JSObject *
 NewSandbox(JSContext *cx, bool lazy)
 {
     RootedObject obj(cx, JS_NewGlobalObject(cx, &sandbox_class, nullptr,
@@ -3957,23 +3957,20 @@ GetMaxArgs(JSContext *cx, unsigned argc,
 static bool
 ObjectEmulatingUndefined(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     static const JSClass cls = {
         "ObjectEmulatingUndefined",
         JSCLASS_EMULATES_UNDEFINED,
-        JS_PropertyStub,
-        JS_DeletePropertyStub,
+        nullptr,
+        nullptr,
         JS_PropertyStub,
-        JS_StrictPropertyStub,
-        JS_EnumerateStub,
-        JS_ResolveStub,
-        JS_ConvertStub
+        JS_StrictPropertyStub
     };
 
     RootedObject obj(cx, JS_NewObject(cx, &cls, JS::NullPtr(), JS::NullPtr()));
     if (!obj)
         return false;
     args.rval().setObject(*obj);
     return true;
 }
@@ -4780,20 +4777,20 @@ global_resolve(JSContext *cx, HandleObje
     if (!JS_ResolveStandardClass(cx, obj, id, resolvedp))
         return false;
 #endif
     return true;
 }
 
 static const JSClass global_class = {
     "global", JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub,  JS_DeletePropertyStub,
+    nullptr,          nullptr,
     JS_PropertyStub,  JS_StrictPropertyStub,
     global_enumerate, global_resolve,
-    JS_ConvertStub,   nullptr,
+    nullptr, nullptr,
     nullptr, nullptr, nullptr,
     JS_GlobalObjectTraceHook
 };
 
 /*
  * Define a FakeDOMObject constructor. It returns an object with a getter,
  * setter and method with attached JitInfo. This object can be used to test
  * IonMonkey DOM optimizations in the shell.
@@ -4897,23 +4894,23 @@ static const JSPropertySpec dom_props[] 
 
 static const JSFunctionSpec dom_methods[] = {
     JS_FNINFO("doFoo", dom_genericMethod, &doFoo_methodinfo, 3, JSPROP_ENUMERATE),
     JS_FS_END
 };
 
 static const JSClass dom_class = {
     "FakeDOMObject", JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
+    nullptr,               /* addProperty */
+    nullptr,               /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,               /* enumerate */
+    nullptr,               /* resolve */
+    nullptr,               /* convert */
     nullptr,               /* finalize */
     nullptr,               /* call */
     nullptr,               /* hasInstance */
     nullptr,               /* construct */
     nullptr,               /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
 };
 
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -565,23 +565,23 @@ ArgumentsObject::trace(JSTracer *trc, JS
  * stack frame with their corresponding property values in the frame's
  * arguments object.
  */
 const Class NormalArgumentsObject::class_ = {
     "Arguments",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(NormalArgumentsObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,         /* addProperty */
+    nullptr,                 /* addProperty */
     args_delProperty,
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     args_enumerate,
     args_resolve,
-    JS_ConvertStub,
+    nullptr,                 /* convert     */
     ArgumentsObject::finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     ArgumentsObject::trace
 };
 
 /*
@@ -589,21 +589,21 @@ const Class NormalArgumentsObject::class
  * arguments, so it is represented by a different class while sharing some
  * functionality.
  */
 const Class StrictArgumentsObject::class_ = {
     "Arguments",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(StrictArgumentsObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,         /* addProperty */
+    nullptr,                 /* addProperty */
     args_delProperty,
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     strictargs_enumerate,
     strictargs_resolve,
-    JS_ConvertStub,
+    nullptr,                 /* convert     */
     ArgumentsObject::finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     ArgumentsObject::trace
 };
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -90,38 +90,35 @@ js::ToClampedIndex(JSContext *cx, Handle
 
 /*
  * ArrayBufferObject (base)
  */
 
 const Class ArrayBufferObject::protoClass = {
     "ArrayBufferPrototype",
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 const Class ArrayBufferObject::class_ = {
     "ArrayBuffer",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer) |
     JSCLASS_BACKGROUND_FINALIZE,
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     ArrayBufferObject::finalize,
     nullptr,        /* call        */
     nullptr,        /* hasInstance */
     nullptr,        /* construct   */
     ArrayBufferObject::trace,
     JS_NULL_CLASS_SPEC,
     {
         nullptr,    /* outerObject */
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2343,18 +2343,18 @@ Debugger::finalize(FreeOp *fop, JSObject
         return;
     fop->delete_(dbg);
 }
 
 const Class Debugger::jsclass = {
     "Debugger",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUG_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Debugger::finalize,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, Debugger::finalize,
     nullptr,              /* call        */
     nullptr,              /* hasInstance */
     nullptr,              /* construct   */
     Debugger::traceObject
 };
 
 /* static */ Debugger *
 Debugger::fromThisValue(JSContext *cx, const CallArgs &args, const char *fnname)
@@ -3823,18 +3823,18 @@ DebuggerScript_trace(JSTracer *trc, JSOb
         obj->as<NativeObject>().setPrivateUnbarriered(script);
     }
 }
 
 const Class DebuggerScript_class = {
     "Script",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, nullptr,
     nullptr,              /* call        */
     nullptr,              /* hasInstance */
     nullptr,              /* construct   */
     DebuggerScript_trace
 };
 
 JSObject *
 Debugger::newDebuggerScript(JSContext *cx, HandleScript script)
@@ -4777,18 +4777,18 @@ DebuggerSource_trace(JSTracer *trc, JSOb
         obj->as<NativeObject>().setPrivateUnbarriered(referent);
     }
 }
 
 const Class DebuggerSource_class = {
     "Source",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSOURCE_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, nullptr,
     nullptr,              /* call        */
     nullptr,              /* hasInstance */
     nullptr,              /* construct   */
     DebuggerSource_trace
 };
 
 JSObject *
 Debugger::newDebuggerSource(JSContext *cx, HandleScriptSource source)
@@ -5123,18 +5123,18 @@ DebuggerFrame_maybeDecrementFrameScriptS
 static void
 DebuggerFrame_finalize(FreeOp *fop, JSObject *obj)
 {
     DebuggerFrame_freeScriptFrameIterData(fop, obj);
 }
 
 const Class DebuggerFrame_class = {
     "Frame", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, DebuggerFrame_finalize
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, DebuggerFrame_finalize
 };
 
 static NativeObject *
 CheckThisFrame(JSContext *cx, const CallArgs &args, const char *fnname, bool checkLive)
 {
     if (!args.thisv().isObject()) {
         ReportObjectRequired(cx);
         return nullptr;
@@ -5342,18 +5342,17 @@ DebuggerFrame_getOlder(JSContext *cx, un
         }
     }
     args.rval().setNull();
     return true;
 }
 
 const Class DebuggerArguments_class = {
     "Arguments", JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGARGUMENTS_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 /* The getter used for each element of frame.arguments. See DebuggerFrame_getArguments. */
 static bool
 DebuggerArguments_getArg(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     int32_t i = args.callee().as<JSFunction>().getExtendedSlot(0).toInt32();
@@ -5856,18 +5855,18 @@ DebuggerObject_trace(JSTracer *trc, JSOb
         obj->as<NativeObject>().setPrivateUnbarriered(referent);
     }
 }
 
 const Class DebuggerObject_class = {
     "Object",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGOBJECT_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, nullptr,
     nullptr,              /* call        */
     nullptr,              /* hasInstance */
     nullptr,              /* construct   */
     DebuggerObject_trace
 };
 
 static NativeObject *
 DebuggerObject_checkThis(JSContext *cx, const CallArgs &args, const char *fnname)
@@ -6764,18 +6763,18 @@ DebuggerEnv_trace(JSTracer *trc, JSObjec
         obj->as<NativeObject>().setPrivateUnbarriered(referent);
     }
 }
 
 const Class DebuggerEnv_class = {
     "Environment",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGENV_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, nullptr,
     nullptr,              /* call        */
     nullptr,              /* hasInstance */
     nullptr,              /* construct   */
     DebuggerEnv_trace
 };
 
 static NativeObject *
 DebuggerEnv_checkThis(JSContext *cx, const CallArgs &args, const char *fnname,
--- a/js/src/vm/DebuggerMemory.cpp
+++ b/js/src/vm/DebuggerMemory.cpp
@@ -67,23 +67,20 @@ DebuggerMemory::construct(JSContext *cx,
     return false;
 }
 
 /* static */ const Class DebuggerMemory::class_ = {
     "Memory",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_COUNT),
 
-    JS_PropertyStub,       // addProperty
-    JS_DeletePropertyStub, // delProperty
+    nullptr,               // addProperty
+    nullptr,               // delProperty
     JS_PropertyStub,       // getProperty
-    JS_StrictPropertyStub, // setProperty
-    JS_EnumerateStub,      // enumerate
-    JS_ResolveStub,        // resolve
-    JS_ConvertStub,        // convert
+    JS_StrictPropertyStub  // setProperty
 };
 
 /* static */ DebuggerMemory *
 DebuggerMemory::checkThis(JSContext *cx, CallArgs &args, const char *fnName)
 {
     const Value &thisValue = args.thisv();
 
     if (!thisValue.isObject()) {
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -198,45 +198,29 @@ LegacyGeneratorObject::close(JSContext *
     args.setThis(ObjectValue(*genObj));
 
     return Invoke(cx, args);
 }
 
 const Class LegacyGeneratorObject::class_ = {
     "Generator",
     JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,                 /* finalize    */
-    nullptr,                 /* call        */
-    nullptr,                 /* hasInstance */
-    nullptr,                 /* construct   */
-    nullptr,                 /* trace       */
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 const Class StarGeneratorObject::class_ = {
     "Generator",
     JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,                 /* finalize    */
-    nullptr,                 /* call        */
-    nullptr,                 /* hasInstance */
-    nullptr,                 /* construct   */
-    nullptr,                 /* trace       */
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 static const JSFunctionSpec star_generator_methods[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
     JS_SELF_HOSTED_FN("next", "StarGeneratorNext", 1, 0),
     JS_SELF_HOSTED_FN("throw", "StarGeneratorThrow", 1, 0),
     JS_FS_END
 };
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -457,18 +457,18 @@ static void
 GlobalDebuggees_finalize(FreeOp *fop, JSObject *obj)
 {
     fop->delete_((GlobalObject::DebuggerVector *) obj->as<NativeObject>().getPrivate());
 }
 
 static const Class
 GlobalDebuggees_class = {
     "GlobalDebuggee", JSCLASS_HAS_PRIVATE,
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, GlobalDebuggees_finalize
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, GlobalDebuggees_finalize
 };
 
 GlobalObject::DebuggerVector *
 GlobalObject::getDebuggers()
 {
     Value debuggers = getReservedSlot(DEBUGGERS);
     if (debuggers.isUndefined())
         return nullptr;
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -171,20 +171,19 @@ js::CancelOffThreadIonCompile(JSCompartm
             jit::FinishOffThreadBuilder(nullptr, builder);
         }
         builder = next;
     }
 }
 
 static const JSClass parseTaskGlobalClass = {
     "internal-parse-task-global", JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub,  JS_DeletePropertyStub,
+    nullptr,          nullptr,
     JS_PropertyStub,  JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub,
-    JS_ConvertStub,   nullptr,
+    nullptr, nullptr, nullptr, nullptr,
     nullptr, nullptr, nullptr,
     JS_GlobalObjectTraceHook
 };
 
 ParseTask::ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSContext *initCx,
                      const char16_t *chars, size_t length,
                      JS::OffThreadCompileCallback callback, void *callbackData)
   : cx(cx), options(initCx), chars(chars), length(length),
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -137,18 +137,17 @@ js::BoxNonStrictThis(JSContext *cx, cons
 #if JS_HAS_NO_SUCH_METHOD
 
 static const uint32_t JSSLOT_FOUND_FUNCTION = 0;
 static const uint32_t JSSLOT_SAVED_ID = 1;
 
 static const Class js_NoSuchMethodClass = {
     "NoSuchMethod",
     JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 /*
  * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
  * the base object, we search for the __noSuchMethod__ method in the base.
  * If it exists, we store the method and the property's id into an object of
  * NoSuchMethod class and store this object into the callee's stack slot.
  * Later, Invoke will recognise such an object and transfer control to
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -561,17 +561,17 @@ LookupOwnPropertyInline(ExclusiveContext
     if (Shape *shape = obj->lookup(cx, id)) {
         objp.set(obj);
         propp.set(shape);
         *donep = true;
         return true;
     }
 
     // id was not found in obj. Try obj's resolve hook, if any.
-    if (obj->getClass()->resolve != JS_ResolveStub) {
+    if (obj->getClass()->resolve) {
         if (!cx->shouldBeJSContext() || !allowGC)
             return false;
 
         bool recursed;
         if (!CallResolveOp(cx->asJSContext(),
                            MaybeRooted<NativeObject*, allowGC>::toHandle(obj),
                            MaybeRooted<jsid, allowGC>::toHandle(id),
                            MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp),
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1070,17 +1070,19 @@ NativeObject::addDataProperty(ExclusiveC
  * both while saving cycles for classes that stub their addProperty hook.
  */
 template <ExecutionMode mode>
 static inline bool
 CallAddPropertyHook(typename ExecutionModeTraits<mode>::ExclusiveContextType cxArg,
                     const Class *clasp, HandleNativeObject obj, HandleShape shape,
                     HandleValue nominal)
 {
-    if (clasp->addProperty != JS_PropertyStub) {
+    if (clasp->addProperty) {
+        MOZ_ASSERT(clasp->addProperty != JS_PropertyStub);
+
         if (mode == ParallelExecution)
             return false;
 
         ExclusiveContext *cx = cxArg->asExclusiveContext();
         if (!cx->shouldBeJSContext())
             return false;
 
         /* Make a local copy of value so addProperty can mutate its inout parameter. */
@@ -1117,17 +1119,19 @@ CallAddPropertyHookDense(typename Execut
                 arr->setLengthInt32(index + 1);
             } else {
                 arr->setLength(cxArg->asExclusiveContext(), index + 1);
             }
         }
         return true;
     }
 
-    if (clasp->addProperty != JS_PropertyStub) {
+    if (clasp->addProperty) {
+        MOZ_ASSERT(clasp->addProperty != JS_PropertyStub);
+
         if (mode == ParallelExecution)
             return false;
 
         ExclusiveContext *cx = cxArg->asExclusiveContext();
         if (!cx->shouldBeJSContext())
             return false;
 
         if (!obj->maybeCopyElementsForWrite(cx))
--- a/js/src/vm/PIC.cpp
+++ b/js/src/vm/PIC.cpp
@@ -297,18 +297,18 @@ static void
 ForOfPIC_traceObject(JSTracer *trc, JSObject *obj)
 {
     if (ForOfPIC::Chain *chain = ForOfPIC::fromJSObject(&obj->as<NativeObject>()))
         chain->mark(trc);
 }
 
 const Class ForOfPIC::jsclass = {
     "ForOfPIC", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ForOfPIC_finalize,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, ForOfPIC_finalize,
     nullptr,              /* call        */
     nullptr,              /* hasInstance */
     nullptr,              /* construct   */
     ForOfPIC_traceObject
 };
 
 /* static */ NativeObject *
 js::ForOfPIC::createForOfPICObject(JSContext *cx, Handle<GlobalObject*> global)
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -261,23 +261,23 @@ RegExpObject::trace(JSTracer *trc, JSObj
     }
 }
 
 const Class RegExpObject::class_ = {
     js_RegExp_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,        /* enumerate */
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     nullptr,                 /* finalize */
     nullptr,                 /* call */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct */
     RegExpObject::trace
 };
 
 RegExpObject *
--- a/js/src/vm/RegExpStatics.cpp
+++ b/js/src/vm/RegExpStatics.cpp
@@ -33,23 +33,23 @@ resc_trace(JSTracer *trc, JSObject *obj)
     MOZ_ASSERT(pdata);
     RegExpStatics *res = static_cast<RegExpStatics *>(pdata);
     res->mark(trc);
 }
 
 const Class RegExpStaticsObject::class_ = {
     "RegExpStatics",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     resc_finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     resc_trace
 };
 
 RegExpStaticsObject *
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -136,24 +136,23 @@ SavedFrame::HashPolicy::rekey(Key &key, 
     key = newKey;
 }
 
 /* static */ const Class SavedFrame::class_ = {
     "SavedFrame",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT),
 
-    JS_PropertyStub,       // addProperty
-    JS_DeletePropertyStub, // delProperty
+    nullptr,               // addProperty
+    nullptr,               // delProperty
     JS_PropertyStub,       // getProperty
     JS_StrictPropertyStub, // setProperty
-    JS_EnumerateStub,      // enumerate
-    JS_ResolveStub,        // resolve
-    JS_ConvertStub,        // convert
-
+    nullptr,               // enumerate
+    nullptr,               // resolve
+    nullptr,               // convert
     SavedFrame::finalize   // finalize
 };
 
 /* static */ void
 SavedFrame::finalize(FreeOp *fop, JSObject *obj)
 {
     JSPrincipals *p = obj->as<SavedFrame>().getPrincipals();
     if (p) {
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -287,36 +287,30 @@ CallObject::createForStrictEval(JSContex
     RootedScript script(cx, frame.script());
     RootedObject scopeChain(cx, frame.scopeChain());
     return create(cx, script, scopeChain, callee);
 }
 
 const Class CallObject::class_ = {
     "Call",
     JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    nullptr                  /* convert: Leave it nullptr so we notice if calls ever escape */
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 const Class DeclEnvObject::class_ = {
     js_Object_str,
     JSCLASS_HAS_RESERVED_SLOTS(DeclEnvObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 /*
  * Create a DeclEnvObject for a JSScript that is not initialized to any
  * particular callsite. This object can either be initialized (with an enclosing
  * scope and callee) or used as a template for jit compilation.
  */
 DeclEnvObject *
@@ -583,36 +577,33 @@ with_ThisObject(JSContext *cx, HandleObj
     return &obj->as<DynamicWithObject>().withThis();
 }
 
 const Class StaticWithObject::class_ = {
     "WithTemplate",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(StaticWithObject::RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 const Class DynamicWithObject::class_ = {
     "With",
     JSCLASS_HAS_RESERVED_SLOTS(DynamicWithObject::RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     nullptr,                 /* finalize */
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     nullptr,                 /* trace       */
     JS_NULL_CLASS_SPEC,
     JS_NULL_CLASS_EXT,
     {
@@ -740,23 +731,20 @@ StaticBlockObject::addVar(ExclusiveConte
                                                                   /* allowDictionary = */ false);
 }
 
 const Class BlockObject::class_ = {
     "Block",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(BlockObject::RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 template<XDRMode mode>
 bool
 js::XDRStaticBlockObject(XDRState<mode> *xdr, HandleObject enclosingScope,
                          MutableHandle<StaticBlockObject*> objp)
 {
     /* NB: Keep this in sync with CloneStaticBlockObject. */
@@ -1036,23 +1024,23 @@ uninitialized_DeleteGeneric(JSContext *c
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 const Class UninitializedLexicalObject::class_ = {
     "UninitializedLexical",
     JSCLASS_HAS_RESERVED_SLOTS(UninitializedLexicalObject::RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     nullptr,                 /* finalize */
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     nullptr,                 /* trace       */
     JS_NULL_CLASS_SPEC,
     JS_NULL_CLASS_EXT,
     {
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -46,20 +46,19 @@ using JS::AutoCheckCannotGC;
 static void
 selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
 {
     PrintError(cx, stderr, message, report, true);
 }
 
 static const JSClass self_hosting_global_class = {
     "self-hosting-global", JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub,  JS_DeletePropertyStub,
+    nullptr,          nullptr,
     JS_PropertyStub,  JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub,
-    JS_ConvertStub,   nullptr,
+    nullptr, nullptr, nullptr, nullptr,
     nullptr, nullptr, nullptr,
     JS_GlobalObjectTraceHook
 };
 
 bool
 js::intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -295,37 +295,34 @@ SharedArrayBufferObject::addSizeOfExclud
                                                 JS::ClassInfo *info)
 {
     info->objectsNonHeapElementsMapped += obj->as<SharedArrayBufferObject>().byteLength();
 }
 
 const Class SharedArrayBufferObject::protoClass = {
     "SharedArrayBufferPrototype",
     JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 const Class SharedArrayBufferObject::class_ = {
     "SharedArrayBuffer",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                 /* enumerate */
+    nullptr,                 /* resolve */
+    nullptr,                 /* convert */
     SharedArrayBufferObject::Finalize,
     nullptr,        /* call        */
     nullptr,        /* hasInstance */
     nullptr,        /* construct   */
     nullptr,        /* trace */
     JS_NULL_CLASS_SPEC,
     JS_NULL_CLASS_EXT
 };
--- a/js/src/vm/SharedTypedArrayObject.cpp
+++ b/js/src/vm/SharedTypedArrayObject.cpp
@@ -699,44 +699,44 @@ IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPP
 }
 
 #define IMPL_SHARED_TYPED_ARRAY_PROTO_CLASS(_typedArray)                       \
 {                                                                              \
     "Shared" #_typedArray "Prototype",                                         \
     JSCLASS_HAS_RESERVED_SLOTS(SharedTypedArrayObject::RESERVED_SLOTS) |       \
     JSCLASS_HAS_PRIVATE |                                                      \
     JSCLASS_HAS_CACHED_PROTO(JSProto_Shared##_typedArray),                     \
-    JS_PropertyStub,         /* addProperty */                                 \
-    JS_DeletePropertyStub,   /* delProperty */                                 \
+    nullptr,                 /* addProperty */                                 \
+    nullptr,                 /* delProperty */                                 \
     JS_PropertyStub,         /* getProperty */                                 \
     JS_StrictPropertyStub,   /* setProperty */                                 \
-    JS_EnumerateStub,                                                          \
-    JS_ResolveStub,                                                            \
-    JS_ConvertStub,                                                            \
+    nullptr,                 /* enumerate   */                                 \
+    nullptr,                 /* resolve     */                                 \
+    nullptr,                 /* convert     */                                 \
     nullptr,                 /* finalize    */                                 \
     nullptr,                 /* call        */                                 \
     nullptr,                 /* hasInstance */                                 \
     nullptr,                 /* construct   */                                 \
     nullptr,                 /* trace  */                                      \
     SHARED_TYPED_ARRAY_CLASS_SPEC(_typedArray)                                 \
 }
 
 #define IMPL_SHARED_TYPED_ARRAY_FAST_CLASS(_typedArray)                        \
 {                                                                              \
     "Shared" #_typedArray,                                                     \
     JSCLASS_HAS_RESERVED_SLOTS(SharedTypedArrayObject::RESERVED_SLOTS) |       \
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |                        \
     JSCLASS_HAS_CACHED_PROTO(JSProto_Shared##_typedArray),                     \
-    JS_PropertyStub,         /* addProperty */                                 \
-    JS_DeletePropertyStub,   /* delProperty */                                 \
+    nullptr,                 /* addProperty */                                 \
+    nullptr,                 /* delProperty */                                 \
     JS_PropertyStub,         /* getProperty */                                 \
     JS_StrictPropertyStub,   /* setProperty */                                 \
-    JS_EnumerateStub,                                                          \
-    JS_ResolveStub,                                                            \
-    JS_ConvertStub,                                                            \
+    nullptr,                 /* enumerate   */                                 \
+    nullptr,                 /* resolve     */                                 \
+    nullptr,                 /* convert     */                                 \
     nullptr,                 /* finalize    */                                 \
     nullptr,                 /* call        */                                 \
     nullptr,                 /* hasInstance */                                 \
     nullptr,                 /* construct   */                                 \
     nullptr,                 /* trace  */                                      \
     SHARED_TYPED_ARRAY_CLASS_SPEC(_typedArray)                                 \
 }
 
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -799,23 +799,23 @@ TypedArrayObject::sharedTypedArrayProtot
     // Actually ({}).toString.call(%TypedArray%.prototype) should throw,
     // because %TypedArray%.prototype lacks the the typed array internal
     // slots.  (It's not clear this is desirable -- particularly applied to
     // the actual typed array prototypes, see below -- but it's what ES6
     // draft 20140824 requires.)  But this is about as much as we can do
     // until we implement @@toStringTag.
     "???",
     JSCLASS_HAS_CACHED_PROTO(JSProto_TypedArray),
-    JS_PropertyStub,        /* addProperty */
-    JS_DeletePropertyStub,  /* delProperty */
+    nullptr,                /* addProperty */
+    nullptr,                /* delProperty */
     JS_PropertyStub,        /* getProperty */
     JS_StrictPropertyStub,  /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,                /* enumerate */
+    nullptr,                /* resolve */
+    nullptr,                /* convert */
     nullptr,                /* finalize */
     nullptr,                /* call */
     nullptr,                /* hasInstance */
     nullptr,                /* construct */
     nullptr,                /* trace */
     {
         GenericCreateConstructor<TypedArrayConstructor, 3, JSFunction::FinalizeKind>,
         GenericCreatePrototype,
@@ -1754,23 +1754,23 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Flo
 }
 
 #define IMPL_TYPED_ARRAY_CLASS(_typedArray)                                    \
 {                                                                              \
     #_typedArray,                                                              \
     JSCLASS_HAS_RESERVED_SLOTS(TypedArrayLayout::RESERVED_SLOTS) |             \
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |                        \
     JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray),                           \
-    JS_PropertyStub,         /* addProperty */                                 \
-    JS_DeletePropertyStub,   /* delProperty */                                 \
+    nullptr,                 /* addProperty */                                 \
+    nullptr,                 /* delProperty */                                 \
     JS_PropertyStub,         /* getProperty */                                 \
     JS_StrictPropertyStub,   /* setProperty */                                 \
-    JS_EnumerateStub,                                                          \
-    JS_ResolveStub,                                                            \
-    JS_ConvertStub,                                                            \
+    nullptr,                 /* enumerate   */                                 \
+    nullptr,                 /* resolve     */                                 \
+    nullptr,                 /* convert     */                                 \
     nullptr,                 /* finalize    */                                 \
     nullptr,                 /* call        */                                 \
     nullptr,                 /* hasInstance */                                 \
     nullptr,                 /* construct   */                                 \
     TypedArrayObject::trace, /* trace  */                                      \
     TYPED_ARRAY_CLASS_SPEC(_typedArray)                                        \
 }
 
@@ -1799,28 +1799,28 @@ const Class TypedArrayObject::classes[Sc
      * Actually ({}).toString.call(Uint8Array.prototype) should throw, because
      * Uint8Array.prototype lacks the the typed array internal slots.  (Same as
      * with %TypedArray%.prototype.)  It's not clear this is desirable (see
      * above), but it's what we've always done, so keep doing it til we
      * implement @@toStringTag or ES6 changes.
      */ \
     #typedArray "Prototype", \
     JSCLASS_HAS_CACHED_PROTO(JSProto_##typedArray), \
-    JS_PropertyStub,        /* addProperty */ \
-    JS_DeletePropertyStub,  /* delProperty */ \
+    nullptr,                /* addProperty */ \
+    nullptr,                /* delProperty */ \
     JS_PropertyStub,        /* getProperty */ \
     JS_StrictPropertyStub,  /* setProperty */ \
-    JS_EnumerateStub, \
-    JS_ResolveStub, \
-    JS_ConvertStub, \
-    nullptr,                 /* finalize    */ \
-    nullptr,                 /* call        */ \
-    nullptr,                 /* hasInstance */ \
-    nullptr,                 /* construct   */ \
-    nullptr,                 /* trace  */ \
+    nullptr,                /* enumerate   */ \
+    nullptr,                /* resolve     */ \
+    nullptr,                /* convert     */ \
+    nullptr,                /* finalize    */ \
+    nullptr,                /* call        */ \
+    nullptr,                /* hasInstance */ \
+    nullptr,                /* construct   */ \
+    nullptr,                /* trace  */ \
     { \
         typedArray::createConstructor, \
         typedArray::createPrototype, \
         nullptr, \
         nullptr, \
         nullptr, \
         nullptr, \
         JSProto_TypedArray \
@@ -1845,43 +1845,40 @@ TypedArrayObject::isOriginalLengthGetter
     return native == TypedArray_lengthGetter;
 }
 
 const Class DataViewObject::protoClass = {
     "DataViewPrototype",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(TypedArrayLayout::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub    /* setProperty */
 };
 
 const Class DataViewObject::class_ = {
     "DataView",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(TypedArrayLayout::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
+    nullptr,                 /* addProperty */
+    nullptr,                 /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,                 /* finalize */
+    nullptr,                 /* enumerate   */
+    nullptr,                 /* resolve     */
+    nullptr,                 /* convert     */
+    nullptr,                 /* finalize    */
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
-    ArrayBufferViewObject::trace, /* trace       */
+    ArrayBufferViewObject::trace
 };
 
 const JSFunctionSpec DataViewObject::jsfuncs[] = {
     JS_FN("getInt8",    DataViewObject::fun_getInt8,      1,0),
     JS_FN("getUint8",   DataViewObject::fun_getUint8,     1,0),
     JS_FN("getInt16",   DataViewObject::fun_getInt16,     2,0),
     JS_FN("getUint16",  DataViewObject::fun_getUint16,    2,0),
     JS_FN("getInt32",   DataViewObject::fun_getInt32,     2,0),
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -52,23 +52,20 @@ using namespace JS;
 
 // This JSClass exists to trick silly code that expects toString()ing the
 // global in a component scope to return something with "BackstagePass" in it
 // to continue working.
 static const JSClass kFakeBackstagePassJSClass =
 {
     "FakeBackstagePass",
     0,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    nullptr,
+    nullptr,
     JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
+    JS_StrictPropertyStub
 };
 
 static const char kXPConnectServiceContractID[] = "@mozilla.org/js/xpc/XPConnect;1";
 static const char kObserverServiceContractID[] = "@mozilla.org/observer-service;1";
 static const char kJSCachePrefix[] = "jsloader";
 
 #define HAVE_PR_MEMMAP
 
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -338,17 +338,17 @@ sandbox_moved(JSObject *obj, const JSObj
 static bool
 sandbox_convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp)
 {
     if (type == JSTYPE_OBJECT) {
         vp.set(OBJECT_TO_JSVAL(obj));
         return true;
     }
 
-    return JS_ConvertStub(cx, obj, type, vp);
+    return JS::OrdinaryToPrimitive(cx, obj, type, vp);
 }
 
 static bool
 writeToProto_setProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                     bool strict, JS::MutableHandleValue vp)
 {
     RootedObject proto(cx);
     if (!JS_GetPrototype(cx, obj, &proto))
@@ -454,17 +454,17 @@ sandbox_addProperty(JSContext *cx, Handl
     return true;
 }
 
 #define XPCONNECT_SANDBOX_CLASS_METADATA_SLOT (XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET)
 
 static const js::Class SandboxClass = {
     "Sandbox",
     XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
-    JS_PropertyStub,   JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
     sandbox_enumerate, sandbox_resolve, sandbox_convert,  sandbox_finalize,
     nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
     JS_NULL_CLASS_SPEC,
     {
       nullptr,      /* outerObject */
       nullptr,      /* innerObject */
       false,        /* isWrappedNative */
       nullptr,      /* weakmapKeyDelegateOp */
@@ -473,17 +473,17 @@ static const js::Class SandboxClass = {
     JS_NULL_OBJECT_OPS
 };
 
 // Note to whomever comes here to remove addProperty hooks: billm has promised
 // to do the work for this class.
 static const js::Class SandboxWriteToProtoClass = {
     "Sandbox",
     XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
-    sandbox_addProperty,   JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    sandbox_addProperty, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
     sandbox_enumerate, sandbox_resolve, sandbox_convert,  sandbox_finalize,
     nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
     JS_NULL_CLASS_SPEC,
     {
       nullptr,      /* outerObject */
       nullptr,      /* innerObject */
       false,        /* isWrappedNative */
       nullptr,      /* weakmapKeyDelegateOp */
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -767,20 +767,19 @@ env_resolve(JSContext *cx, HandleObject 
         }
         *resolvedp = true;
     }
     return true;
 }
 
 static const JSClass env_class = {
     "environment", JSCLASS_HAS_PRIVATE,
-    JS_PropertyStub,  JS_DeletePropertyStub,
-    JS_PropertyStub,  env_setProperty,
-    env_enumerate, env_resolve,
-    JS_ConvertStub,   nullptr
+    nullptr, nullptr,
+    JS_PropertyStub, env_setProperty,
+    env_enumerate, env_resolve
 };
 
 /***************************************************************************/
 
 typedef enum JSShellErrNum {
 #define MSG_DEF(name, number, count, exception, format) \
     name = number,
 #include "jsshell.msg"
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1420,23 +1420,23 @@ nsXPCWrappedJSClass::GetInterfaceName()
 static void
 FinalizeStub(JSFreeOp *fop, JSObject *obj)
 {
 }
 
 static const JSClass XPCOutParamClass = {
     "XPCOutParam",
     0,
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
+    nullptr,
+    nullptr,
     JS_PropertyStub,
     JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
+    nullptr,   /* enumerate */
+    nullptr,   /* resolve */
+    nullptr,   /* convert */
     FinalizeStub,
     nullptr,   /* call */
     nullptr,   /* hasInstance */
     nullptr,   /* construct */
     nullptr    /* trace */
 };
 
 bool
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -799,21 +799,18 @@ XPCWrappedNative::Init(HandleObject pare
     const JSClass* jsclazz = si ? si->GetJSClass() : Jsvalify(&XPC_WN_NoHelper_JSClass.base);
 
     // We should have the global jsclass flag if and only if we're a global.
     MOZ_ASSERT_IF(si, !!si->GetFlags().IsGlobalObject() == !!(jsclazz->flags & JSCLASS_IS_GLOBAL));
 
     MOZ_ASSERT(jsclazz &&
                jsclazz->name &&
                jsclazz->flags &&
-               jsclazz->addProperty &&
-               jsclazz->delProperty &&
                jsclazz->getProperty &&
                jsclazz->setProperty &&
-               jsclazz->enumerate &&
                jsclazz->resolve &&
                jsclazz->convert &&
                jsclazz->finalize, "bad class");
 
     RootedObject protoJSObject(cx, HasProto() ?
                                    GetProto()->GetJSProtoObject() :
                                    JS_GetObjectPrototype(cx, parent));
     if (!protoJSObject) {
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -1096,28 +1096,28 @@ XPCNativeScriptableShared::PopulateJSCla
 
     if (mFlags.IsGlobalObject())
         mJSClass.base.flags |= XPCONNECT_GLOBAL_FLAGS;
 
     JSPropertyOp addProperty;
     if (mFlags.WantAddProperty())
         addProperty = XPC_WN_Helper_AddProperty;
     else if (mFlags.UseJSStubForAddProperty())
-        addProperty = JS_PropertyStub;
+        addProperty = nullptr;
     else if (mFlags.AllowPropModsDuringResolve())
         addProperty = XPC_WN_MaybeResolvingPropertyStub;
     else
         addProperty = XPC_WN_CannotModifyPropertyStub;
     mJSClass.base.addProperty = addProperty;
 
     JSDeletePropertyOp delProperty;
     if (mFlags.WantDelProperty())
         delProperty = XPC_WN_Helper_DelProperty;
     else if (mFlags.UseJSStubForDelProperty())
-        delProperty = JS_DeletePropertyStub;
+        delProperty = nullptr;
     else if (mFlags.AllowPropModsDuringResolve())
         delProperty = XPC_WN_MaybeResolvingDeletePropertyStub;
     else
         delProperty = XPC_WN_CantDeletePropertyStub;
     mJSClass.base.delProperty = delProperty;
 
     if (mFlags.WantGetProperty())
         mJSClass.base.getProperty = XPC_WN_Helper_GetProperty;
@@ -1134,17 +1134,17 @@ XPCNativeScriptableShared::PopulateJSCla
     else
         setProperty = XPC_WN_CannotModifyStrictPropertyStub;
     mJSClass.base.setProperty = setProperty;
 
     // We figure out most of the enumerate strategy at call time.
 
     if (mFlags.WantNewEnumerate() || mFlags.WantEnumerate() ||
         mFlags.DontEnumStaticProps())
-        mJSClass.base.enumerate = JS_EnumerateStub;
+        mJSClass.base.enumerate = nullptr;
     else
         mJSClass.base.enumerate = XPC_WN_Shared_Enumerate;
 
     // We have to figure out resolve strategy at call time
     mJSClass.base.resolve = XPC_WN_Helper_Resolve;
 
     if (mFlags.WantConvert())
         mJSClass.base.convert = XPC_WN_Helper_Convert;
@@ -1387,49 +1387,49 @@ XPC_WN_ModsAllowed_Proto_Resolve(JSConte
         nullptr,    /* weakmapKeyDelegateOp */                         \
         XPC_WN_Shared_Proto_ObjectMoved                                \
     }
 
 const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
     "XPC_WN_ModsAllowed_WithCall_Proto_JSClass", // name;
     WRAPPER_SLOTS, // flags;
 
-    /* Mandatory non-null function pointer members. */
-    JS_PropertyStub,                // addProperty;
-    JS_DeletePropertyStub,          // delProperty;
+    /* Function pointer members. */
+    nullptr,                        // addProperty;
+    nullptr,                        // delProperty;
     JS_PropertyStub,                // getProperty;
     JS_StrictPropertyStub,          // setProperty;
     XPC_WN_Shared_Proto_Enumerate,  // enumerate;
     XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
-    JS_ConvertStub,                 // convert;
+    nullptr,                        // convert;
     XPC_WN_Shared_Proto_Finalize,   // finalize;
 
     /* Optionally non-null members start here. */
-    nullptr,                         // call;
-    nullptr,                         // construct;
-    nullptr,                         // hasInstance;
+    nullptr,                        // call;
+    nullptr,                        // construct;
+    nullptr,                        // hasInstance;
     XPC_WN_Shared_Proto_Trace,      // trace;
 
     JS_NULL_CLASS_SPEC,
     XPC_WN_SHARED_PROTO_CLASS_EXT,
     XPC_WN_WithCall_ObjectOps
 };
 
 const js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = {
     "XPC_WN_ModsAllowed_NoCall_Proto_JSClass", // name;
     WRAPPER_SLOTS,                  // flags;
 
-    /* Mandatory non-null function pointer members. */
-    JS_PropertyStub,                // addProperty;
-    JS_DeletePropertyStub,          // delProperty;
+    /* Function pointer members. */
+    nullptr,                        // addProperty;
+    nullptr,                        // delProperty;
     JS_PropertyStub,                // getProperty;
     JS_StrictPropertyStub,          // setProperty;
     XPC_WN_Shared_Proto_Enumerate,  // enumerate;
     XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
-    JS_ConvertStub,                 // convert;
+    nullptr,                        // convert;
     XPC_WN_Shared_Proto_Finalize,   // finalize;
 
     /* Optionally non-null members start here. */
     nullptr,                         // call;
     nullptr,                         // construct;
     nullptr,                         // hasInstance;
     XPC_WN_Shared_Proto_Trace,      // trace;
 
@@ -1506,17 +1506,17 @@ const js::Class XPC_WN_NoMods_WithCall_P
 
     /* Mandatory non-null function pointer members. */
     XPC_WN_OnlyIWrite_Proto_AddPropertyStub,   // addProperty;
     XPC_WN_CantDeletePropertyStub,             // delProperty;
     JS_PropertyStub,                           // getProperty;
     XPC_WN_OnlyIWrite_Proto_SetPropertyStub,   // setProperty;
     XPC_WN_Shared_Proto_Enumerate,             // enumerate;
     XPC_WN_NoMods_Proto_Resolve,               // resolve;
-    JS_ConvertStub,                            // convert;
+    nullptr,                                   // convert;
     XPC_WN_Shared_Proto_Finalize,              // finalize;
 
     /* Optionally non-null members start here. */
     nullptr,                         // call;
     nullptr,                         // construct;
     nullptr,                         // hasInstance;
     XPC_WN_Shared_Proto_Trace,      // trace;
 
@@ -1531,17 +1531,17 @@ const js::Class XPC_WN_NoMods_NoCall_Pro
 
     /* Mandatory non-null function pointer members. */
     XPC_WN_OnlyIWrite_Proto_AddPropertyStub,   // addProperty;
     XPC_WN_CantDeletePropertyStub,             // delProperty;
     JS_PropertyStub,                           // getProperty;
     XPC_WN_OnlyIWrite_Proto_SetPropertyStub,   // setProperty;
     XPC_WN_Shared_Proto_Enumerate,             // enumerate;
     XPC_WN_NoMods_Proto_Resolve,               // resolve;
-    JS_ConvertStub,                            // convert;
+    nullptr,                                   // convert;
     XPC_WN_Shared_Proto_Finalize,              // finalize;
 
     /* Optionally non-null members start here. */
     nullptr,                         // call;
     nullptr,                         // construct;
     nullptr,                         // hasInstance;
     XPC_WN_Shared_Proto_Trace,      // trace;
 
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -140,27 +140,23 @@ XrayTraits::setExpandoChain(JSContext *c
 XPCWrappedNative *
 XPCWrappedNativeXrayTraits::getWN(JSObject *wrapper)
 {
     return XPCWrappedNative::Get(getTargetObject(wrapper));
 }
 
 const JSClass XPCWrappedNativeXrayTraits::HolderClass = {
     "NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(2),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub,
-    JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub,
-    JS_ConvertStub
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 
 const JSClass JSXrayTraits::HolderClass = {
     "JSXrayHolder", JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub,
-    JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
 };
 
 bool
 OpaqueXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper, HandleObject wrapper,
                                      HandleObject holder, HandleId id,
                                      MutableHandle<JSPropertyDescriptor> desc)
 {
     bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder, id, desc);
@@ -846,18 +842,18 @@ ExpandoObjectFinalize(JSFreeOp *fop, JSO
     // Release the principal.
     nsIPrincipal *principal = GetExpandoObjectPrincipal(obj);
     NS_RELEASE(principal);
 }
 
 const JSClass ExpandoObjectClass = {
     "XrayExpandoObject",
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_EXPANDO_COUNT),
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ExpandoObjectFinalize
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+    nullptr, nullptr, nullptr, ExpandoObjectFinalize
 };
 
 bool
 XrayTraits::expandoObjectMatchesConsumer(JSContext *cx,
                                          HandleObject expandoObject,
                                          nsIPrincipal *consumerOrigin,
                                          HandleObject exclusiveGlobal)
 {
--- a/netwerk/base/src/ProxyAutoConfig.cpp
+++ b/netwerk/base/src/ProxyAutoConfig.cpp
@@ -598,18 +598,18 @@ private:
 
     return NS_OK;
   }
 };
 
 const JSClass JSRuntimeWrapper::sGlobalClass = {
   "PACResolutionThreadGlobal",
   JSCLASS_GLOBAL_FLAGS,
-  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+  nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
+  nullptr, nullptr, nullptr,
   nullptr, nullptr, nullptr, nullptr,
   JS_GlobalObjectTraceHook
 };
 
 void
 ProxyAutoConfig::SetThreadLocalIndex(uint32_t index)
 {
   sRunningIndex = index;
--- a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
+++ b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
@@ -110,23 +110,23 @@ void Finalize(JSFreeOp *fop, JSObject *o
   (void)NS_DispatchToMainThread(event);
   // We may fail at dispatching to the main thread if we arrive too late
   // during shutdown. In that case, there is not much we can do.
 }
 
 static const JSClass sWitnessClass = {
   "FinalizationWitness",
   JSCLASS_HAS_RESERVED_SLOTS(WITNESS_INSTANCES_SLOTS),
-  JS_PropertyStub /* addProperty */,
-  JS_DeletePropertyStub /* delProperty */,
+  nullptr /* addProperty */,
+  nullptr /* delProperty */,
   JS_PropertyStub /* getProperty */,
   JS_StrictPropertyStub /* setProperty */,
-  JS_EnumerateStub /* enumerate */,
-  JS_ResolveStub /* resolve */,
-  JS_ConvertStub /* convert */,
+  nullptr /* enumerate */,
+  nullptr /* resolve */,
+  nullptr /* convert */,
   Finalize /* finalize */
 };
 
 bool IsWitness(JS::Handle<JS::Value> v)
 {
   return v.isObject() && JS_GetClass(&v.toObject()) == &sWitnessClass;
 }
 
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -1263,18 +1263,17 @@ JSHistogram_Clear(JSContext *cx, unsigne
 }
 
 nsresult
 WrapAndReturnHistogram(Histogram *h, JSContext *cx, JS::MutableHandle<JS::Value> ret)
 {
   static const JSClass JSHistogram_class = {
     "JSHistogram",  /* name */
     JSCLASS_HAS_PRIVATE, /* flags */
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
   };
 
   JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &JSHistogram_class, JS::NullPtr(), JS::NullPtr()));
   if (!obj)
     return NS_ERROR_FAILURE;
   if (!(JS_DefineFunction(cx, obj, "add", JSHistogram_Add, 1, 0)
         && JS_DefineFunction(cx, obj, "snapshot", JSHistogram_Snapshot, 0, 0)
         && JS_DefineFunction(cx, obj, "clear", JSHistogram_Clear, 0, 0))) {
@@ -1441,18 +1440,17 @@ JSKeyedHistogram_Clear(JSContext *cx, un
 }
 
 nsresult
 WrapAndReturnKeyedHistogram(KeyedHistogram *h, JSContext *cx, JS::MutableHandle<JS::Value> ret)
 {
   static const JSClass JSHistogram_class = {
     "JSKeyedHistogram",  /* name */
     JSCLASS_HAS_PRIVATE, /* flags */
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub
   };
 
   JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &JSHistogram_class, JS::NullPtr(), JS::NullPtr()));
   if (!obj)
     return NS_ERROR_FAILURE;
   if (!(JS_DefineFunction(cx, obj, "add", JSKeyedHistogram_Add, 2, 0)
         && JS_DefineFunction(cx, obj, "snapshot", JSKeyedHistogram_Snapshot, 1, 0)
         && JS_DefineFunction(cx, obj, "keys", JSKeyedHistogram_Keys, 0, 0)
--- a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
+++ b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
@@ -85,19 +85,19 @@ RunTest(JSRuntime* rt, JSContext* cx, Ar
   JS_RemoveExtraGCRootsTracer(rt, TraceArray<ArrayT>, array);
 }
 
 static void
 CreateGlobalAndRunTest(JSRuntime* rt, JSContext* cx)
 {
   static const JSClass GlobalClass = {
     "global", JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+    nullptr, nullptr, JS_PropertyStub, JS_StrictPropertyStub,
     nullptr, nullptr, nullptr, nullptr,
+    nullptr, nullptr, nullptr,
     JS_GlobalObjectTraceHook
   };
 
   JS::CompartmentOptions options;
   options.setVersion(JSVERSION_LATEST);
   JS::PersistentRootedObject global(cx);
   global = JS_NewGlobalObject(cx, &GlobalClass, nullptr, JS::FireOnNewGlobalHook, options);
   ASSERT_TRUE(global != nullptr);