Bug 1321374 - Simplify js::Class handling relating to nsIXPCScriptable. r=mccr8, sr=bholley, a=lizzard
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 21 Dec 2016 10:29:52 +1100
changeset 357015 be751ea19d464d51be7d36bd2a0fd6a72029dc02
parent 357014 0ef9b3667a0664b6496f565b567f9705e0c6e462
child 357016 73f6920fed067f54692a3a4987bab2b7da0c9138
push id6713
push userryanvm@gmail.com
push dateFri, 30 Dec 2016 02:48:30 +0000
treeherdermozilla-beta@c0b69901edd1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, bholley, lizzard
bugs1321374
milestone51.0
Bug 1321374 - Simplify js::Class handling relating to nsIXPCScriptable. r=mccr8, sr=bholley, a=lizzard This patch removes XPCNativeScriptableShared and XPCNativeScriptableSharedMap, which results in a net reduction of ~100 lines of code.
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
js/xpconnect/idl/nsIXPCScriptable.idl
js/xpconnect/public/moz.build
js/xpconnect/public/xpc_make_class.h
js/xpconnect/public/xpc_map_end.h
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCForwards.h
js/xpconnect/src/XPCJSContext.cpp
js/xpconnect/src/XPCJSID.cpp
js/xpconnect/src/XPCMaps.cpp
js/xpconnect/src/XPCMaps.h
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
storage/mozStorageAsyncStatementJSHelper.cpp
storage/mozStorageAsyncStatementParams.cpp
storage/mozStorageStatementJSHelper.cpp
storage/mozStorageStatementRow.cpp
toolkit/components/ctypes/ctypes.cpp
toolkit/components/perf/PerfMeasurement.cpp
toolkit/components/reflect/reflect.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -14,16 +14,17 @@
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "WrapperFactory.h"
 #include "AccessCheck.h"
 #include "XrayWrapper.h"
 
 #include "xpcpublic.h"
 #include "xpcprivate.h"
+#include "xpc_make_class.h"
 #include "XPCWrapper.h"
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/RegisterBindings.h"
 
 #include "nscore.h"
 #include "nsDOMClassInfo.h"
 #include "nsIDOMClassInfo.h"
@@ -133,16 +134,19 @@ using namespace mozilla::dom;
 #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                \
   // nothing
 #endif
 
 #define NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags,              \
                                         _chromeOnly, _allowXBL)               \
   { #_class,                                                                  \
     nullptr,                                                                  \
+    XPC_MAKE_CLASS_OPS(_flags),                                               \
+    XPC_MAKE_CLASS(#_class, _flags,                                           \
+                   &sClassInfoData[eDOMClassInfo_##_class##_id].mClassOps),   \
     _helper::doCreate,                                                        \
     nullptr,                                                                  \
     nullptr,                                                                  \
     nullptr,                                                                  \
     _flags,                                                                   \
     true,                                                                     \
     _chromeOnly,                                                              \
     _allowXBL,                                                                \
@@ -783,16 +787,23 @@ nsDOMClassInfo::GetClassName(char **aCla
 
 // virtual
 uint32_t
 nsDOMClassInfo::GetScriptableFlags()
 {
   return mData->mScriptableFlags;
 }
 
+// virtual
+const js::Class*
+nsDOMClassInfo::GetClass()
+{
+    return &mData->mClass;
+}
+
 NS_IMETHODIMP
 nsDOMClassInfo::PreCreate(nsISupports *nativeObj, JSContext *cx,
                           JSObject *globalObj, JSObject **parentObj)
 {
   *parentObj = globalObj;
   return NS_OK;
 }
 
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -6,16 +6,17 @@
 
 #ifndef nsDOMClassInfo_h___
 #define nsDOMClassInfo_h___
 
 #include "mozilla/Attributes.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIXPCScriptable.h"
 #include "nsIScriptGlobalObject.h"
+#include "js/Class.h"
 #include "js/Id.h"
 #include "nsIXPConnect.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 struct nsGlobalNameStruct;
@@ -25,18 +26,22 @@ struct nsDOMClassInfoData;
 
 typedef nsIClassInfo* (*nsDOMClassInfoConstructorFnc)
   (nsDOMClassInfoData* aData);
 
 typedef nsresult (*nsDOMConstructorFunc)(nsISupports** aNewObject);
 
 struct nsDOMClassInfoData
 {
+  // XXX: mName is the same as the name gettable from the callback. This
+  // redundancy should be removed eventually.
   const char *mName;
   const char16_t *mNameUTF16;
+  const js::ClassOps mClassOps;
+  const js::Class mClass;
   nsDOMClassInfoConstructorFnc mConstructorFptr;
 
   nsIClassInfo *mCachedClassInfo;
   const nsIID *mProtoChainInterface;
   const nsIID **mInterfaces;
   uint32_t mScriptableFlags : 31; // flags must not use more than 31 bits!
   uint32_t mHasClassInterface : 1;
   bool mChromeOnly : 1;
--- a/js/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/xpconnect/idl/nsIXPCScriptable.idl
@@ -10,26 +10,30 @@
 %{C++
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 #include "js/TypeDecls.h"
 
 struct JSFreeOp;
+namespace js {
+struct Class;
+}
 %}
 
 interface nsIXPConnectWrappedNative;
 
 [ptr] native JSContextPtr(JSContext);
 [ptr] native JSObjectPtr(JSObject);
 [ptr] native JSValPtr(JS::Value);
 [ptr] native JSFreeOpPtr(JSFreeOp);
 [ref] native JSCallArgsRef(const JS::CallArgs);
 [ref] native JSAutoIdVector(JS::AutoIdVector);
+[ptr] native jsClassPtr(const js::Class);
 
 /**
  * Note: This is not really an XPCOM interface.  For example, callers must
  * guarantee that they set the *_retval of the various methods that return a
  * boolean to PR_TRUE before making the call.  Implementations may skip writing
  * to *_retval unless they want to return PR_FALSE.
  */
 [uuid(19b70b26-7c3f-437f-a04a-2a8f9e28b617)]
@@ -68,16 +72,17 @@ interface nsIXPCScriptable : nsISupports
 
     // The high order bit is RESERVED for consumers of these flags. 
     // No implementor of this interface should ever return flags 
     // with this bit set.
     const uint32_t RESERVED                         = 1 << 31;
 
     readonly attribute string   className;
     [notxpcom,nostdcall] uint32_t getScriptableFlags();
+    [notxpcom,nostdcall] jsClassPtr getClass();
 
     void   preCreate(in nsISupports nativeObj, in JSContextPtr cx,
                      in JSObjectPtr globalObj, out JSObjectPtr parentObj);
 
     boolean addProperty(in nsIXPConnectWrappedNative wrapper,
                        in JSContextPtr cx, in JSObjectPtr obj, in jsid id,
                        in jsval val);
 
--- a/js/xpconnect/public/moz.build
+++ b/js/xpconnect/public/moz.build
@@ -2,11 +2,12 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS += [
     'nsAXPCNativeCallContext.h',
     'nsTArrayHelpers.h',
+    'xpc_make_class.h',
     'xpc_map_end.h',
 ]
 
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/public/xpc_make_class.h
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef xpc_make_class_h
+#define xpc_make_class_h
+
+// This file should be used to create js::Class instances for nsIXPCScriptable
+// instances. This includes any file that uses xpc_map_end.h.
+
+#include "xpcpublic.h"
+#include "mozilla/dom/DOMJSClass.h"
+
+bool
+XPC_WN_MaybeResolvingPropertyStub(JSContext* cx, JS::HandleObject obj,
+                                  JS::HandleId id, JS::HandleValue v);
+bool
+XPC_WN_CannotModifyPropertyStub(JSContext* cx, JS::HandleObject obj,
+                                JS::HandleId id, JS::HandleValue v);
+
+bool
+XPC_WN_MaybeResolvingDeletePropertyStub(JSContext* cx, JS::HandleObject obj,
+                                        JS::HandleId id,
+                                        JS::ObjectOpResult& result);
+bool
+XPC_WN_CantDeletePropertyStub(JSContext* cx, JS::HandleObject obj,
+                              JS::HandleId id, JS::ObjectOpResult& result);
+
+bool
+XPC_WN_Helper_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
+                          JS::MutableHandleValue vp);
+
+bool
+XPC_WN_Helper_SetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
+                          JS::MutableHandleValue vp,
+                          JS::ObjectOpResult& result);
+bool
+XPC_WN_MaybeResolvingSetPropertyStub(JSContext* cx, JS::HandleObject obj,
+                                     JS::HandleId id, JS::MutableHandleValue vp,
+                                     JS::ObjectOpResult& result);
+bool
+XPC_WN_CannotModifySetPropertyStub(JSContext* cx, JS::HandleObject obj,
+                                   JS::HandleId id, JS::MutableHandleValue vp,
+                                   JS::ObjectOpResult& result);
+
+bool
+XPC_WN_Helper_Enumerate(JSContext* cx, JS::HandleObject obj);
+bool
+XPC_WN_Shared_Enumerate(JSContext* cx, JS::HandleObject obj);
+
+bool
+XPC_WN_Helper_Resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
+                      bool* resolvedp);
+
+void
+XPC_WN_Helper_Finalize(js::FreeOp* fop, JSObject* obj);
+void
+XPC_WN_NoHelper_Finalize(js::FreeOp* fop, JSObject* obj);
+
+bool
+XPC_WN_Helper_Call(JSContext* cx, unsigned argc, JS::Value* vp);
+
+bool
+XPC_WN_Helper_HasInstance(JSContext* cx, JS::HandleObject obj,
+                          JS::MutableHandleValue valp, bool* bp);
+
+bool
+XPC_WN_Helper_Construct(JSContext* cx, unsigned argc, JS::Value* vp);
+
+void
+XPCWrappedNative_Trace(JSTracer* trc, JSObject* obj);
+
+extern const js::ClassExtension XPC_WN_JSClassExtension;
+
+extern const js::ObjectOps XPC_WN_ObjectOpsWithEnumerate;
+
+#define XPC_MAKE_CLASS_OPS(_flags) { \
+    /* addProperty */ \
+    ((_flags) & nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY) \
+    ? nullptr \
+    : ((_flags) & nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE) \
+      ? XPC_WN_MaybeResolvingPropertyStub \
+      : XPC_WN_CannotModifyPropertyStub, \
+    \
+    /* delProperty */ \
+    ((_flags) & nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY) \
+    ? nullptr \
+    : ((_flags) & nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE) \
+      ? XPC_WN_MaybeResolvingDeletePropertyStub \
+      : XPC_WN_CantDeletePropertyStub, \
+    \
+    /* getProperty */ \
+    ((_flags) & nsIXPCScriptable::WANT_GETPROPERTY) \
+    ? XPC_WN_Helper_GetProperty \
+    : nullptr, \
+    \
+    /* setProperty */ \
+    ((_flags) & nsIXPCScriptable::WANT_SETPROPERTY) \
+    ? XPC_WN_Helper_SetProperty \
+    : ((_flags) & nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY) \
+      ? nullptr \
+      : ((_flags) & nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE) \
+        ? XPC_WN_MaybeResolvingSetPropertyStub \
+        : XPC_WN_CannotModifySetPropertyStub, \
+    \
+    /* enumerate */ \
+    ((_flags) & nsIXPCScriptable::WANT_NEWENUMERATE) \
+    ? nullptr /* We will use oOps->enumerate set below in this case */ \
+    : ((_flags) & nsIXPCScriptable::WANT_ENUMERATE) \
+      ? XPC_WN_Helper_Enumerate \
+      : XPC_WN_Shared_Enumerate, \
+    \
+    /* resolve */ \
+    /* We have to figure out resolve strategy at call time */ \
+    XPC_WN_Helper_Resolve, \
+    \
+    /* mayResolve */ \
+    nullptr, \
+    \
+    /* finalize */ \
+    ((_flags) & nsIXPCScriptable::WANT_FINALIZE) \
+    ? XPC_WN_Helper_Finalize \
+    : XPC_WN_NoHelper_Finalize, \
+    \
+    /* call */ \
+    ((_flags) & nsIXPCScriptable::WANT_CALL) \
+    ? XPC_WN_Helper_Call \
+    : nullptr, \
+    \
+    /* hasInstance */ \
+    ((_flags) & nsIXPCScriptable::WANT_HASINSTANCE) \
+    ? XPC_WN_Helper_HasInstance \
+    : nullptr, \
+    \
+    /* construct */ \
+    ((_flags) & nsIXPCScriptable::WANT_CONSTRUCT) \
+    ? XPC_WN_Helper_Construct \
+    : nullptr, \
+    \
+    /* trace */ \
+    ((_flags) & nsIXPCScriptable::IS_GLOBAL_OBJECT) \
+    ? JS_GlobalObjectTraceHook \
+    : XPCWrappedNative_Trace, \
+}
+
+#define XPC_MAKE_CLASS(_name, _flags, _classOps) { \
+    /* name */ \
+    _name, \
+    \
+    /* flags */ \
+    XPC_WRAPPER_FLAGS | \
+    JSCLASS_PRIVATE_IS_NSISUPPORTS | \
+    JSCLASS_IS_WRAPPED_NATIVE | \
+    (((_flags) & nsIXPCScriptable::IS_GLOBAL_OBJECT) \
+     ? XPCONNECT_GLOBAL_FLAGS \
+     : 0), \
+    \
+    /* cOps */ \
+    _classOps, \
+    \
+    /* spec */ \
+    nullptr, \
+    \
+    /* ext */ \
+    &XPC_WN_JSClassExtension, \
+    \
+    /* oOps */ \
+    ((_flags) & nsIXPCScriptable::WANT_NEWENUMERATE) \
+    ? &XPC_WN_ObjectOpsWithEnumerate \
+    : nullptr, \
+}
+
+#endif
--- a/js/xpconnect/public/xpc_map_end.h
+++ b/js/xpconnect/public/xpc_map_end.h
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+// If you include this file you must also include xpc_make_class.h at the top
+// of the file doing the including.
 
 #ifndef XPC_MAP_CLASSNAME
 #error "Must #define XPC_MAP_CLASSNAME before #including xpc_map_end.h"
 #endif
 
 #ifndef XPC_MAP_QUOTED_CLASSNAME
 #error "Must #define XPC_MAP_QUOTED_CLASSNAME before #including xpc_map_end.h"
 #endif
@@ -65,16 +67,28 @@ XPC_MAP_CLASSNAME::GetScriptableFlags()
     nsIXPCScriptable::WANT_HASINSTANCE |
 #endif
 #ifdef XPC_MAP_FLAGS
     XPC_MAP_FLAGS |
 #endif
     0;
 }
 
+// virtual
+const js::Class*
+XPC_MAP_CLASSNAME::GetClass()
+{
+    static const js::ClassOps classOps =
+        XPC_MAKE_CLASS_OPS(GetScriptableFlags());
+    static const js::Class klass =
+        XPC_MAKE_CLASS(XPC_MAP_QUOTED_CLASSNAME, GetScriptableFlags(),
+                       &classOps);
+    return &klass;
+}
+
 /**************************************************************/
 
 #ifndef XPC_MAP_WANT_PRECREATE
 NS_IMETHODIMP XPC_MAP_CLASSNAME::PreCreate(nsISupports* nativeObj, JSContext * cx, JSObject * globalObj, JSObject * *parentObj)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_ADDPROPERTY
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -18,16 +18,17 @@
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIURI.h"
 #include "nsJSUtils.h"
 #include "nsNetUtil.h"
 #include "nsNullPrincipal.h"
 #include "nsPrincipal.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
+#include "xpc_make_class.h"
 #include "XPCWrapper.h"
 #include "XrayWrapper.h"
 #include "Crypto.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/cache/CacheStorage.h"
 #include "mozilla/dom/CSSBinding.h"
 #include "mozilla/dom/DirectoryBinding.h"
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* The "Components" xpcom objects for JavaScript. */
 
 #include "xpcprivate.h"
+#include "xpc_make_class.h"
 #include "xpcIJSModuleLoader.h"
 #include "XPCJSWeakReference.h"
 #include "WrapperFactory.h"
 #include "nsJSUtils.h"
 #include "mozJSComponentLoader.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "jsfriendapi.h"
--- a/js/xpconnect/src/XPCForwards.h
+++ b/js/xpconnect/src/XPCForwards.h
@@ -23,32 +23,30 @@ class nsXPCWrappedJSClass;
 
 class XPCNativeMember;
 class XPCNativeInterface;
 class XPCNativeSet;
 
 class XPCWrappedNative;
 class XPCWrappedNativeProto;
 class XPCWrappedNativeTearOff;
-class XPCNativeScriptableShared;
 class XPCNativeScriptableInfo;
 class XPCNativeScriptableCreateInfo;
 
 class XPCTraceableVariant;
 class XPCJSObjectHolder;
 
 class JSObject2WrappedJSMap;
 class Native2WrappedNativeMap;
 class IID2WrappedJSClassMap;
 class IID2NativeInterfaceMap;
 class ClassInfo2NativeSetMap;
 class ClassInfo2WrappedNativeProtoMap;
 class NativeSetMap;
 class IID2ThisTranslatorMap;
-class XPCNativeScriptableSharedMap;
 class XPCWrappedNativeProtoMap;
 class JSObject2JSObjectMap;
 
 class nsXPCComponents;
 class nsXPCComponents_Interfaces;
 class nsXPCComponents_InterfacesByID;
 class nsXPCComponents_Classes;
 class nsXPCComponents_ClassesByID;
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -1619,19 +1619,16 @@ XPCJSContext::~XPCJSContext()
     mClassInfo2NativeSetMap = nullptr;
 
     delete mNativeSetMap;
     mNativeSetMap = nullptr;
 
     delete mThisTranslatorMap;
     mThisTranslatorMap = nullptr;
 
-    delete mNativeScriptableSharedMap;
-    mNativeScriptableSharedMap = nullptr;
-
     delete mDyingWrappedNativeProtoMap;
     mDyingWrappedNativeProtoMap = nullptr;
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
     // Tell the profiler that the context is gone
     if (PseudoStack* stack = mozilla_get_pseudo_stack())
         stack->sampleContext(nullptr);
 #endif
@@ -3294,17 +3291,16 @@ XPCJSContext::XPCJSContext()
    mResolveName(JSID_VOID),
    mResolvingWrapper(nullptr),
    mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_LENGTH)),
    mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_LENGTH)),
    mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_LENGTH)),
    mClassInfo2NativeSetMap(ClassInfo2NativeSetMap::newMap(XPC_NATIVE_SET_MAP_LENGTH)),
    mNativeSetMap(NativeSetMap::newMap(XPC_NATIVE_SET_MAP_LENGTH)),
    mThisTranslatorMap(IID2ThisTranslatorMap::newMap(XPC_THIS_TRANSLATOR_MAP_LENGTH)),
-   mNativeScriptableSharedMap(XPCNativeScriptableSharedMap::newMap(XPC_NATIVE_JSCLASS_MAP_LENGTH)),
    mDyingWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DYING_NATIVE_PROTO_MAP_LENGTH)),
    mGCIsRunning(false),
    mNativesToReleaseArray(),
    mDoingFinalization(false),
    mVariantRoots(nullptr),
    mWrappedJSRoots(nullptr),
    mObjectHolderRoots(nullptr),
    mWatchdogManager(new WatchdogManager(this)),
@@ -3534,17 +3530,16 @@ XPCJSContext::newXPCJSContext()
 
     if (self->Context()                         &&
         self->GetMultiCompartmentWrappedJSMap() &&
         self->GetWrappedJSClassMap()            &&
         self->GetIID2NativeInterfaceMap()       &&
         self->GetClassInfo2NativeSetMap()       &&
         self->GetNativeSetMap()                 &&
         self->GetThisTranslatorMap()            &&
-        self->GetNativeScriptableSharedMap()    &&
         self->GetDyingWrappedNativeProtoMap()   &&
         self->mWatchdogManager) {
         return self;
     }
 
     NS_RUNTIMEABORT("new XPCJSContext failed to initialize.");
 
     delete self;
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* An xpcom implementation of the JavaScript nsIID and nsCID objects. */
 
 #include "xpcprivate.h"
+#include "xpc_make_class.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/StaticPtr.h"
 
 using namespace mozilla::dom;
 using namespace JS;
 
--- a/js/xpconnect/src/XPCMaps.cpp
+++ b/js/xpconnect/src/XPCMaps.cpp
@@ -356,115 +356,16 @@ IID2ThisTranslatorMap::newMap(int length
 }
 
 IID2ThisTranslatorMap::IID2ThisTranslatorMap(int length)
   : mTable(&Entry::sOps, sizeof(Entry), length)
 {
 }
 
 /***************************************************************************/
-
-PLDHashNumber
-XPCNativeScriptableSharedMap::Entry::Hash(const void* key)
-{
-    PLDHashNumber h;
-    const unsigned char* s;
-
-    XPCNativeScriptableShared* obj =
-        (XPCNativeScriptableShared*) key;
-
-    // hash together the flags and the classname string, ignore the interfaces
-    // bitmap since it's very rare that it's different when flags and classname
-    // are the same.
-
-    h = (PLDHashNumber) obj->GetFlags();
-    for (s = (const unsigned char*) obj->GetJSClass()->name; *s != '\0'; s++)
-        h = RotateLeft(h, 4) ^ *s;
-    return h;
-}
-
-bool
-XPCNativeScriptableSharedMap::Entry::Match(const PLDHashEntryHdr* entry,
-                                           const void* key)
-{
-    XPCNativeScriptableShared* obj1 =
-        ((XPCNativeScriptableSharedMap::Entry*) entry)->key;
-
-    XPCNativeScriptableShared* obj2 =
-        (XPCNativeScriptableShared*) key;
-
-    // match the flags and the classname string
-
-    if (obj1->GetFlags() != obj2->GetFlags())
-        return false;
-
-    const char* name1 = obj1->GetJSClass()->name;
-    const char* name2 = obj2->GetJSClass()->name;
-
-    if (!name1 || !name2)
-        return name1 == name2;
-
-    return 0 == strcmp(name1, name2);
-}
-
-const struct PLDHashTableOps XPCNativeScriptableSharedMap::Entry::sOps =
-{
-    Hash,
-    Match,
-    PLDHashTable::MoveEntryStub,
-    PLDHashTable::ClearEntryStub
-};
-
-// static
-XPCNativeScriptableSharedMap*
-XPCNativeScriptableSharedMap::newMap(int length)
-{
-    return new XPCNativeScriptableSharedMap(length);
-}
-
-XPCNativeScriptableSharedMap::XPCNativeScriptableSharedMap(int length)
-  : mTable(&Entry::sOps, sizeof(Entry), length)
-{
-}
-
-bool
-XPCNativeScriptableSharedMap::GetNewOrUsed(uint32_t flags,
-                                           char* name,
-                                           XPCNativeScriptableInfo* si)
-{
-    NS_PRECONDITION(name,"bad param");
-    NS_PRECONDITION(si,"bad param");
-
-    RefPtr<XPCNativeScriptableShared> key =
-        new XPCNativeScriptableShared(flags, name, /* populate = */ false);
-    auto entry = static_cast<Entry*>(mTable.Add(key, fallible));
-    if (!entry)
-        return false;
-
-    RefPtr<XPCNativeScriptableShared> shared = entry->key;
-
-    // XXX: this XPCNativeScriptableShared is heap-allocated, which means the
-    // js::Class it contains is also heap-allocated. This causes problems for
-    // memory reporting. See the comment above the BaseShape case in
-    // StatsCellCallback() in js/src/vm/MemoryMetrics.cpp.
-    //
-    // When the code below is removed (bug 1265271) and there are no longer any
-    // heap-allocated js::Class instances, the disabled code in
-    // StatsCellCallback() should be reinstated.
-    //
-    if (!shared) {
-        shared = new XPCNativeScriptableShared(flags, key->TransferNameOwnership(),
-                                               /* populate = */ true);
-        entry->key = shared;
-    }
-    si->SetScriptableShared(shared.forget());
-    return true;
-}
-
-/***************************************************************************/
 // implement XPCWrappedNativeProtoMap...
 
 // static
 XPCWrappedNativeProtoMap*
 XPCWrappedNativeProtoMap::newMap(int length)
 {
     return new XPCWrappedNativeProtoMap(length);
 }
--- a/js/xpconnect/src/XPCMaps.h
+++ b/js/xpconnect/src/XPCMaps.h
@@ -501,51 +501,16 @@ private:
     IID2ThisTranslatorMap();    // no implementation
     explicit IID2ThisTranslatorMap(int size);
 private:
     PLDHashTable mTable;
 };
 
 /***************************************************************************/
 
-class XPCNativeScriptableSharedMap
-{
-public:
-    struct Entry : public PLDHashEntryHdr
-    {
-        // This is a weak reference that will be cleared
-        // in the XPCNativeScriptableShared destructor.
-        XPCNativeScriptableShared* key;
-
-        static PLDHashNumber
-        Hash(const void* key);
-
-        static bool
-        Match(const PLDHashEntryHdr* entry, const void* key);
-
-        static const struct PLDHashTableOps sOps;
-    };
-
-    static XPCNativeScriptableSharedMap* newMap(int length);
-
-    bool GetNewOrUsed(uint32_t flags, char* name, XPCNativeScriptableInfo* si);
-
-    inline uint32_t Count() { return mTable.EntryCount(); }
-
-    void Remove(XPCNativeScriptableShared* key) { mTable.Remove(key); }
-
-private:
-    XPCNativeScriptableSharedMap();    // no implementation
-    explicit XPCNativeScriptableSharedMap(int size);
-private:
-    PLDHashTable mTable;
-};
-
-/***************************************************************************/
-
 class XPCWrappedNativeProtoMap
 {
 public:
     typedef PLDHashEntryStub Entry;
 
     static XPCWrappedNativeProtoMap* newMap(int length);
 
     inline XPCWrappedNativeProto* Add(XPCWrappedNativeProto* proto)
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -217,29 +217,26 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
 
     //
     // We don't call ::Init() on this wrapper, because our setup requirements
     // are different for globals. We do our setup inline here, instead.
     //
 
     // Share mScriptableInfo with the proto.
     //
-    // This is probably more trouble than it's worth, since we've already created
-    // an XPCNativeScriptableInfo for ourselves. Moreover, most of that class is
-    // shared internally via XPCNativeScriptableInfoShared, so the memory
-    // savings are negligible. Nevertheless, this is what ::Init() does, and we
-    // want to be as consistent as possible with that code.
+    // This is probably more trouble than it's worth, since we've already
+    // created an XPCNativeScriptableInfo for ourselves. Nevertheless, this is
+    // what ::Init() does, and we want to be as consistent as possible with
+    // that code.
     XPCNativeScriptableInfo* siProto = proto->GetScriptableInfo();
     if (siProto && siProto->GetCallback() == sciWrapper.GetCallback()) {
         wrapper->mScriptableInfo = siProto;
-        // XPCNativeScriptableShared instances live in a map, and are
-        // GCed, but XPCNativeScriptableInfo is per-instance and must be
-        // manually managed. If we're switching over to that of the proto, we
-        // need to destroy the one we've allocated, and also null out the
-        // AutoMarkingPtr, so that it doesn't try to mark garbage data.
+        // XPCNativeScriptableInfo uses manual memory management. If we're
+        // switching over to that of the proto, we need to destroy the one
+        // we've allocated.
         delete si;
         si = nullptr;
     } else {
         wrapper->mScriptableInfo = si;
     }
 
     // Set the JS object to the global we already created.
     wrapper->mFlatJSObject = global;
@@ -745,18 +742,17 @@ XPCWrappedNative::Init(const XPCNativeSc
 
     if (sci->GetCallback()) {
         if (HasProto()) {
             XPCNativeScriptableInfo* siProto = GetProto()->GetScriptableInfo();
             if (siProto && siProto->GetCallback() == sci->GetCallback())
                 mScriptableInfo = siProto;
         }
         if (!mScriptableInfo) {
-            mScriptableInfo =
-                XPCNativeScriptableInfo::Construct(sci);
+            mScriptableInfo = XPCNativeScriptableInfo::Construct(sci);
 
             if (!mScriptableInfo)
                 return false;
         }
     }
     XPCNativeScriptableInfo* si = mScriptableInfo;
 
     // create our flatJSObject
@@ -966,19 +962,17 @@ XPCWrappedNative::SystemIsBeingShutDown(
     mFlatJSObject = nullptr;
     mFlatJSObject.unsetFlags(FLAT_JS_OBJECT_VALID);
 
     XPCWrappedNativeProto* proto = GetProto();
 
     if (HasProto())
         proto->SystemIsBeingShutDown();
 
-    // Don't destroy mScriptableInfo here because this will release
-    // XPCNativeScriptableShared, which will destroy js::ClassOps
-    // which may still be in use by JS objects.
+    // We don't destroy mScriptableInfo here. The destructor will do it.
 
     // Cleanup the tearoffs.
     for (XPCWrappedNativeTearOff* to = &mFirstTearOff; to; to = to->GetNextTearOff()) {
         if (JSObject* jso = to->GetJSObjectPreserveColor()) {
             JS_SetPrivate(jso, nullptr);
             to->SetJSObject(nullptr);
         }
         // We leak the tearoff mNative
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */
 
 #include "xpcprivate.h"
+#include "xpc_make_class.h"
 #include "jsprf.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsIAddonInterposition.h"
 #include "AddonWrapper.h"
 #include "js/Class.h"
 
 using namespace mozilla;
@@ -465,38 +466,38 @@ XPC_WN_OnlyIWrite_AddPropertyStub(JSCont
 
     // Allow only XPConnect to add/set the property
     if (ccx.GetResolveName() == id)
         return true;
 
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
-static bool
+bool
 XPC_WN_CannotModifyPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
                                 HandleValue v)
 {
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
-static bool
+bool
 XPC_WN_CantDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id,
                               ObjectOpResult& result)
 {
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
-static bool
+bool
 XPC_WN_CannotModifySetPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
                                    MutableHandleValue vp, ObjectOpResult& result)
 {
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
-static bool
+bool
 XPC_WN_Shared_Enumerate(JSContext* cx, HandleObject obj)
 {
     XPCCallContext ccx(cx, obj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
     // Since we aren't going to enumerate tearoff names and the prototype
     // handles non-mutated members, we can do this potential short-circuit.
@@ -558,48 +559,48 @@ WrappedNativeObjectMoved(JSObject* obj, 
     nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
     if (!p)
         return;
 
     XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p);
     wrapper->FlatJSObjectMoved(obj, old);
 }
 
-static void
+void
 XPC_WN_NoHelper_Finalize(js::FreeOp* fop, JSObject* obj)
 {
     WrappedNativeFinalize(fop, obj, WN_NOHELPER);
 }
 
 /*
  * General comment about XPConnect tracing: Given a C++ object |wrapper| and its
  * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS
  * engine to mark |obj|. Eventually, this will lead to the trace hook being
  * called for |obj|. The trace hook should call |wrapper->TraceInside|, which
  * should mark any JS objects held by |wrapper| as members.
  */
 
-static void
-MarkWrappedNative(JSTracer* trc, JSObject* obj)
+/* static */ void
+XPCWrappedNative::Trace(JSTracer* trc, JSObject* obj)
 {
     const js::Class* clazz = js::GetObjectClass(obj);
     if (clazz->flags & JSCLASS_DOM_GLOBAL) {
         mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
     }
     MOZ_ASSERT(IS_WN_CLASS(clazz));
 
     XPCWrappedNative* wrapper = XPCWrappedNative::Get(obj);
     if (wrapper && wrapper->IsValid())
         wrapper->TraceInside(trc);
 }
 
-/* static */ void
-XPCWrappedNative::Trace(JSTracer* trc, JSObject* obj)
+void
+XPCWrappedNative_Trace(JSTracer* trc, JSObject* obj)
 {
-    MarkWrappedNative(trc, obj);
+    XPCWrappedNative::Trace(trc, obj);
 }
 
 static bool
 XPC_WN_NoHelper_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
 {
     XPCCallContext ccx(cx, obj, nullptr, id);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@@ -631,57 +632,57 @@ static const js::ClassOps XPC_WN_NoHelpe
     nullptr,                           // mayResolve
     XPC_WN_NoHelper_Finalize,          // finalize
     nullptr,                           // call
     nullptr,                           // construct
     nullptr,                           // hasInstance
     XPCWrappedNative::Trace,           // trace
 };
 
-static const js::ClassExtension XPC_WN_JSClassExtension = {
+const js::ClassExtension XPC_WN_JSClassExtension = {
     nullptr, // weakmapKeyDelegateOp
     WrappedNativeObjectMoved
 };
 
 const js::Class XPC_WN_NoHelper_JSClass = {
     "XPCWrappedNative_NoHelper",
-    WRAPPER_FLAGS |
+    XPC_WRAPPER_FLAGS |
     JSCLASS_IS_WRAPPED_NATIVE |
     JSCLASS_PRIVATE_IS_NSISUPPORTS |
     JSCLASS_FOREGROUND_FINALIZE,
     &XPC_WN_NoHelper_JSClassOps,
     JS_NULL_CLASS_SPEC,
     &XPC_WN_JSClassExtension,
     JS_NULL_OBJECT_OPS
 };
 
 
 /***************************************************************************/
 
-static bool
+bool
 XPC_WN_MaybeResolvingPropertyStub(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
 {
     XPCCallContext ccx(cx, obj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
     if (ccx.GetResolvingWrapper() == wrapper)
         return true;
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
-static bool
+bool
 XPC_WN_MaybeResolvingSetPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
                                      MutableHandleValue vp, ObjectOpResult& result)
 {
     result.succeed();
     return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp);
 }
 
-static bool
+bool
 XPC_WN_MaybeResolvingDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id,
                                         ObjectOpResult& result)
 {
     XPCCallContext ccx(cx, obj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
     if (ccx.GetResolvingWrapper() == wrapper) {
@@ -710,25 +711,16 @@ XPC_WN_MaybeResolvingDeletePropertyStub(
         return Throw(rv, cx);                                                 \
     return retval;
 
 #define POST_HELPER_STUB_WITH_OBJECTOPRESULT(failMethod)                      \
     if (NS_FAILED(rv))                                                        \
         return Throw(rv, cx);                                                 \
     return retval ? result.succeed() : result.failMethod();
 
-static bool
-XPC_WN_Helper_AddProperty(JSContext* cx, HandleObject obj, HandleId id,
-                          HandleValue v)
-{
-    PRE_HELPER_STUB
-    AddProperty(wrapper, cx, obj, id, v, &retval);
-    POST_HELPER_STUB
-}
-
 bool
 XPC_WN_Helper_GetProperty(JSContext* cx, HandleObject obj, HandleId id,
                           MutableHandleValue vp)
 {
     PRE_HELPER_STUB
     GetProperty(wrapper, cx, obj, id, vp.address(), &retval);
     POST_HELPER_STUB
 }
@@ -737,34 +729,34 @@ bool
 XPC_WN_Helper_SetProperty(JSContext* cx, HandleObject obj, HandleId id,
                           MutableHandleValue vp, ObjectOpResult& result)
 {
     PRE_HELPER_STUB
     SetProperty(wrapper, cx, obj, id, vp.address(), &retval);
     POST_HELPER_STUB_WITH_OBJECTOPRESULT(failReadOnly)
 }
 
-static bool
+bool
 XPC_WN_Helper_Call(JSContext* cx, unsigned argc, Value* vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     // N.B. we want obj to be the callee, not JS_THIS(cx, vp)
     RootedObject obj(cx, &args.callee());
 
     XPCCallContext ccx(cx, obj, nullptr, JSID_VOIDHANDLE, args.length(),
                        args.array(), args.rval().address());
     if (!ccx.IsValid())
         return false;
 
     PRE_HELPER_STUB
     Call(wrapper, cx, obj, args, &retval);
     POST_HELPER_STUB
 }
 
-static bool
+bool
 XPC_WN_Helper_Construct(JSContext* cx, unsigned argc, Value* vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     RootedObject obj(cx, &args.callee());
     if (!obj)
         return false;
 
     XPCCallContext ccx(cx, obj, nullptr, JSID_VOIDHANDLE, args.length(),
@@ -772,33 +764,33 @@ XPC_WN_Helper_Construct(JSContext* cx, u
     if (!ccx.IsValid())
         return false;
 
     PRE_HELPER_STUB
     Construct(wrapper, cx, obj, args, &retval);
     POST_HELPER_STUB
 }
 
-static bool
+bool
 XPC_WN_Helper_HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue valp, bool* bp)
 {
     bool retval2;
     PRE_HELPER_STUB
     HasInstance(wrapper, cx, obj, valp, &retval2, &retval);
     *bp = retval2;
     POST_HELPER_STUB
 }
 
-static void
+void
 XPC_WN_Helper_Finalize(js::FreeOp* fop, JSObject* obj)
 {
     WrappedNativeFinalize(fop, obj, WN_HELPER);
 }
 
-static bool
+bool
 XPC_WN_Helper_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
 {
     nsresult rv = NS_OK;
     bool retval = true;
     bool resolved = false;
     XPCCallContext ccx(cx, obj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@@ -860,17 +852,17 @@ XPC_WN_Helper_Resolve(JSContext* cx, Han
                                            JSPROP_ENUMERATE, resolvedp);
             (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
         }
     }
 
     return retval;
 }
 
-static bool
+bool
 XPC_WN_Helper_Enumerate(JSContext* cx, HandleObject obj)
 {
     XPCCallContext ccx(cx, obj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
     XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
     if (!si || !si->GetFlags().WantEnumerate())
@@ -912,173 +904,37 @@ XPC_WN_JSOp_Enumerate(JSContext* cx, Han
 
 /***************************************************************************/
 
 // static
 XPCNativeScriptableInfo*
 XPCNativeScriptableInfo::Construct(const XPCNativeScriptableCreateInfo* sci)
 {
     MOZ_ASSERT(sci, "bad param");
-    MOZ_ASSERT(sci->GetCallback(), "bad param");
-
-    XPCNativeScriptableInfo* newObj =
-        new XPCNativeScriptableInfo(sci->GetCallback());
-    if (!newObj)
-        return nullptr;
-
-    char* name = nullptr;
-    if (NS_FAILED(sci->GetCallback()->GetClassName(&name)) || !name) {
-        delete newObj;
-        return nullptr;
-    }
-
-    bool success;
-
-    XPCJSContext* cx = XPCJSContext::Get();
-    XPCNativeScriptableSharedMap* map = cx->GetNativeScriptableSharedMap();
-    success = map->GetNewOrUsed(sci->GetFlags(), name, newObj);
-
-    if (!success) {
-        delete newObj;
-        return nullptr;
-    }
-
-    return newObj;
+    nsCOMPtr<nsIXPCScriptable> callback = sci->GetCallback();
+    MOZ_ASSERT(callback);
+    MOZ_ASSERT(callback->GetScriptableFlags() == sci->GetFlags());
+    return new XPCNativeScriptableInfo(callback);
 }
 
-static const js::ObjectOps XPC_WN_ObjectOpsWithEnumerate = {
+const js::ObjectOps XPC_WN_ObjectOpsWithEnumerate = {
     nullptr,  // lookupProperty
     nullptr,  // defineProperty
     nullptr,  // hasProperty
     nullptr,  // getProperty
     nullptr,  // setProperty
     nullptr,  // getOwnPropertyDescriptor
     nullptr,  // deleteProperty
     nullptr,  // watch
     nullptr,  // unwatch
     nullptr,  // getElements
     XPC_WN_JSOp_Enumerate,
     nullptr,  // funToString
 };
 
-XPCNativeScriptableShared::XPCNativeScriptableShared(uint32_t aFlags,
-                                                     char* aName,
-                                                     bool aPopulate)
-    : mFlags(aFlags)
-{
-    // Initialize the js::Class.
-
-    memset(&mJSClass, 0, sizeof(mJSClass));
-    mJSClass.name = aName;  // take ownership
-
-    if (!aPopulate)
-        return;
-
-    mJSClass.flags = WRAPPER_FLAGS |
-                     JSCLASS_PRIVATE_IS_NSISUPPORTS |
-                     JSCLASS_IS_WRAPPED_NATIVE;
-
-    if (mFlags.IsGlobalObject())
-        mJSClass.flags |= XPCONNECT_GLOBAL_FLAGS;
-
-    // Initialize the js::ClassExtension.
-
-    // This is an unusual js::ClassOps: it is heap-allocated and belongs to
-    // |this|.
-    js::ClassOps* cOps = new js::ClassOps;
-    memset(cOps, 0, sizeof(js::ClassOps));
-    mJSClass.cOps = cOps;
-
-    if (mFlags.WantAddProperty())
-        cOps->addProperty = XPC_WN_Helper_AddProperty;
-    else if (mFlags.UseJSStubForAddProperty())
-        cOps->addProperty = nullptr;
-    else if (mFlags.AllowPropModsDuringResolve())
-        cOps->addProperty = XPC_WN_MaybeResolvingPropertyStub;
-    else
-        cOps->addProperty = XPC_WN_CannotModifyPropertyStub;
-
-    if (mFlags.UseJSStubForDelProperty())
-        cOps->delProperty = nullptr;
-    else if (mFlags.AllowPropModsDuringResolve())
-        cOps->delProperty = XPC_WN_MaybeResolvingDeletePropertyStub;
-    else
-        cOps->delProperty = XPC_WN_CantDeletePropertyStub;
-
-    if (mFlags.WantGetProperty())
-        cOps->getProperty = XPC_WN_Helper_GetProperty;
-    else
-        cOps->getProperty = nullptr;
-
-    if (mFlags.WantSetProperty())
-        cOps->setProperty = XPC_WN_Helper_SetProperty;
-    else if (mFlags.UseJSStubForSetProperty())
-        cOps->setProperty = nullptr;
-    else if (mFlags.AllowPropModsDuringResolve())
-        cOps->setProperty = XPC_WN_MaybeResolvingSetPropertyStub;
-    else
-        cOps->setProperty = XPC_WN_CannotModifySetPropertyStub;
-
-    MOZ_ASSERT_IF(mFlags.WantEnumerate(), !mFlags.WantNewEnumerate());
-    MOZ_ASSERT_IF(mFlags.WantNewEnumerate(), !mFlags.WantEnumerate());
-
-    // We will use ops->enumerate set below for NewEnumerate
-    if (mFlags.WantNewEnumerate())
-        cOps->enumerate = nullptr;
-    else if (mFlags.WantEnumerate())
-        cOps->enumerate = XPC_WN_Helper_Enumerate;
-    else
-        cOps->enumerate = XPC_WN_Shared_Enumerate;
-
-    // We have to figure out resolve strategy at call time
-    cOps->resolve = XPC_WN_Helper_Resolve;
-
-    if (mFlags.WantFinalize())
-        cOps->finalize = XPC_WN_Helper_Finalize;
-    else
-        cOps->finalize = XPC_WN_NoHelper_Finalize;
-
-    if (mFlags.WantCall())
-        cOps->call = XPC_WN_Helper_Call;
-    if (mFlags.WantConstruct())
-        cOps->construct = XPC_WN_Helper_Construct;
-
-    if (mFlags.WantHasInstance())
-        cOps->hasInstance = XPC_WN_Helper_HasInstance;
-
-    if (mFlags.IsGlobalObject())
-        cOps->trace = JS_GlobalObjectTraceHook;
-    else
-        cOps->trace = XPCWrappedNative::Trace;
-
-    // Initialize the js::ClassExtension.
-
-    mJSClass.ext = &XPC_WN_JSClassExtension;
-
-    // Initialize the js::ObjectOps.
-
-    if (mFlags.WantNewEnumerate())
-        mJSClass.oOps = &XPC_WN_ObjectOpsWithEnumerate;
-}
-
-XPCNativeScriptableShared::~XPCNativeScriptableShared()
-{
-    // mJSClass.cOps will be null if |this| was created with
-    // populate=false. Otherwise, it was created with populate=true
-    // and there is a weak reference in a global map that must be
-    // removed.
-
-    if (mJSClass.cOps) {
-        XPCJSContext::Get()->GetNativeScriptableSharedMap()->Remove(this);
-        free((void*)mJSClass.cOps);
-    }
-
-    free((void*)mJSClass.name);
-}
-
 /***************************************************************************/
 /***************************************************************************/
 
 // Compatibility hack.
 //
 // XPConnect used to do all sorts of funny tricks to find the "correct"
 // |this| object for a given method (often to the detriment of proper
 // call/apply). When these tricks were removed, a fair amount of chrome
@@ -1285,17 +1141,17 @@ static const js::ClassOps XPC_WN_ModsAll
 
 static const js::ClassExtension XPC_WN_Shared_Proto_ClassExtension = {
     nullptr,    /* weakmapKeyDelegateOp */
     XPC_WN_Shared_Proto_ObjectMoved
 };
 
 const js::Class XPC_WN_ModsAllowed_Proto_JSClass = {
     "XPC_WN_ModsAllowed_Proto_JSClass",
-    WRAPPER_FLAGS,
+    XPC_WRAPPER_FLAGS,
     &XPC_WN_ModsAllowed_Proto_JSClassOps,
     JS_NULL_CLASS_SPEC,
     &XPC_WN_Shared_Proto_ClassExtension,
     JS_NULL_OBJECT_OPS
 };
 
 /***************************************************************************/
 
@@ -1360,17 +1216,17 @@ static const js::ClassOps XPC_WN_NoMods_
     nullptr,                                   // call
     nullptr,                                   // construct
     nullptr,                                   // hasInstance
     XPC_WN_Shared_Proto_Trace,                 // trace
 };
 
 const js::Class XPC_WN_NoMods_Proto_JSClass = {
     "XPC_WN_NoMods_Proto_JSClass",
-    WRAPPER_FLAGS,
+    XPC_WRAPPER_FLAGS,
     &XPC_WN_NoMods_Proto_JSClassOps,
     JS_NULL_CLASS_SPEC,
     &XPC_WN_Shared_Proto_ClassExtension,
     JS_NULL_OBJECT_OPS
 };
 
 /***************************************************************************/
 
@@ -1432,21 +1288,22 @@ XPC_WN_TearOff_ObjectMoved(JSObject* obj
 {
     XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
         xpc_GetJSPrivate(obj);
     if (!p)
         return;
     p->JSObjectMoved(obj, old);
 }
 
-// Make sure WRAPPER_FLAGS has no reserved slots, so our XPC_WN_TEAROFF_RESERVED_SLOTS value is OK.
+// Make sure XPC_WRAPPER_FLAGS has no reserved slots, so our
+// XPC_WN_TEAROFF_RESERVED_SLOTS value is OK.
 
-static_assert(((WRAPPER_FLAGS >> JSCLASS_RESERVED_SLOTS_SHIFT) &
+static_assert(((XPC_WRAPPER_FLAGS >> JSCLASS_RESERVED_SLOTS_SHIFT) &
                JSCLASS_RESERVED_SLOTS_MASK) == 0,
-              "WRAPPER_FLAGS should not include any reserved slots");
+              "XPC_WRAPPER_FLAGS should not include any reserved slots");
 
 static const js::ClassOps XPC_WN_Tearoff_JSClassOps = {
     XPC_WN_OnlyIWrite_AddPropertyStub,  // addProperty
     XPC_WN_CantDeletePropertyStub,      // delProperty
     nullptr,                            // getProperty
     nullptr,                            // setProperty
     XPC_WN_TearOff_Enumerate,           // enumerate
     XPC_WN_TearOff_Resolve,             // resolve
@@ -1460,14 +1317,14 @@ static const js::ClassOps XPC_WN_Tearoff
 
 static const js::ClassExtension XPC_WN_Tearoff_JSClassExtension = {
     nullptr,                            // weakmapKeyDelegateOp
     XPC_WN_TearOff_ObjectMoved
 };
 
 const js::Class XPC_WN_Tearoff_JSClass = {
     "WrappedNative_TearOff",
-    WRAPPER_FLAGS |
+    XPC_WRAPPER_FLAGS |
     JSCLASS_HAS_RESERVED_SLOTS(XPC_WN_TEAROFF_RESERVED_SLOTS),
     &XPC_WN_Tearoff_JSClassOps,
     JS_NULL_CLASS_SPEC,
     &XPC_WN_Tearoff_JSClassExtension
 };
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -57,21 +57,16 @@
  * Besides having class info, a C++ object may be "scriptable" (i.e., implement
  * nsIXPCScriptable). This allows it to implement a more DOM-like interface,
  * besides just exposing XPCOM methods and constants. An nsIXPCScriptable
  * instance has hooks that correspond to all the normal JSClass hooks. Each
  * nsIXPCScriptable instance is mirrored by an XPCNativeScriptableInfo in
  * XPConnect. These can have pointers from XPCWrappedNativeProto and
  * XPCWrappedNative (since C++ objects can have scriptable info without having
  * class info).
- *
- * Most data in an XPCNativeScriptableInfo is shared between instances. The
- * shared data is stored in an XPCNativeScriptableShared object. This type is
- * important because it holds the JSClass of the flattened JS objects with the
- * given scriptable info.
  */
 
 /* All the XPConnect private declarations - only include locally. */
 
 #ifndef xpcprivate_h___
 #define xpcprivate_h___
 
 #include "mozilla/Alignment.h"
@@ -175,17 +170,16 @@
 #define XPC_JS_MAP_LENGTH                       32
 #define XPC_JS_CLASS_MAP_LENGTH                 32
 
 #define XPC_NATIVE_MAP_LENGTH                    8
 #define XPC_NATIVE_PROTO_MAP_LENGTH              8
 #define XPC_DYING_NATIVE_PROTO_MAP_LENGTH        8
 #define XPC_NATIVE_INTERFACE_MAP_LENGTH         32
 #define XPC_NATIVE_SET_MAP_LENGTH               32
-#define XPC_NATIVE_JSCLASS_MAP_LENGTH           16
 #define XPC_THIS_TRANSLATOR_MAP_LENGTH           4
 #define XPC_WRAPPER_MAP_LENGTH                   8
 
 /***************************************************************************/
 // data declarations...
 extern const char XPC_CONTEXT_STACK_CONTRACTID[];
 extern const char XPC_EXCEPTION_CONTRACTID[];
 extern const char XPC_CONSOLE_CONTRACTID[];
@@ -202,19 +196,16 @@ extern const char XPC_XPCONNECT_CONTRACT
     if (src)                                                                  \
         result = (char*) nsMemory::Clone(src,                                 \
                                          sizeof(char)*(strlen(src)+1));       \
     else                                                                      \
         result = nullptr;                                                      \
     *dest = result;                                                           \
     return (result || !src) ? NS_OK : NS_ERROR_OUT_OF_MEMORY
 
-
-#define WRAPPER_FLAGS (JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE)
-
 // If IS_WN_CLASS for the JSClass of an object is true, the object is a
 // wrappednative wrapper, holding the XPCWrappedNative in its private slot.
 static inline bool IS_WN_CLASS(const js::Class* clazz)
 {
     return clazz->isWrappedNative();
 }
 
 static inline bool IS_WN_REFLECTOR(JSObject* obj)
@@ -443,19 +434,16 @@ public:
         {return mClassInfo2NativeSetMap;}
 
     NativeSetMap* GetNativeSetMap() const
         {return mNativeSetMap;}
 
     IID2ThisTranslatorMap* GetThisTranslatorMap() const
         {return mThisTranslatorMap;}
 
-    XPCNativeScriptableSharedMap* GetNativeScriptableSharedMap() const
-        {return mNativeScriptableSharedMap;}
-
     XPCWrappedNativeProtoMap* GetDyingWrappedNativeProtoMap() const
         {return mDyingWrappedNativeProtoMap;}
 
     bool JSContextInitialized(JSContext* cx);
 
     virtual bool
     DescribeCustomObjects(JSObject* aObject, const js::Class* aClasp,
                           char (&aName)[72]) const override;
@@ -606,17 +594,16 @@ private:
     jsid                     mResolveName;
     XPCWrappedNative*        mResolvingWrapper;
     JSObject2WrappedJSMap*   mWrappedJSMap;
     IID2WrappedJSClassMap*   mWrappedJSClassMap;
     IID2NativeInterfaceMap*  mIID2NativeInterfaceMap;
     ClassInfo2NativeSetMap*  mClassInfo2NativeSetMap;
     NativeSetMap*            mNativeSetMap;
     IID2ThisTranslatorMap*   mThisTranslatorMap;
-    XPCNativeScriptableSharedMap* mNativeScriptableSharedMap;
     XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
     bool mGCIsRunning;
     nsTArray<nsISupports*> mNativesToReleaseArray;
     bool mDoingFinalization;
     XPCRootSetElem* mVariantRoots;
     XPCRootSetElem* mWrappedJSRoots;
     XPCRootSetElem* mObjectHolderRoots;
     nsTArray<xpcGCCallback> extraGCCallbacks;
@@ -1481,95 +1468,53 @@ public:
 
 #undef GET_IT
 
 private:
     uint32_t mFlags;
 };
 
 /***************************************************************************/
-
-// XPCNativeScriptableShared is used to hold the JSClass and the
-// associated scriptable flags for XPCWrappedNatives. These are shared across
-// the context and are garbage collected by xpconnect. We *used* to just store
-// this inside the XPCNativeScriptableInfo (usually owned by instances of
-// XPCWrappedNativeProto. This had two problems... It was wasteful, and it
-// was a big problem when wrappers are reparented to different scopes (and
-// thus different protos (the DOM does this).
-
-class XPCNativeScriptableShared final
-{
-public:
-    NS_INLINE_DECL_REFCOUNTING(XPCNativeScriptableShared)
-
-    const XPCNativeScriptableFlags& GetFlags() const { return mFlags; }
-
-    const JSClass* GetJSClass() { return Jsvalify(&mJSClass); }
-
-    XPCNativeScriptableShared(uint32_t aFlags, char* aName, bool aPopulate);
-
-    char* TransferNameOwnership() {
-        char* name = (char*)mJSClass.name;
-        mJSClass.name = nullptr;
-        return name;
-    }
-
-private:
-    ~XPCNativeScriptableShared();
-
-    XPCNativeScriptableFlags mFlags;
-
-    // This is an unusual js::Class instance: its name and cOps members are
-    // heap-allocated, unlike all other instances for which they are statically
-    // allocated. So we must free them in the destructor.
-    js::Class mJSClass;
-};
-
-/***************************************************************************/
-// XPCNativeScriptableInfo is used to hold the nsIXPCScriptable state for a
-// given class or instance.
+// XPCNativeScriptableInfo is a trivial wrapper for nsIXPCScriptable which
+// should be removed eventually.
 
 class XPCNativeScriptableInfo final
 {
 public:
     static XPCNativeScriptableInfo*
     Construct(const XPCNativeScriptableCreateInfo* sci);
 
     nsIXPCScriptable*
     GetCallback() const { return mCallback; }
 
-    const XPCNativeScriptableFlags&
-    GetFlags() const { return mShared->GetFlags(); }
+    XPCNativeScriptableFlags
+    GetFlags() const { return XPCNativeScriptableFlags(mCallback->GetScriptableFlags()); }
 
     const JSClass*
-    GetJSClass() { return mShared->GetJSClass(); }
-
-    void
-    SetScriptableShared(already_AddRefed<XPCNativeScriptableShared>&& shared) { mShared = shared; }
+    GetJSClass() { return Jsvalify(mCallback->GetClass()); }
 
 protected:
-    explicit XPCNativeScriptableInfo(nsIXPCScriptable* scriptable)
-        : mCallback(scriptable)
+    explicit XPCNativeScriptableInfo(nsIXPCScriptable* aCallback)
+        : mCallback(aCallback)
     {
         MOZ_COUNT_CTOR(XPCNativeScriptableInfo);
     }
 public:
     ~XPCNativeScriptableInfo()
     {
         MOZ_COUNT_DTOR(XPCNativeScriptableInfo);
     }
 private:
 
     // disable copy ctor and assignment
     XPCNativeScriptableInfo(const XPCNativeScriptableInfo& r) = delete;
     XPCNativeScriptableInfo& operator= (const XPCNativeScriptableInfo& r) = delete;
 
 private:
     nsCOMPtr<nsIXPCScriptable> mCallback;
-    RefPtr<XPCNativeScriptableShared> mShared;
 };
 
 /***************************************************************************/
 // XPCNativeScriptableCreateInfo is used in creating new wrapper and protos.
 // it abstracts out the scriptable interface pointer and the flags. After
 // creation these are factored differently using XPCNativeScriptableInfo.
 
 class MOZ_STACK_CLASS XPCNativeScriptableCreateInfo final
@@ -1596,16 +1541,18 @@ public:
     void
     SetCallback(already_AddRefed<nsIXPCScriptable>&& callback)
         {mCallback = callback;}
 
     void
     SetFlags(const XPCNativeScriptableFlags& flags)  {mFlags = flags;}
 
 private:
+    // XXX: the flags are the same as the ones gettable from the callback. This
+    // redundancy should be removed eventually.
     nsCOMPtr<nsIXPCScriptable>  mCallback;
     XPCNativeScriptableFlags    mFlags;
 };
 
 /***********************************************/
 // XPCWrappedNativeProto hold the additional shared wrapper data
 // for XPCWrappedNative whose native objects expose nsIClassInfo.
 
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -157,16 +157,18 @@ TraceXPCGlobal(JSTracer* trc, JSObject* 
 } /* namespace xpc */
 
 namespace JS {
 
 struct RuntimeStats;
 
 } // namespace JS
 
+#define XPC_WRAPPER_FLAGS (JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE)
+
 #define XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(n)                            \
     JSCLASS_DOM_GLOBAL | JSCLASS_HAS_PRIVATE |                                \
     JSCLASS_PRIVATE_IS_NSISUPPORTS |                                          \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS + n)
 
 #define XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET (JSCLASS_GLOBAL_SLOT_COUNT + DOM_GLOBAL_SLOTS)
 
 #define XPCONNECT_GLOBAL_FLAGS XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(0)
--- a/storage/mozStorageAsyncStatementJSHelper.cpp
+++ b/storage/mozStorageAsyncStatementJSHelper.cpp
@@ -13,16 +13,18 @@
 #include "nsServiceManagerUtils.h"
 
 #include "mozStorageAsyncStatementJSHelper.h"
 
 #include "mozStorageAsyncStatementParams.h"
 
 #include "jsapi.h"
 
+#include "xpc_make_class.h"
+
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncStatementJSHelper
 
 nsresult
 AsyncStatementJSHelper::getParams(AsyncStatement *aStatement,
--- a/storage/mozStorageAsyncStatementParams.cpp
+++ b/storage/mozStorageAsyncStatementParams.cpp
@@ -11,16 +11,18 @@
 
 #include "jsapi.h"
 
 #include "mozStoragePrivateHelpers.h"
 #include "mozStorageAsyncStatement.h"
 #include "mozStorageAsyncStatementParams.h"
 #include "mozIStorageStatement.h"
 
+#include "xpc_make_class.h"
+
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncStatementParams
 
 AsyncStatementParams::AsyncStatementParams(AsyncStatement *aStatement)
 : mStatement(aStatement)
--- a/storage/mozStorageStatementJSHelper.cpp
+++ b/storage/mozStorageStatementJSHelper.cpp
@@ -14,16 +14,18 @@
 
 #include "mozStorageStatementJSHelper.h"
 
 #include "mozStorageStatementRow.h"
 #include "mozStorageStatementParams.h"
 
 #include "jsapi.h"
 
+#include "xpc_make_class.h"
+
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Global Functions
 
 static
 bool
--- a/storage/mozStorageStatementRow.cpp
+++ b/storage/mozStorageStatementRow.cpp
@@ -7,16 +7,18 @@
 #include "nsMemory.h"
 #include "nsString.h"
 
 #include "mozStorageStatementRow.h"
 #include "mozStorageStatement.h"
 
 #include "jsapi.h"
 
+#include "xpc_make_class.h"
+
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// StatementRow
 
 StatementRow::StatementRow(Statement *aStatement)
 : mStatement(aStatement)
--- a/toolkit/components/ctypes/ctypes.cpp
+++ b/toolkit/components/ctypes/ctypes.cpp
@@ -7,16 +7,17 @@
 #include "jsapi.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsMemory.h"
 #include "nsString.h"
 #include "nsNativeCharsetUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozJSComponentLoader.h"
 #include "nsZipArchive.h"
+#include "xpc_make_class.h"
 
 #define JSCTYPES_CONTRACTID \
   "@mozilla.org/jsctypes;1"
 
 
 #define JSCTYPES_CID \
 { 0xc797702, 0x1c60, 0x4051, { 0x9d, 0xd7, 0x4d, 0x74, 0x5, 0x60, 0x56, 0x42 } }
 
--- a/toolkit/components/perf/PerfMeasurement.cpp
+++ b/toolkit/components/perf/PerfMeasurement.cpp
@@ -5,16 +5,17 @@
 
 #include "PerfMeasurement.h"
 #include "jsperf.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsMemory.h"
 #include "mozilla/Preferences.h"
 #include "mozJSComponentLoader.h"
 #include "nsZipArchive.h"
+#include "xpc_make_class.h"
 
 #define JSPERF_CONTRACTID \
   "@mozilla.org/jsperf;1"
 
 #define JSPERF_CID            \
 { 0x421c38e6, 0xaee0, 0x4509, \
   { 0xa0, 0x25, 0x13, 0x0f, 0x43, 0x78, 0x03, 0x5a } }
 
--- a/toolkit/components/reflect/reflect.cpp
+++ b/toolkit/components/reflect/reflect.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "reflect.h"
 #include "jsapi.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsMemory.h"
 #include "nsString.h"
 #include "nsNativeCharsetUtils.h"
+#include "xpc_make_class.h"
 
 #define JSREFLECT_CONTRACTID \
   "@mozilla.org/jsreflect;1"
 
 #define JSREFLECT_CID \
 { 0x1a817186, 0x357a, 0x47cd, { 0x8a, 0xea, 0x28, 0x50, 0xd6, 0x0e, 0x95, 0x9e } }
 
 namespace mozilla {