Fix for bug 590612 (Speed up js-wrapping in classinfo when we already have a wrapper). r=bz, a=jst.
authorPeter Van der Beken <peterv@propagandism.org>
Sat, 28 Aug 2010 10:04:25 +0200
changeset 57854 7e42ccaa7269cd8cf0ed30684bc4a718673710c4
parent 57853 789f0f85f75a3fa55d36c5d69a5b3bbbf3596410
child 57855 2aceaa1070b43970bb058cb589a6a37ae96e94ac
push id17043
push userpvanderbeken@mozilla.com
push dateThu, 18 Nov 2010 15:47:35 +0000
treeherdermozilla-central@7e42ccaa7269 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, jst
bugs590612
milestone2.0b8pre
first release with
nightly mac
7e42ccaa7269 / 4.0b8pre / 20101118100301 / files
nightly win32
7e42ccaa7269 / 4.0b8pre / 20101118112142 / files
nightly linux32
nightly linux64
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly mac
nightly win32
Fix for bug 590612 (Speed up js-wrapping in classinfo when we already have a wrapper). r=bz, a=jst.
caps/src/nsScriptSecurityManager.cpp
content/base/src/nsContentUtils.cpp
dom/base/nsDOMClassInfo.h
js/src/jstl.h
js/src/jsvector.h
js/src/xpconnect/src/qsgen.py
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcpublic.h
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -101,22 +101,16 @@ static NS_DEFINE_CID(kZipReaderCID, NS_Z
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nsnull;
 nsIXPConnect    *nsScriptSecurityManager::sXPConnect = nsnull;
 nsIThreadJSContextStack *nsScriptSecurityManager::sJSContextStack = nsnull;
 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
 JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
 PRBool nsScriptSecurityManager::sStrictFileOriginPolicy = PR_TRUE;
 
-// Info we need about the JSClasses used by XPConnects wrapped
-// natives, to avoid having to QI to nsIXPConnectWrappedNative all the
-// time when doing security checks.
-static JSEqualityOp sXPCWrappedNativeEqualityOps;
-
-
 ///////////////////////////
 // Convenience Functions //
 ///////////////////////////
 // Result of this function should not be freed.
 static inline const PRUnichar *
 IDToString(JSContext *cx, jsid id)
 {
     if (JSID_IS_STRING(id))
@@ -2409,21 +2403,18 @@ nsScriptSecurityManager::doGetObjectPrin
 
             jsClass = aObj->getClass();
         }
     }
 
     do {
         // Note: jsClass is set before this loop, and also at the
         // *end* of this loop.
-
-        // NOTE: These class and equality hook checks better match
-        // what IS_WRAPPER_CLASS() does in xpconnect!
         
-        if (jsClass->ext.equality == js::Valueify(sXPCWrappedNativeEqualityOps)) {
+        if (IS_WRAPPER_CLASS(jsClass)) {
             result = sXPConnect->GetPrincipal(aObj,
 #ifdef DEBUG
                                               aAllowShortCircuit
 #else
                                               PR_TRUE
 #endif
                                               );
             if (result) {
@@ -3418,17 +3409,16 @@ nsresult nsScriptSecurityManager::Init()
     };
 
 #ifdef DEBUG
     JSSecurityCallbacks *oldcallbacks =
 #endif
     JS_SetRuntimeSecurityCallbacks(sRuntime, &securityCallbacks);
     NS_ASSERTION(!oldcallbacks, "Someone else set security callbacks!");
 
-    sXPConnect->GetXPCWrappedNativeJSClassInfo(&sXPCWrappedNativeEqualityOps);
     return NS_OK;
 }
 
 static nsScriptSecurityManager *gScriptSecMan = nsnull;
 
 jsid nsScriptSecurityManager::sEnabledID   = JSID_VOID;
 
 nsScriptSecurityManager::~nsScriptSecurityManager(void)
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5532,16 +5532,21 @@ nsContentUtils::WrapNative(JSContext *cx
   if (!native) {
     NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
 
     *vp = JSVAL_NULL;
 
     return NS_OK;
   }
 
+  JSObject *wrapper = xpc_GetCachedSlimWrapper(cache, scope, vp);
+  if (wrapper) {
+    return NS_OK;
+  }
+
   NS_ENSURE_TRUE(sXPConnect && sThreadJSContextStack, NS_ERROR_UNEXPECTED);
 
   // Keep sXPConnect and sThreadJSContextStack alive. If we're on the main
   // thread then this can be done simply and cheaply by adding a reference to
   // nsLayoutStatics. If we're not on the main thread then we need to add a
   // more expensive reference sXPConnect directly. We have to use manual
   // AddRef and Release calls so don't early-exit from this function after we've
   // added the reference!
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -43,16 +43,17 @@
 #include "nsIDOMClassInfo.h"
 #include "nsIXPCScriptable.h"
 #include "jsapi.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptContext.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 #include "nsIScriptGlobalObject.h"
 #include "nsContentUtils.h"
+#include "xpcpublic.h"
 
 class nsIDOMWindow;
 class nsIDOMNSHTMLOptionCollection;
 class nsIPluginInstance;
 class nsIForm;
 class nsIDOMNodeList;
 class nsIDOMDocument;
 class nsIHTMLDocument;
@@ -135,18 +136,18 @@ public:
 
   static nsresult WrapNative(JSContext *cx, JSObject *scope,
                              nsISupports *native, const nsIID* aIID,
                              PRBool aAllowWrapping, jsval *vp,
                              // If non-null aHolder will keep the jsval alive
                              // while there's a ref to it
                              nsIXPConnectJSObjectHolder** aHolder = nsnull)
   {
-    return nsContentUtils::WrapNative(cx, scope, native, aIID, vp, aHolder,
-                                      aAllowWrapping);
+    return WrapNative(cx, scope, native, nsnull, aIID, vp, aHolder,
+                      aAllowWrapping);
   }
 
   // Used for cases where PreCreate needs to wrap the native parent, and the
   // native parent is likely to have been wrapped already.  |native| must
   // implement nsWrapperCache, and nativeWrapperCache must be |native|'s
   // nsWrapperCache.
   static inline nsresult WrapNativeParent(JSContext *cx, JSObject *scope,
                                           nsISupports *native,
@@ -156,28 +157,28 @@ public:
   // Same as the WrapNative above, but use these if aIID is nsISupports' IID.
   static nsresult WrapNative(JSContext *cx, JSObject *scope,
                              nsISupports *native, PRBool aAllowWrapping,
                              jsval *vp,
                              // If non-null aHolder will keep the jsval alive
                              // while there's a ref to it
                              nsIXPConnectJSObjectHolder** aHolder = nsnull)
   {
-    return nsContentUtils::WrapNative(cx, scope, native, vp, aHolder,
-                                      aAllowWrapping);
+    return WrapNative(cx, scope, native, nsnull, nsnull, vp, aHolder,
+                      aAllowWrapping);
   }
   static nsresult WrapNative(JSContext *cx, JSObject *scope,
                              nsISupports *native, nsWrapperCache *cache,
                              PRBool aAllowWrapping, jsval *vp,
                              // If non-null aHolder will keep the jsval alive
                              // while there's a ref to it
                              nsIXPConnectJSObjectHolder** aHolder = nsnull)
   {
-    return nsContentUtils::WrapNative(cx, scope, native, cache, vp, aHolder,
-                                      aAllowWrapping);
+    return WrapNative(cx, scope, native, cache, nsnull, vp, aHolder,
+                      aAllowWrapping);
   }
 
   static nsresult ThrowJSException(JSContext *cx, nsresult aResult);
 
   static PRBool ObjectIsNativeWrapper(JSContext* cx, JSObject* obj);
 
   static nsISupports *GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj);
 
@@ -242,16 +243,39 @@ protected:
             id == sOuterHeight_id  ||
             id == sOuterWidth_id   ||
             id == sScreenX_id      ||
             id == sScreenY_id      ||
             id == sStatus_id       ||
             id == sName_id);
   }
 
+  static nsresult WrapNative(JSContext *cx, JSObject *scope,
+                             nsISupports *native, nsWrapperCache *cache,
+                             const nsIID* aIID, jsval *vp,
+                             nsIXPConnectJSObjectHolder** aHolder,
+                             PRBool aAllowWrapping)
+  {
+    if (!native) {
+      NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
+
+      *vp = JSVAL_NULL;
+
+      return NS_OK;
+    }
+
+    JSObject *wrapper = xpc_GetCachedSlimWrapper(cache, scope, vp);
+    if (wrapper) {
+      return NS_OK;
+    }
+
+    return sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID,
+                                         aAllowWrapping, vp, aHolder);
+  }
+
   static nsIXPConnect *sXPConnect;
   static nsIScriptSecurityManager *sSecMan;
 
   // nsIXPCScriptable code
   static nsresult DefineStaticJSVals(JSContext *cx);
 
   static PRBool sIsInitialized;
   static PRBool sDisableDocumentAllSupport;
--- a/js/src/jstl.h
+++ b/js/src/jstl.h
@@ -35,29 +35,29 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jstl_h_
 #define jstl_h_
 
-/* Gross special case for Gecko, which defines malloc/calloc/free. */
-#ifdef mozilla_mozalloc_macro_wrappers_h
-#  define JS_UNDEFD_MOZALLOC_WRAPPERS
-/* The "anti-header" */
-#  include "mozilla/mozalloc_undef_macro_wrappers.h"
-#endif
-
 #include "jsbit.h"
 #include "jsstaticcheck.h"
 
 #include <new>
 #include <string.h>
 
+/* Gross special case for Gecko, which defines malloc/calloc/free. */
+#ifdef mozilla_mozalloc_macro_wrappers_h
+#  define JSSTL_UNDEFD_MOZALLOC_WRAPPERS
+/* The "anti-header" */
+#  include "mozilla/mozalloc_undef_macro_wrappers.h"
+#endif
+
 namespace js {
 
 /* JavaScript Template Library. */
 namespace tl {
 
 /* Compute min/max/clamp. */
 template <size_t i, size_t j> struct Min {
     static const size_t result = i < j ? i : j;
@@ -462,9 +462,13 @@ template <class T>
 static T&
 InitConst(const T &t)
 {
     return const_cast<T &>(t);
 }
 
 } /* namespace js */
 
+#ifdef JSSTL_UNDEFD_MOZALLOC_WRAPPERS
+#  include "mozilla/mozalloc_macro_wrappers.h"
+#endif
+
 #endif /* jstl_h_ */
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -45,16 +45,22 @@
 #include "jsprvtd.h"
 
 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4345)
 #endif
 
+/* Gross special case for Gecko, which defines malloc/calloc/free. */
+#ifdef mozilla_mozalloc_macro_wrappers_h
+#  define JSVECTOR_UNDEFD_MOZALLOC_WRAPPERS
+#  include "mozilla/mozalloc_undef_macro_wrappers.h"
+#endif
+
 namespace js {
 
 /*
  * This template class provides a default implementation for vector operations
  * when the element type is not known to be a POD, as judged by IsPodType.
  */
 template <class T, size_t N, class AP, bool IsPod>
 struct VectorImpl
@@ -738,9 +744,13 @@ Vector<T,N,AP>::replaceRawBuffer(T *p, s
 }
 
 }  /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
+#ifdef JSVECTOR_UNDEFD_MOZALLOC_WRAPPERS
+#  include "mozilla/mozalloc_macro_wrappers.h"
+#endif
+
 #endif /* jsvector_h_ */
--- a/js/src/xpconnect/src/qsgen.py
+++ b/js/src/xpconnect/src/qsgen.py
@@ -702,27 +702,18 @@ def writeResultConv(f, type, jsvalPtr, j
         # else fall through; this type isn't supported yet
     elif isInterfaceType(type):
         if isVariantType(type):
             f.write("    return xpc_qsVariantToJsval(lccx, result, %s);\n"
                     % jsvalPtr)
             return
         else:
             f.write("    nsWrapperCache* cache = xpc_qsGetWrapperCache(result);\n"
-                    "    if (cache) {\n"
-                    "      JSObject* wrapper = cache->GetWrapper();\n"
-                    "      NS_ASSERTION(cx->compartment == obj->compartment(),\n"
-                    "                   \"wrong compartment in object or context!\");\n"
-                    "      if (wrapper &&\n"
-                    # FIXME: Bug 585786, this check should go away
-                    "          IS_SLIM_WRAPPER_OBJECT(wrapper) &&\n"
-                    "          cx->compartment == wrapper->compartment()) {\n"
-                    "        *%s = OBJECT_TO_JSVAL(wrapper);\n"
-                    "        return JS_TRUE;\n"
-                    "      }\n"
+                    "    if (xpc_GetCachedSlimWrapper(cache, obj, %s)) {\n"
+                    "      return JS_TRUE;\n"
                     "    }\n"
                     "    // After this point do not use 'result'!\n"
                     "    qsObjectHelper helper(result, cache);\n"
                     "    return xpc_qsXPCOMObjectToJsval(lccx, "
                     "helper, &NS_GET_IID(%s), &interfaces[k_%s], %s);\n"
                     % (jsvalPtr, type.name, type.name, jsvalPtr))
             return
 
@@ -1254,27 +1245,20 @@ def writeTraceableResultConv(f, type):
             return
         # else fall through; this type isn't supported yet
     elif isInterfaceType(type):
         if isVariantType(type):
             f.write("    JSBool ok = xpc_qsVariantToJsval(lccx, result, "
                     "&vp.array[0]);\n")
         else:
             f.write("    nsWrapperCache* cache = xpc_qsGetWrapperCache(result);\n"
-                    "    if (cache) {\n"
-                    "      JSObject* wrapper = cache->GetWrapper();\n"
-                    "      NS_ASSERTION(cx->compartment == obj->compartment(),\n"
-                    "                   \"wrong compartment in object or context!\");\n"
-                    "      if (wrapper &&\n"
-                    # FIXME: Bug 585786, this check should go away
-                    "          IS_SLIM_WRAPPER_OBJECT(wrapper) &&\n"
-                    "          cx->compartment == wrapper->compartment()) {\n"
-                    "        vp.array[0] = OBJECT_TO_JSVAL(wrapper);\n"
-                    "        return wrapper;\n"
-                    "      }\n"
+                    "    JSObject* wrapper =\n"
+                    "      xpc_GetCachedSlimWrapper(cache, obj, &vp.array[0]);\n"
+                    "    if (wrapper) {\n"
+                    "      return wrapper;\n"
                     "    }\n"
                     "    // After this point do not use 'result'!\n"
                     "    qsObjectHelper helper(result, cache);\n"
                     "    JSBool ok = xpc_qsXPCOMObjectToJsval(lccx, "
                     "helper, &NS_GET_IID(%s), &interfaces[k_%s], "
                     "&vp.array[0]);\n"
                     % (type.name, type.name))
         f.write("    if (!ok) {\n");
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -45,16 +45,17 @@
 
 #ifndef xpcprivate_h___
 #define xpcprivate_h___
 
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <math.h>
+#include "xpcpublic.h"
 #include "jsapi.h"
 #include "jsdhash.h"
 #include "jsprf.h"
 #include "prprf.h"
 #include "jsinterp.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jsgc.h"
@@ -1449,56 +1450,16 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
 // XPC_WN_Shared_Proto_Enumerate or something rather than checking for
 // 4 classes?
 #define IS_PROTO_CLASS(clazz)                                                 \
     ((clazz) == &XPC_WN_NoMods_WithCall_Proto_JSClass ||                      \
      (clazz) == &XPC_WN_NoMods_NoCall_Proto_JSClass ||                        \
      (clazz) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||                 \
      (clazz) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass)
 
-// NOTE!!!
-//
-// If this ever changes,
-// nsScriptSecurityManager::doGetObjectPrincipal() *must* be updated
-// also!
-//
-// NOTE!!!
-#define IS_WRAPPER_CLASS(clazz)                                               \
-    (clazz->ext.equality == js::Valueify(XPC_WN_Equality))
-
-inline JSBool
-DebugCheckWrapperClass(JSObject* obj)
-{
-    NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()),
-                 "Forgot to check if this is a wrapper?");
-    return JS_TRUE;
-}
-
-// If IS_WRAPPER_CLASS for the JSClass of an object is true, the object can be
-// a slim wrapper, holding a native in its private slot, or a wrappednative
-// wrapper, holding the XPCWrappedNative in its private slot. A slim wrapper
-// also holds a pointer to its XPCWrappedNativeProto in a reserved slot, we can
-// check that slot for a non-void value to distinguish between the two.
-
-// Only use these macros if IS_WRAPPER_CLASS(obj->getClass()) is true.
-#define IS_WN_WRAPPER_OBJECT(obj)                                             \
-    (DebugCheckWrapperClass(obj) &&                                           \
-     obj->getSlot(0).isUndefined())
-#define IS_SLIM_WRAPPER_OBJECT(obj)                                           \
-    (DebugCheckWrapperClass(obj) &&                                           \
-     !obj->getSlot(0).isUndefined())
-
-// Use these macros if IS_WRAPPER_CLASS(obj->getClass()) might be false.
-// Avoid calling them if IS_WRAPPER_CLASS(obj->getClass()) can only be
-// true, as we'd do a redundant call to IS_WRAPPER_CLASS.
-#define IS_WN_WRAPPER(obj)                                                    \
-    (IS_WRAPPER_CLASS(obj->getClass()) && IS_WN_WRAPPER_OBJECT(obj))
-#define IS_SLIM_WRAPPER(obj)                                                  \
-    (IS_WRAPPER_CLASS(obj->getClass()) && IS_SLIM_WRAPPER_OBJECT(obj))
-
 // Comes from xpcwrappednativeops.cpp
 extern void
 xpc_TraceForValidWrapper(JSTracer *trc, XPCWrappedNative* wrapper);
 
 /***************************************************************************/
 
 namespace XPCWrapper {
 
@@ -2458,17 +2419,16 @@ private:
     ~XPCWrappedNativeTearOffChunk() {delete mNextChunk;}
 
 private:
     XPCWrappedNativeTearOff mTearOffs[XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK];
     XPCWrappedNativeTearOffChunk* mNextChunk;
 };
 
 void *xpc_GetJSPrivate(JSObject *obj);
-inline JSObject *xpc_GetGlobalForObject(JSObject *obj);
 
 /***************************************************************************/
 // XPCWrappedNative the wrapper around one instance of a native xpcom object
 // to be used from JavaScript.
 
 class XPCWrappedNative : public nsIXPConnectWrappedNative
 {
 public:
@@ -4452,23 +4412,16 @@ NS_DEFINE_STATIC_IID_ACCESSOR(PrincipalH
 /***************************************************************************/
 // Utilities
 
 inline void *
 xpc_GetJSPrivate(JSObject *obj)
 {
     return obj->getPrivate();
 }
-inline JSObject *
-xpc_GetGlobalForObject(JSObject *obj)
-{
-    while(JSObject *parent = obj->getParent())
-        obj = parent;
-    return obj;
-}
 
 
 #ifndef XPCONNECT_STANDALONE
 
 // Helper for creating a sandbox object to use for evaluating
 // untrusted code completely separated from all other code in the
 // system using xpc_EvalInSandbox(). Takes the JSContext on which to
 // do setup etc on, puts the sandbox object in *vp (which must be
--- a/js/src/xpconnect/src/xpcpublic.h
+++ b/js/src/xpconnect/src/xpcpublic.h
@@ -36,24 +36,88 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef xpcpublic_h
 #define xpcpublic_h
 
 #include "jsapi.h"
-#include "nsISupports.h"
+#include "jsobj.h"
+#include "nsAString.h"
+#include "nsIPrincipal.h"
+#include "nsWrapperCache.h"
 
 class nsIPrincipal;
 
 nsresult
 xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
                        nsIPrincipal *principal, nsISupports *ptr,
                        bool wantXrays, JSObject **global,
                        JSCompartment **compartment);
 
 nsresult
 xpc_CreateMTGlobalObject(JSContext *cx, JSClass *clasp,
                          nsISupports *ptr, JSObject **global,
                          JSCompartment **compartment);
 
+extern JSBool
+XPC_WN_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp);
+
+#define IS_WRAPPER_CLASS(clazz)                                               \
+    (clazz->ext.equality == js::Valueify(XPC_WN_Equality))
+
+inline JSBool
+DebugCheckWrapperClass(JSObject* obj)
+{
+    NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()),
+                 "Forgot to check if this is a wrapper?");
+    return JS_TRUE;
+}
+
+// If IS_WRAPPER_CLASS for the JSClass of an object is true, the object can be
+// a slim wrapper, holding a native in its private slot, or a wrappednative
+// wrapper, holding the XPCWrappedNative in its private slot. A slim wrapper
+// also holds a pointer to its XPCWrappedNativeProto in a reserved slot, we can
+// check that slot for a non-void value to distinguish between the two.
+
+// Only use these macros if IS_WRAPPER_CLASS(obj->getClass()) is true.
+#define IS_WN_WRAPPER_OBJECT(obj)                                             \
+    (DebugCheckWrapperClass(obj) && obj->getSlot(0).isUndefined())
+#define IS_SLIM_WRAPPER_OBJECT(obj)                                           \
+    (DebugCheckWrapperClass(obj) && !obj->getSlot(0).isUndefined())
+
+// Use these macros if IS_WRAPPER_CLASS(obj->getClass()) might be false.
+// Avoid calling them if IS_WRAPPER_CLASS(obj->getClass()) can only be
+// true, as we'd do a redundant call to IS_WRAPPER_CLASS.
+#define IS_WN_WRAPPER(obj)                                                    \
+    (IS_WRAPPER_CLASS(obj->getClass()) && IS_WN_WRAPPER_OBJECT(obj))
+#define IS_SLIM_WRAPPER(obj)                                                  \
+    (IS_WRAPPER_CLASS(obj->getClass()) && IS_SLIM_WRAPPER_OBJECT(obj))
+
+inline JSObject *
+xpc_GetGlobalForObject(JSObject *obj)
+{
+    while(JSObject *parent = obj->getParent())
+        obj = parent;
+    return obj;
+}
+
+inline JSObject*
+xpc_GetCachedSlimWrapper(nsWrapperCache *cache, JSObject *scope, jsval *vp)
+{
+    if (cache) {
+        JSObject* wrapper = cache->GetWrapper();
+        // FIXME: Bug 585786, the check for IS_SLIM_WRAPPER_OBJECT should go
+        //        away
+        if (wrapper &&
+            IS_SLIM_WRAPPER_OBJECT(wrapper) &&
+            wrapper->getCompartment() == scope->getCompartment()) {
+            *vp = OBJECT_TO_JSVAL(wrapper);
+
+            return wrapper;
+        }
+    }
+
+    return nsnull;
+}
+
 #endif