Fix for bug 519614 (Having to QI javascript scriptable helpers to nsIXPCScriptable is silly). r=mrbkap.
authorPeter Van der Beken <peterv@propagandism.org>
Mon, 28 Sep 2009 23:00:35 +0200
changeset 40489 c19b69a502ea175e344e4e5c7af76b8b77d5bfb9
parent 40488 ff91de87a87887534179c2e09b650addad1dc520
child 40490 8e6cbbc07c71d3b003d33e326601e168a42c6c47
push id12630
push userpvanderbeken@mozilla.com
push dateTue, 06 Apr 2010 13:53:25 +0000
treeherdermozilla-central@b974b6dca6ce [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs519614
milestone1.9.3a4pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Fix for bug 519614 (Having to QI javascript scriptable helpers to nsIXPCScriptable is silly). r=mrbkap.
content/base/public/nsContentUtils.h
content/html/content/src/nsGenericHTMLElement.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMClassInfoID.h
dom/base/nsIDOMClassInfo.h
dom/base/nsIDOMScriptObjectFactory.h
dom/base/nsJSEnvironment.cpp
js/src/xpconnect/idl/nsIXPCScriptNotify.idl
js/src/xpconnect/idl/nsIXPCScriptable.idl
js/src/xpconnect/src/XPCWrapper.cpp
js/src/xpconnect/src/XPCWrapper.h
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/src/xpcwrappednativeproto.cpp
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -52,17 +52,17 @@
 #endif
 
 #include "nsAString.h"
 #include "nsIStatefulFrame.h"
 #include "nsINodeInfo.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentList.h"
 #include "nsDOMClassInfoID.h"
-#include "nsIClassInfo.h"
+#include "nsIXPCScriptable.h"
 #include "nsIDOM3Node.h"
 #include "nsDataHashtable.h"
 #include "nsIScriptRuntime.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMEvent.h"
 #include "nsTArray.h"
 #include "nsTextFragment.h"
 #include "nsReadableUtils.h"
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -1103,17 +1103,18 @@ NS_NewHTML##_elementName##Element(nsINod
 
 #define NS_INTERFACE_MAP_ENTRY_IF_TAG(_interface, _tag)                       \
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface,                              \
                                      mNodeInfo->Equals(nsGkAtoms::_tag))
 
 
 #define NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_IF_TAG(_class, _tag)             \
   if (mNodeInfo->Equals(nsGkAtoms::_tag) &&                                   \
-      aIID.Equals(NS_GET_IID(nsIClassInfo))) {                                \
+      (aIID.Equals(NS_GET_IID(nsIClassInfo)) ||                               \
+       aIID.Equals(NS_GET_IID(nsXPCClassInfo)))) {                            \
     foundInterface = NS_GetDOMClassInfoInstance(eDOMClassInfo_##_class##_id); \
     if (!foundInterface) {                                                    \
       *aInstancePtr = nsnull;                                                 \
       return NS_ERROR_OUT_OF_MEMORY;                                          \
     }                                                                         \
   } else
 
 #define NS_HTML_CONTENT_INTERFACE_TABLE0(_class)                              \
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1738,30 +1738,27 @@ nsDOMClassInfo::~nsDOMClassInfo()
 {
   if (IS_EXTERNAL(mData->mCachedClassInfo)) {
     // Some compilers don't like delete'ing a const nsDOMClassInfo*
     nsDOMClassInfoData* data = const_cast<nsDOMClassInfoData*>(mData);
     delete static_cast<nsExternalDOMClassInfoData*>(data);
   }
 }
 
-NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMClassInfo, NS_DOMCLASSINFO_IID)
-
 NS_IMPL_ADDREF(nsDOMClassInfo)
 NS_IMPL_RELEASE(nsDOMClassInfo)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMClassInfo)
+  if (aIID.Equals(NS_GET_IID(nsXPCClassInfo)))
+    foundInterface = static_cast<nsIClassInfo*>(
+                                    static_cast<nsXPCClassInfo*>(this));
+  else
   NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
   NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCScriptable)
-  if (aIID.Equals(NS_GET_IID(nsDOMClassInfo))) {
-    *aInstancePtr = static_cast<nsIXPCScriptable*>(this);
-    return NS_OK;
-  }
-  else
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClassInfo)
 NS_INTERFACE_MAP_END
 
 
 static JSClass sDOMConstructorProtoClass = {
   "DOM Constructor.prototype", 0,
   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nsnull
 };
@@ -4420,30 +4417,16 @@ nsDOMClassInfo::GetClassInfoInstance(nsD
 
     NS_ADDREF(aData->mCachedClassInfo);
     aData->mCachedClassInfo = MARK_EXTERNAL(aData->mCachedClassInfo);
   }
 
   return GET_CLEAN_CI_PTR(aData->mCachedClassInfo);
 }
 
-// static
-void
-nsDOMClassInfo::PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper)
-{
-  nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(aWrapper->Native());
-  if (ci) {
-    nsDOMClassInfo* domci = nsnull;
-    CallQueryInterface(ci, &domci);
-    if (domci) {
-      domci->PreserveWrapper(aWrapper->Native());
-    }
-  }
-}
-
 
 // static
 void
 nsDOMClassInfo::ShutDown()
 {
   if (sClassInfoData[0].u.mConstructorFptr) {
     PRUint32 i;
 
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -96,26 +96,19 @@ typedef PRUptrdiff PtrBits;
 // To be used with the nsDOMClassInfoData::mCachedClassInfo pointer.
 // The low bit is set when we created a generic helper for an external
 // (which holds on to the nsDOMClassInfoData).
 #define GET_CLEAN_CI_PTR(_ptr) (nsIClassInfo*)(PtrBits(_ptr) & ~0x1)
 #define MARK_EXTERNAL(_ptr) (nsIClassInfo*)(PtrBits(_ptr) | 0x1)
 #define IS_EXTERNAL(_ptr) (PtrBits(_ptr) & 0x1)
 
 
-#define NS_DOMCLASSINFO_IID   \
-{ 0x7da6858c, 0x5c12, 0x4588, \
- { 0x82, 0xbe, 0x01, 0xa2, 0x45, 0xc5, 0xc0, 0xb0 } }
-
-class nsDOMClassInfo : public nsIXPCScriptable,
-                       public nsIClassInfo
+class nsDOMClassInfo : public nsXPCClassInfo
 {
 public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMCLASSINFO_IID)
-
   nsDOMClassInfo(nsDOMClassInfoData* aData);
   virtual ~nsDOMClassInfo();
 
   NS_DECL_NSIXPCSCRIPTABLE
 
   NS_DECL_ISUPPORTS
 
   NS_DECL_NSICLASSINFO
@@ -198,18 +191,16 @@ public:
                       "Must know what the XPCNativeWrapper class GetProperty op is!");
     }
 #endif
 
     return sXPCNativeWrapperGetPropertyOp &&
       ::JS_GET_CLASS(cx, obj)->getProperty == sXPCNativeWrapperGetPropertyOp;
   }
 
-  static void PreserveNodeWrapper(nsIXPConnectWrappedNative *aWrapper);
-
   static nsISupports *GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj);
 
   static nsIXPConnect *XPConnect()
   {
     return sXPConnect;
   }
 
 protected:
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -483,25 +483,27 @@ enum nsDOMClassInfoID {
   // This one better be the last one in this list
   eDOMClassInfoIDCount
 };
 
 /**
  * nsIClassInfo helper macros
  */
 
-class nsIClassInfo;
+#ifdef _IMPL_NS_LAYOUT
 
-#ifdef _IMPL_NS_LAYOUT
+class nsIClassInfo;
+class nsXPCClassInfo;
 
 extern nsIClassInfo*
 NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID);
 
 #define NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(_class)                          \
-  if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {                                \
+  if (aIID.Equals(NS_GET_IID(nsIClassInfo)) ||                                \
+      aIID.Equals(NS_GET_IID(nsXPCClassInfo))) {                              \
     foundInterface = NS_GetDOMClassInfoInstance(eDOMClassInfo_##_class##_id); \
     if (!foundInterface) {                                                    \
       *aInstancePtr = nsnull;                                                 \
       return NS_ERROR_OUT_OF_MEMORY;                                          \
     }                                                                         \
   } else
 
 #else
--- a/dom/base/nsIDOMClassInfo.h
+++ b/dom/base/nsIDOMClassInfo.h
@@ -69,17 +69,18 @@
 
 #ifdef _IMPL_NS_LAYOUT
 
 // See nsDOMClassInfoID.h
 
 #else
 
 #define NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(_class)                       \
-  if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {                             \
+  if (aIID.Equals(NS_GET_IID(nsIClassInfo)) ||                             \
+      aIID.Equals(NS_GET_IID(nsXPCClassInfo))) {                           \
     static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);   \
                                                                            \
     nsresult rv;                                                           \
     nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID,     \
                                                           &rv));           \
     if (NS_FAILED(rv)) {                                                   \
       *aInstancePtr = nsnull;                                              \
       return rv;                                                           \
@@ -90,17 +91,18 @@
   } else
 
 #endif /* _IMPL_NS_LAYOUT */
 
 // Looks up the nsIClassInfo for a class name registered with the 
 // nsScriptNamespaceManager. Remember to release NS_CLASSINFO_NAME(_class)
 // (eg. when your module unloads).
 #define NS_INTERFACE_MAP_ENTRY_EXTERNAL_DOM_CLASSINFO(_class)              \
-  if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {                             \
+  if (aIID.Equals(NS_GET_IID(nsIClassInfo)) ||                             \
+      aIID.Equals(NS_GET_IID(nsXPCClassInfo))) {                           \
     extern nsISupports *NS_CLASSINFO_NAME(_class);                         \
     if (NS_CLASSINFO_NAME(_class)) {                                       \
       foundInterface = NS_CLASSINFO_NAME(_class);                          \
     } else {                                                               \
       static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); \
                                                                            \
       nsresult rv;                                                         \
       nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID,   \
--- a/dom/base/nsIDOMScriptObjectFactory.h
+++ b/dom/base/nsIDOMScriptObjectFactory.h
@@ -38,25 +38,25 @@
 #ifndef nsIDOMScriptObjectFactory_h__
 #define nsIDOMScriptObjectFactory_h__
 
 #include "nsISupports.h"
 #include "nsIDOMClassInfo.h"
 #include "nsStringGlue.h"
 
 #define NS_IDOM_SCRIPT_OBJECT_FACTORY_IID   \
-{ 0xd5a4f935, 0xe428, 0x47ec, \
-  { 0x8f, 0x36, 0x44, 0x23, 0xfa, 0xa2, 0x21, 0x90 } }
+{ 0x8c0eb687, 0xa859, 0x4a62, \
+ { 0x99, 0x82, 0xea, 0xbf, 0x9e, 0xf5, 0x59, 0x5f } }
 
 class nsIScriptContext;
 class nsIScriptGlobalObject;
 class nsIScriptRuntime;
 class nsIDOMEventListener;
 
-typedef nsIClassInfo* (*nsDOMClassInfoExternalConstructorFnc)
+typedef nsXPCClassInfo* (*nsDOMClassInfoExternalConstructorFnc)
   (const char* aName);
 
 class nsIDOMScriptObjectFactory : public nsISupports {
 public:  
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOM_SCRIPT_OBJECT_FACTORY_IID)
 
   // Get a script language given its "name" (ie, the mime-type)
   // Note that to fetch javascript from this function, you must currently
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -3515,23 +3515,16 @@ nsJSContext::SetGCOnDestruction(PRBool a
 NS_IMETHODIMP
 nsJSContext::ScriptExecuted()
 {
   ScriptEvaluated(!::JS_IsRunning(mContext));
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsJSContext::PreserveWrapper(nsIXPConnectWrappedNative *aWrapper)
-{
-  nsDOMClassInfo::PreserveNodeWrapper(aWrapper);
-  return NS_OK;
-}
-
 //static
 void
 nsJSContext::CC()
 {
   ++sCCollectCount;
 #ifdef DEBUG_smaug
   printf("Will run cycle collector (%i), %lldms since previous.\n",
          sCCollectCount, (PR_Now() - sPreviousCCTime) / PR_USEC_PER_MSEC);
--- a/js/src/xpconnect/idl/nsIXPCScriptNotify.idl
+++ b/js/src/xpconnect/idl/nsIXPCScriptNotify.idl
@@ -43,24 +43,17 @@
  * that the script has been evaluated by XPConnect. if any JSContext in our 
  * JSRuntime has set the JSOPTION_PRIVATE_IS_NSISUPPORTS option and the 
  * private context supports nsIXPCScriptNotify then this method is invoked
  */
 
 
 #include "nsISupports.idl"
 
-interface nsIXPConnectWrappedNative;
-
-[uuid(b804504d-0025-4d6b-8ced-d94e41102a7f)]
+[uuid(13aceb15-812a-476a-9326-2adc00250b76)]
 interface nsIXPCScriptNotify : nsISupports
 {
     /**
      * Method invoked when a script has been executed by XPConnect
      */
     void ScriptExecuted();
-
-    /**
-     * Method invoked to preserve an nsIXPConnectWrappedNative as needed
-     */
-    void preserveWrapper(in nsIXPConnectWrappedNative wrapper);
 };
 
--- a/js/src/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/src/xpconnect/idl/nsIXPCScriptable.idl
@@ -43,16 +43,24 @@
 
 [ptr] native JSTracerPtr(JSTracer);
 
 %{ C++
 #define NS_SUCCESS_I_DID_SOMETHING \
    (NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,1))
 #define NS_SUCCESS_CHROME_ACCESS_ONLY \
    (NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,2))
+
+/**
+ * Classes that want slim wrappers should return NS_SUCCESS_ALLOW_SLIM_WRAPPERS
+ * from their scriptable helper's PreCreate hook. They must also force a parent
+ * for their wrapper (from the PreCreate hook), they must implement
+ * nsWrapperCache and their scriptable helper must implement nsXPCClassInfo and
+ * must return DONT_ASK_INSTANCE_FOR_SCRIPTABLE in the flags.
+ */
 #define NS_SUCCESS_ALLOW_SLIM_WRAPPERS \
    (NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,3))
 %}
 
 /**
  * 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
@@ -176,8 +184,41 @@ interface nsIXPCScriptable : nsISupports
     JSObjectPtr outerObject(in nsIXPConnectWrappedNative wrapper,
                             in JSContextPtr cx, in JSObjectPtr obj);
 
     JSObjectPtr innerObject(in nsIXPConnectWrappedNative wrapper,
                             in JSContextPtr cx, in JSObjectPtr obj);
 
     void postCreatePrototype(in JSContextPtr cx, in JSObjectPtr proto);
 };
+
+%{ C++
+
+#include "nsAutoPtr.h"
+
+#define NS_XPCCLASSINFO_IID \
+{ 0xc39aa8db, 0x619d, 0x4ee6, \
+ { 0xb1, 0x72, 0x5a, 0x83, 0x5d, 0x68, 0xfb, 0xb2 } }
+
+class NS_NO_VTABLE nsXPCClassInfo : public nsIClassInfo,
+                                    public nsIXPCScriptable
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_XPCCLASSINFO_IID)
+
+  NS_IMETHOD_(nsrefcnt) AddRef() = 0;
+  NS_IMETHOD_(nsrefcnt) Release() = 0;
+
+  virtual void PreserveWrapper(nsISupports *aNative) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCClassInfo, NS_XPCCLASSINFO_IID)
+
+inline
+nsresult
+CallQueryInterface(nsISupports* aSourcePtr,
+                   nsRefPtrGetterAddRefs<nsXPCClassInfo> aDestPtr)
+{
+  return CallQueryInterface(aSourcePtr,
+                            static_cast<nsXPCClassInfo**>(aDestPtr));
+}
+
+%}
--- a/js/src/xpconnect/src/XPCWrapper.cpp
+++ b/js/src/xpconnect/src/XPCWrapper.cpp
@@ -613,41 +613,47 @@ ResolveNativeProperty(JSContext *cx, JSO
       return DoThrowException(NS_ERROR_NOT_IMPLEMENTED, cx);
     }
   }
 
   if (!JSVAL_IS_STRING(id)) {
     // A non-string id is being resolved. Won't be found here, return
     // early.
 
-    return MaybePreserveWrapper(cx, wn, flags);
+    MaybePreserveWrapper(cx, wn, flags);
+
+    return JS_TRUE;
   }
 
   // Verify that our jsobject really is a wrapped native.
   XPCWrappedNative* wrapper = ccx.GetWrapper();
   if (wrapper != wn || !wrapper->IsValid()) {
     NS_ASSERTION(wrapper == wn, "Uh, how did this happen!");
     return DoThrowException(NS_ERROR_XPC_BAD_CONVERT_JS, cx);
   }
 
   // it would be a big surprise if there is a member without an
   // interface :)
   XPCNativeInterface* iface = ccx.GetInterface();
   if (!iface) {
     // No interface, nothing to resolve.
 
-    return MaybePreserveWrapper(cx, wn, flags);
+    MaybePreserveWrapper(cx, wn, flags);
+
+    return JS_TRUE;
   }
 
   // did we find a method/attribute by that name?
   XPCNativeMember* member = ccx.GetMember();
   if (!member) {
     // No member, nothing to resolve.
 
-    return MaybePreserveWrapper(cx, wn, flags);
+    MaybePreserveWrapper(cx, wn, flags);
+
+    return JS_TRUE;
   }
 
   JSString *str = JSVAL_TO_STRING(id);
   if (!str) {
     return DoThrowException(NS_ERROR_UNEXPECTED, cx);
   }
 
   // Get (and perhaps lazily create) the member's value (commonly a
--- a/js/src/xpconnect/src/XPCWrapper.h
+++ b/js/src/xpconnect/src/XPCWrapper.h
@@ -271,29 +271,26 @@ GetSecurityManager()
 {
   return ::gScriptSecurityManager;
 }
 
 /**
  * Used to ensure that an XPCWrappedNative stays alive when its scriptable
  * helper defines an "expando" property on it.
  */
-inline JSBool
+inline void
 MaybePreserveWrapper(JSContext *cx, XPCWrappedNative *wn, uintN flags)
 {
-  if ((flags & JSRESOLVE_ASSIGNING) &&
-      (::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
-    nsCOMPtr<nsIXPCScriptNotify> scriptNotify = 
-      do_QueryInterface(static_cast<nsISupports*>
-                                   (JS_GetContextPrivate(cx)));
-    if (scriptNotify) {
-      return NS_SUCCEEDED(scriptNotify->PreserveWrapper(wn));
+  if ((flags & JSRESOLVE_ASSIGNING)) {
+    nsRefPtr<nsXPCClassInfo> ci;
+    CallQueryInterface(wn->Native(), getter_AddRefs(ci));
+    if (ci) {
+      ci->PreserveWrapper(wn->Native());
     }
   }
-  return JS_TRUE;
 }
 
 inline JSBool
 IsSecurityWrapper(JSObject *wrapper)
 {
   JSClass *clasp = wrapper->getClass();
   return (clasp->flags & JSCLASS_IS_EXTENDED) &&
     ((JSExtendedClass*)clasp)->wrappedObject;
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -1627,34 +1627,30 @@ nsXPConnect::MoveWrappers(JSContext *aJS
         // is the singleton classinfo, so we don't need to reparent it.
         if(SameCOMIdentity(identity, info))
             info = nsnull;
 
         if(!info)
             continue;
 
         XPCNativeScriptableCreateInfo sciProto;
-        XPCNativeScriptableCreateInfo sciWrapper;
-
-        nsresult rv =
-            XPCWrappedNative::GatherScriptableCreateInfo(identity,
-                                                         info.get(),
-                                                         &sciProto,
-                                                         &sciWrapper);
-        if(NS_FAILED(rv))
-            return NS_ERROR_FAILURE;
+        XPCNativeScriptableCreateInfo sci;
+        const XPCNativeScriptableCreateInfo& sciWrapper =
+            XPCWrappedNative::GatherScriptableCreateInfo(identity, info,
+                                                         sciProto, sci);
 
         // If the wrapper doesn't want precreate, then we don't need to
         // worry about reparenting it.
         if(!sciWrapper.GetFlags().WantPreCreate())
             continue;
 
         JSObject *newParent = aOldScope;
-        rv = sciWrapper.GetCallback()->PreCreate(identity, ccx, aOldScope,
-                                                 &newParent);
+        nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
+                                                          aOldScope,
+                                                          &newParent);
         if(NS_FAILED(rv))
             return rv;
 
         if(newParent == aOldScope)
         {
             // The old scope still works for this wrapper. We have to assume
             // that the wrapper will continue to return the old scope from
             // PreCreate, so don't move it.
@@ -2104,17 +2100,17 @@ nsXPConnect::GetWrappedNativePrototype(J
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
     if(!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCNativeScriptableCreateInfo sciProto;
-    XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, &sciProto);
+    XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
 
     AutoMarkingWrappedNativeProtoPtr proto(ccx);
     proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, aClassInfo, 
                                                 &sciProto, JS_FALSE,
                                                 OBJ_IS_NOT_GLOBAL);
     if(!proto)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -2022,36 +2022,38 @@ private:
     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 XPCNativeScriptableCreateInfo
+class NS_STACK_CLASS XPCNativeScriptableCreateInfo
 {
 public:
 
     XPCNativeScriptableCreateInfo(const XPCNativeScriptableInfo& si)
         : mCallback(si.GetCallback()), mFlags(si.GetFlags()) {}
 
-    XPCNativeScriptableCreateInfo(nsIXPCScriptable* callback = nsnull,
-                                  XPCNativeScriptableFlags flags = 0)
+    XPCNativeScriptableCreateInfo(already_AddRefed<nsIXPCScriptable> callback,
+                                  XPCNativeScriptableFlags flags)
         : mCallback(callback), mFlags(flags) {}
 
+    XPCNativeScriptableCreateInfo()
+        : mFlags(0) {}
+
+
     nsIXPCScriptable*
     GetCallback() const {return mCallback;}
 
     const XPCNativeScriptableFlags&
     GetFlags() const      {return mFlags;}
 
     void
-    SetCallback(nsIXPCScriptable* callback) {mCallback = callback;}
-    void
     SetCallback(already_AddRefed<nsIXPCScriptable> callback)
       {mCallback = callback;}
 
     void
     SetFlags(const XPCNativeScriptableFlags& flags)  {mFlags = flags;}
 
 private:
     nsCOMPtr<nsIXPCScriptable>  mCallback;
@@ -2604,19 +2606,19 @@ public:
 #endif
 
     inline void SweepTearOffs();
 
     // Returns a string that shuld be free'd using JS_smprintf_free (or null).
     char* ToString(XPCCallContext& ccx,
                    XPCWrappedNativeTearOff* to = nsnull) const;
 
-    static nsresult GatherProtoScriptableCreateInfo(
+    static void GatherProtoScriptableCreateInfo(
                         nsIClassInfo* classInfo,
-                        XPCNativeScriptableCreateInfo* sciProto);
+                        XPCNativeScriptableCreateInfo& sciProto);
 
     JSBool HasExternalReference() const {return mRefCnt > 1;}
 
     JSBool NeedsChromeWrapper() { return !!(mWrapperWord & CHROME_ONLY); }
     void SetNeedsChromeWrapper() { mWrapperWord |= CHROME_ONLY; }
     JSBool IsDoubleWrapper() { return !!(mWrapperWord & DOUBLE_WRAPPER); }
     void SetIsDoubleWrapper() { mWrapperWord |= DOUBLE_WRAPPER; }
 
@@ -2678,21 +2680,21 @@ private:
                          XPCWrappedNativeTearOff* aTearOff,
                          XPCNativeInterface* aInterface,
                          JSBool needJSObject);
 
     JSBool InitTearOffJSObject(XPCCallContext& ccx,
                                 XPCWrappedNativeTearOff* to);
 
 public:
-    static nsresult GatherScriptableCreateInfo(
+    static const XPCNativeScriptableCreateInfo& GatherScriptableCreateInfo(
                         nsISupports* obj,
                         nsIClassInfo* classInfo,
-                        XPCNativeScriptableCreateInfo* sciProto,
-                        XPCNativeScriptableCreateInfo* sciWrapper);
+                        XPCNativeScriptableCreateInfo& sciProto,
+                        XPCNativeScriptableCreateInfo& sciWrapper);
 
 private:
     union
     {
         XPCWrappedNativeScope*   mMaybeScope;
         XPCWrappedNativeProto*   mMaybeProto;
     };
     XPCNativeSet*                mSet;
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -404,29 +404,28 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
     if(isIDispatch && !info)
     {
         info = dont_AddRef(static_cast<nsIClassInfo*>
                                       (XPCIDispatchClassInfo::GetSingleton()));
     }
 #endif
 
     XPCNativeScriptableCreateInfo sciProto;
-    XPCNativeScriptableCreateInfo sciWrapper;
+    XPCNativeScriptableCreateInfo sci;
 
     // Gather scriptable create info if we are wrapping something
     // other than an nsIClassInfo object. We need to not do this for
     // nsIClassInfo objects because often nsIClassInfo implementations
     // are also nsIXPCScriptable helper implmentations, but the helper
     // code is obviously intended for the implementation of the class
     // described by the nsIClassInfo, not for the class info object
     // itself.
-    if(!isClassInfo &&
-       NS_FAILED(GatherScriptableCreateInfo(identity, info.get(),
-                                            &sciProto, &sciWrapper)))
-        return NS_ERROR_FAILURE;
+    const XPCNativeScriptableCreateInfo& sciWrapper =
+        isClassInfo ? sci :
+        GatherScriptableCreateInfo(identity, info, sciProto, sci);
 
     JSObject* parent = Scope->GetGlobalJSObject();
 
     jsval newParentVal = JSVAL_NULL;
     XPCMarkableJSVal newParentVal_markable(&newParentVal);
     AutoMarkingJSVal newParentVal_automarker(ccx, &newParentVal_markable);
     JSBool chromeOnly = JS_FALSE;
     JSBool crossDoubleWrapped = JS_FALSE;
@@ -919,136 +918,150 @@ XPCWrappedNative::~XPCWrappedNative()
         {
             NS_RELEASE(mIdentity);
         }
     }
 }
 
 // This is factored out so that it can be called publicly 
 // static
-nsresult 
+void 
 XPCWrappedNative::GatherProtoScriptableCreateInfo(
                         nsIClassInfo* classInfo,
-                        XPCNativeScriptableCreateInfo* sciProto)
+                        XPCNativeScriptableCreateInfo& sciProto)
 {
     NS_ASSERTION(classInfo, "bad param");
-    NS_ASSERTION(sciProto && !sciProto->GetCallback(), "bad param");
+    NS_ASSERTION(!sciProto.GetCallback(), "bad param");
+
+    nsXPCClassInfo *classInfoHelper = nsnull;
+    CallQueryInterface(classInfo, &classInfoHelper);
+    if(classInfoHelper)
+    {
+        nsCOMPtr<nsIXPCScriptable> helper =
+          dont_AddRef(static_cast<nsIXPCScriptable*>(classInfoHelper));
+        JSUint32 flags;
+        nsresult rv = classInfoHelper->GetScriptableFlags(&flags);
+        if(NS_FAILED(rv))
+            flags = 0;
+
+        sciProto.SetCallback(helper.forget());
+        sciProto.SetFlags(flags);
+
+        return;
+    }
 
     nsCOMPtr<nsISupports> possibleHelper;
     nsresult rv = classInfo->GetHelperForLanguage(
                                     nsIProgrammingLanguage::JAVASCRIPT,
                                     getter_AddRefs(possibleHelper));
     if(NS_SUCCEEDED(rv) && possibleHelper)
     {
         nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(possibleHelper));
         if(helper)
         {
             JSUint32 flags;
             rv = helper->GetScriptableFlags(&flags);
             if(NS_FAILED(rv))
                 flags = 0;
 
-            sciProto->SetCallback(helper.forget());
-            sciProto->SetFlags(flags);
+            sciProto.SetCallback(helper.forget());
+            sciProto.SetFlags(flags);
         }
     }
-    return NS_OK;
 }
 
 // static
-nsresult
+const XPCNativeScriptableCreateInfo&
 XPCWrappedNative::GatherScriptableCreateInfo(
                         nsISupports* obj,
                         nsIClassInfo* classInfo,
-                        XPCNativeScriptableCreateInfo* sciProto,
-                        XPCNativeScriptableCreateInfo* sciWrapper)
+                        XPCNativeScriptableCreateInfo& sciProto,
+                        XPCNativeScriptableCreateInfo& sciWrapper)
 {
-    NS_ASSERTION(sciProto   && !sciProto->GetCallback(), "bad param");
-    NS_ASSERTION(sciWrapper && !sciWrapper->GetCallback(), "bad param");
+    NS_ASSERTION(!sciWrapper.GetCallback(), "bad param");
 
     // Get the class scriptable helper (if present)
     if(classInfo)
     {
         GatherProtoScriptableCreateInfo(classInfo, sciProto);
 
-        sciWrapper->SetCallback(sciProto->GetCallback());
-        sciWrapper->SetFlags(sciProto->GetFlags());
-
-        if(sciProto->GetFlags().DontAskInstanceForScriptable())
-            return NS_OK;
+        if(sciProto.GetFlags().DontAskInstanceForScriptable())
+            return sciProto;
     }
 
     // Do the same for the wrapper specific scriptable
     nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(obj));
     if(helper)
     {
         JSUint32 flags;
         nsresult rv = helper->GetScriptableFlags(&flags);
         if(NS_FAILED(rv))
             flags = 0;
 
-        sciWrapper->SetCallback(helper.forget());
-        sciWrapper->SetFlags(flags);
+        sciWrapper.SetCallback(helper.forget());
+        sciWrapper.SetFlags(flags);
 
         // A whole series of assertions to catch bad uses of scriptable flags on
         // the siWrapper...
 
-        NS_ASSERTION(!(sciWrapper->GetFlags().WantPreCreate() &&
-                        !sciProto->GetFlags().WantPreCreate()),
+        NS_ASSERTION(!(sciWrapper.GetFlags().WantPreCreate() &&
+                        !sciProto.GetFlags().WantPreCreate()),
                      "Can't set WANT_PRECREATE on an instance scriptable "
                      "without also setting it on the class scriptable");
 
-        NS_ASSERTION(!(sciWrapper->GetFlags().DontEnumStaticProps() &&
-                        !sciProto->GetFlags().DontEnumStaticProps() &&
-                        sciProto->GetCallback() &&
-                        !sciProto->GetFlags().DontSharePrototype()),
+        NS_ASSERTION(!(sciWrapper.GetFlags().DontEnumStaticProps() &&
+                        !sciProto.GetFlags().DontEnumStaticProps() &&
+                        sciProto.GetCallback() &&
+                        !sciProto.GetFlags().DontSharePrototype()),
                      "Can't set DONT_ENUM_STATIC_PROPS on an instance scriptable "
                      "without also setting it on the class scriptable (if present and shared)");
 
-        NS_ASSERTION(!(sciWrapper->GetFlags().DontEnumQueryInterface() &&
-                        !sciProto->GetFlags().DontEnumQueryInterface() &&
-                        sciProto->GetCallback() &&
-                        !sciProto->GetFlags().DontSharePrototype()),
+        NS_ASSERTION(!(sciWrapper.GetFlags().DontEnumQueryInterface() &&
+                        !sciProto.GetFlags().DontEnumQueryInterface() &&
+                        sciProto.GetCallback() &&
+                        !sciProto.GetFlags().DontSharePrototype()),
                      "Can't set DONT_ENUM_QUERY_INTERFACE on an instance scriptable "
                      "without also setting it on the class scriptable (if present and shared)");
 
-        NS_ASSERTION(!(sciWrapper->GetFlags().DontAskInstanceForScriptable() &&
-                        !sciProto->GetFlags().DontAskInstanceForScriptable()),
+        NS_ASSERTION(!(sciWrapper.GetFlags().DontAskInstanceForScriptable() &&
+                        !sciProto.GetFlags().DontAskInstanceForScriptable()),
                      "Can't set DONT_ASK_INSTANCE_FOR_SCRIPTABLE on an instance scriptable "
                      "without also setting it on the class scriptable");
 
-        NS_ASSERTION(!(sciWrapper->GetFlags().ClassInfoInterfacesOnly() &&
-                        !sciProto->GetFlags().ClassInfoInterfacesOnly() &&
-                        sciProto->GetCallback() &&
-                        !sciProto->GetFlags().DontSharePrototype()),
+        NS_ASSERTION(!(sciWrapper.GetFlags().ClassInfoInterfacesOnly() &&
+                        !sciProto.GetFlags().ClassInfoInterfacesOnly() &&
+                        sciProto.GetCallback() &&
+                        !sciProto.GetFlags().DontSharePrototype()),
                      "Can't set CLASSINFO_INTERFACES_ONLY on an instance scriptable "
                      "without also setting it on the class scriptable (if present and shared)");
 
-        NS_ASSERTION(!(sciWrapper->GetFlags().AllowPropModsDuringResolve() &&
-                        !sciProto->GetFlags().AllowPropModsDuringResolve() &&
-                        sciProto->GetCallback() &&
-                        !sciProto->GetFlags().DontSharePrototype()),
+        NS_ASSERTION(!(sciWrapper.GetFlags().AllowPropModsDuringResolve() &&
+                        !sciProto.GetFlags().AllowPropModsDuringResolve() &&
+                        sciProto.GetCallback() &&
+                        !sciProto.GetFlags().DontSharePrototype()),
                      "Can't set ALLOW_PROP_MODS_DURING_RESOLVE on an instance scriptable "
                      "without also setting it on the class scriptable (if present and shared)");
 
-        NS_ASSERTION(!(sciWrapper->GetFlags().AllowPropModsToPrototype() &&
-                        !sciProto->GetFlags().AllowPropModsToPrototype() &&
-                        sciProto->GetCallback() &&
-                        !sciProto->GetFlags().DontSharePrototype()),
+        NS_ASSERTION(!(sciWrapper.GetFlags().AllowPropModsToPrototype() &&
+                        !sciProto.GetFlags().AllowPropModsToPrototype() &&
+                        sciProto.GetCallback() &&
+                        !sciProto.GetFlags().DontSharePrototype()),
                      "Can't set ALLOW_PROP_MODS_TO_PROTOTYPE on an instance scriptable "
                      "without also setting it on the class scriptable (if present and shared)");
 
-        NS_ASSERTION(!(sciWrapper->GetFlags().DontSharePrototype() &&
-                        !sciProto->GetFlags().DontSharePrototype() &&
-                        sciProto->GetCallback()),
+        NS_ASSERTION(!(sciWrapper.GetFlags().DontSharePrototype() &&
+                        !sciProto.GetFlags().DontSharePrototype() &&
+                        sciProto.GetCallback()),
                      "Can't set DONT_SHARE_PROTOTYPE on an instance scriptable "
                      "without also setting it on the class scriptable (if present and shared)");
+
+        return sciWrapper;
     }
 
-    return NS_OK;
+    return sciProto;
 }
 
 void
 XPCWrappedNative::TraceOtherWrapper(JSTracer* trc)
 {
     // Note: This isn't wrapped by a MapLock, however, this is normally called
     // during GC, where nobody should be playing with the wrapper map anyway,
     // so this should be OK.
@@ -3801,39 +3814,40 @@ static PRUint32 sSlimWrappers;
 #endif
 
 JSBool
 ConstructSlimWrapper(XPCCallContext &ccx, nsISupports *p, nsWrapperCache *cache,
                      XPCWrappedNativeScope* xpcScope, jsval *rval)
 {
     nsCOMPtr<nsISupports> identityObj = do_QueryInterface(p);
 
-    nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(p);
-    if(!classInfo)
-        return JS_FALSE;
-
-    // XXX Sucks a bit that we have to get the proto before we know whether we
-    //     can create a slim wrapper.
-    XPCNativeScriptableCreateInfo sciProto;
-    nsresult rv = XPCWrappedNative::GatherProtoScriptableCreateInfo(classInfo,
-                                                                    &sciProto);
-    NS_ENSURE_SUCCESS(rv, JS_FALSE);
+    nsRefPtr<nsXPCClassInfo> classInfoHelper;
+    CallQueryInterface(p, getter_AddRefs(classInfoHelper));
+
+    JSUint32 flagsInt;
+    nsresult rv = classInfoHelper->GetScriptableFlags(&flagsInt);
+    if(NS_FAILED(rv))
+        flagsInt = 0;
+
+    XPCNativeScriptableFlags flags(flagsInt);
+
+    NS_ASSERTION(flags.DontAskInstanceForScriptable(),
+                 "Not supported for cached wrappers!");
 
     JSObject* parent = xpcScope->GetGlobalJSObject();
-    if(!sciProto.GetFlags().WantPreCreate())
+    if(!flags.WantPreCreate())
     {
         SLIM_LOG_NOT_CREATED(ccx, identityObj,
                              "scriptable helper has no PreCreate hook");
 
         return JS_FALSE;
     }
 
     JSObject* plannedParent = parent;
-    rv = sciProto.GetCallback()->PreCreate(identityObj, ccx, parent,
-                                           &parent);
+    rv = classInfoHelper->PreCreate(identityObj, ccx, parent, &parent);
     if(rv != NS_SUCCESS_ALLOW_SLIM_WRAPPERS)
     {
         SLIM_LOG_NOT_CREATED(ccx, identityObj, "PreCreate hook refused");
 
         return JS_FALSE;
     }
 
     if(parent != plannedParent)
@@ -3853,16 +3867,20 @@ ConstructSlimWrapper(XPCCallContext &ccx
     JSObject* wrapper = cache->GetWrapper();
     if(wrapper)
     {
         *rval = OBJECT_TO_JSVAL(wrapper);
 
         return JS_TRUE;
     }
 
+    nsIClassInfo* classInfo = classInfoHelper;
+    XPCNativeScriptableCreateInfo sciProto(classInfoHelper.forget().get(),
+                                           flags);
+
     AutoMarkingWrappedNativeProtoPtr xpcproto(ccx);
     JSBool isGlobal = JS_FALSE;
     xpcproto = XPCWrappedNativeProto::GetNewOrUsed(ccx, xpcScope, classInfo,
                                                    &sciProto, JS_FALSE,
                                                    isGlobal);
     if(!xpcproto)
         return JS_FALSE;
 
--- a/js/src/xpconnect/src/xpcwrappednativeproto.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativeproto.cpp
@@ -88,17 +88,20 @@ XPCWrappedNativeProto::~XPCWrappedNative
 }
 
 JSBool
 XPCWrappedNativeProto::Init(
                 XPCCallContext& ccx,
                 JSBool isGlobal,
                 const XPCNativeScriptableCreateInfo* scriptableCreateInfo)
 {
-    if(scriptableCreateInfo && scriptableCreateInfo->GetCallback())
+    nsIXPCScriptable *callback = scriptableCreateInfo ?
+                                 scriptableCreateInfo->GetCallback() :
+                                 nsnull;
+    if(callback)
     {
         mScriptableInfo =
             XPCNativeScriptableInfo::Construct(ccx, isGlobal, scriptableCreateInfo);
         if(!mScriptableInfo)
             return JS_FALSE;
     }
 
     JSClass* jsclazz;
@@ -130,29 +133,25 @@ XPCWrappedNativeProto::Init(
 
     mJSProtoObject =
         xpc_NewSystemInheritingJSObject(ccx, jsclazz,
                                         mScope->GetPrototypeJSObject(),
                                         parent);
 
     JSBool ok = mJSProtoObject && JS_SetPrivate(ccx, mJSProtoObject, this);
 
-    if(ok && scriptableCreateInfo)
+    if(ok && callback)
     {
-        nsIXPCScriptable *callback = scriptableCreateInfo->GetCallback();
-        if(callback)
+        nsresult rv = callback->PostCreatePrototype(ccx, mJSProtoObject);
+        if(NS_FAILED(rv))
         {
-            nsresult rv = callback->PostCreatePrototype(ccx, mJSProtoObject);
-            if(NS_FAILED(rv))
-            {
-                JS_SetPrivate(ccx, mJSProtoObject, nsnull);
-                mJSProtoObject = nsnull;
-                XPCThrower::Throw(rv, ccx);
-                return JS_FALSE;
-            }
+            JS_SetPrivate(ccx, mJSProtoObject, nsnull);
+            mJSProtoObject = nsnull;
+            XPCThrower::Throw(rv, ccx);
+            return JS_FALSE;
         }
     }
 
     DEBUG_ReportShadowedMembers(mSet, nsnull, this);
 
     return ok;
 }