Bug 1321374 - Simplify js::Class handling relating to nsIXPCScriptable. r=mccr8, sr=bholley.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 14 Dec 2016 08:33:46 +1100
changeset 326279 98eaebf80768d80401260f12768d5bab4129961a
parent 326278 ddb057be5d8c8b0242911db3195d42dcc45b2ced
child 326280 da15ea8d6fa5433e275cffe3ec820a74d413c938
push id31093
push userphilringnalda@gmail.com
push dateSat, 17 Dec 2016 22:01:00 +0000
treeherdermozilla-central@5745bab28ff5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, bholley
bugs1321374
milestone53.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 1321374 - Simplify js::Class handling relating to nsIXPCScriptable. r=mccr8, sr=bholley. 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"
@@ -129,16 +130,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,                                                                \
@@ -778,16 +782,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 getProperty(in nsIXPConnectWrappedNative wrapper,
                        in JSContextPtr cx, in JSObjectPtr obj, in jsid id,
                        in JSValPtr vp);
 
--- 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
@@ -62,16 +64,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_GETPROPERTY
--- 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
@@ -1547,19 +1547,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
@@ -3239,17 +3236,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)),
@@ -3485,17 +3481,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
@@ -383,115 +383,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
@@ -504,51 +504,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
@@ -218,29 +218,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;
@@ -746,18 +743,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
@@ -967,19 +963,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) {
@@ -728,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(),
@@ -763,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);
@@ -851,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())
@@ -903,171 +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.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
@@ -1274,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
 };
 
 /***************************************************************************/
 
@@ -1349,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
 };
 
 /***************************************************************************/
 
@@ -1421,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
@@ -1449,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;
@@ -607,17 +595,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;
@@ -1450,95 +1437,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
@@ -1565,16 +1510,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 {