Maintain identity and proto of .wrappedJSObject wrappers (bug 620486, r=mrbkap).
authorAndreas Gal <gal@mozilla.com>
Thu, 13 Jan 2011 13:03:44 -0800
changeset 60580 a6bd34672545f87a6606a427cedfa426ddf9d65a
parent 60579 e60709603fe1c47396bfec2253eb16f8dff130fe
child 60581 f2da7d8646f63b6871b581431e876d51fa8605f7
push id18037
push usercleary@mozilla.com
push dateFri, 14 Jan 2011 17:42:55 +0000
treeherdermozilla-central@4e0501a0c5e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs620486
milestone2.0b10pre
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
Maintain identity and proto of .wrappedJSObject wrappers (bug 620486, r=mrbkap).
js/src/xpconnect/wrappers/WrapperFactory.cpp
js/src/xpconnect/wrappers/WrapperFactory.h
--- a/js/src/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/src/xpconnect/wrappers/WrapperFactory.cpp
@@ -63,40 +63,83 @@ JSWrapper WaiveXrayWrapperWrapper(Wrappe
 
 // When objects for which we waived the X-ray wrapper cross into
 // chrome, we wrap them into a special cross-compartment wrapper
 // that transitively extends the waiver to all properties we get
 // off it.
 CrossOriginWrapper CrossOriginWrapper::singleton(0);
 
 static JSObject *
-DoubleWrap(JSContext *cx, JSObject *obj, uintN flags)
-{
-    if (flags & WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG) {
-        js::SwitchToCompartment sc(cx, obj->compartment());
-        return JSWrapper::New(cx, obj, NULL, obj->getGlobal(),
-                              &WaiveXrayWrapperWrapper);
-    }
-    return obj;
-}
-
-static JSObject *
 GetCurrentOuter(JSContext *cx, JSObject *obj)
 {
     OBJ_TO_OUTER_OBJECT(cx, obj);
     if (obj->isWrapper() && !obj->getClass()->ext.innerObject) {
         obj = obj->unwrap();
         NS_ASSERTION(obj->getClass()->ext.innerObject,
                      "weird object, expecting an outer window proxy");
     }
 
     return obj;
 }
 
 JSObject *
+WrapperFactory::WaiveXray(JSContext *cx, JSObject *obj)
+{
+    // We have to make sure that if we're wrapping an outer window, that
+    // the .wrappedJSObject also wraps the outer window.
+    obj = GetCurrentOuter(cx, obj);
+
+    {
+        // See if we already have a waiver wrapper for this object.
+        CompartmentPrivate *priv =
+            (CompartmentPrivate *)JS_GetCompartmentPrivate(cx, obj->compartment());
+        JSObject *wobj = nsnull;
+        if (priv && priv->waiverWrapperMap)
+            wobj = priv->waiverWrapperMap->Find(obj);
+
+        // No wrapper yet, make one.
+        if (!wobj) {
+            JSObject *proto = obj->getProto();
+            if (proto && !(proto = WaiveXray(cx, proto)))
+                return nsnull;
+
+            js::SwitchToCompartment sc(cx, obj->compartment());
+            wobj = JSWrapper::New(cx, obj, proto, obj->getGlobal(), &WaiveXrayWrapperWrapper);
+            if (!wobj)
+                return nsnull;
+
+            // Add the new wrapper so we find it next time.
+            if (priv) {
+                if (!priv->waiverWrapperMap) {
+                    priv->waiverWrapperMap = JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_SIZE);
+                    if (!priv->waiverWrapperMap)
+                        return nsnull;
+                }
+                if (!priv->waiverWrapperMap->Add(obj, wobj))
+                    return nsnull;
+            }
+        }
+
+        obj = wobj;
+    }
+
+    return obj;
+}
+
+JSObject *
+WrapperFactory::DoubleWrap(JSContext *cx, JSObject *obj, uintN flags)
+{
+    if (flags & WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG) {
+        js::SwitchToCompartment sc(cx, obj->compartment());
+        return WaiveXray(cx, obj);
+    }
+    return obj;
+}
+
+JSObject *
 WrapperFactory::PrepareForWrapping(JSContext *cx, JSObject *scope, JSObject *obj, uintN flags)
 {
     // Don't unwrap an outer window, just double wrap it if needed.
     if (obj->getClass()->ext.innerObject)
         return DoubleWrap(cx, obj, flags);
 
     // Here are the rules for wrapping:
     // We should never get a proxy here (the JS engine unwraps those for us).
@@ -282,66 +325,36 @@ WrapperFactory::IsLocationObject(JSObjec
     return name[0] == 'L' && !strcmp(name, "Location");
 }
 
 JSObject *
 WrapperFactory::WrapLocationObject(JSContext *cx, JSObject *obj)
 {
     JSObject *xrayHolder = LW::createHolder(cx, obj, obj->getParent());
     if (!xrayHolder)
-        return NULL;
+        return nsnull;
     JSObject *wrapperObj = JSWrapper::New(cx, obj, obj->getProto(), obj->getParent(),
                                           &LW::singleton);
     if (!wrapperObj)
-        return NULL;
+        return nsnull;
     wrapperObj->setProxyExtra(js::ObjectValue(*xrayHolder));
     return wrapperObj;
 }
 
 bool
 WrapperFactory::WaiveXrayAndWrap(JSContext *cx, jsval *vp)
 {
     if (JSVAL_IS_PRIMITIVE(*vp))
         return JS_WrapValue(cx, vp);
 
     JSObject *obj = JSVAL_TO_OBJECT(*vp)->unwrap();
 
-    // We have to make sure that if we're wrapping an outer window, that
-    // the .wrappedJSObject also wraps the outer window.
-    obj = GetCurrentOuter(cx, obj);
-
-    {
-        // See if we already have a waiver wrapper for this object.
-        CompartmentPrivate *priv =
-            (CompartmentPrivate *)JS_GetCompartmentPrivate(cx, obj->compartment());
-        JSObject *wobj = nsnull;
-        if (priv && priv->waiverWrapperMap)
-            wobj = priv->waiverWrapperMap->Find(obj);
-
-        // No wrapper yet, make one.
-        if (!wobj) {
-            js::SwitchToCompartment sc(cx, obj->compartment());
-            wobj = JSWrapper::New(cx, obj, NULL, obj->getGlobal(), &WaiveXrayWrapperWrapper);
-            if (!wobj)
-                return false;
-
-            // Add the new wrapper so we find it next time.
-            if (priv) {
-                if (!priv->waiverWrapperMap) {
-                    priv->waiverWrapperMap = JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_SIZE);
-                    if (!priv->waiverWrapperMap)
-                        return false;
-                }
-                if (!priv->waiverWrapperMap->Add(obj, wobj))
-                    return false;
-            }
-        }
-
-        obj = wobj;
-    }
+    obj = WaiveXray(cx, obj);
+    if (!obj)
+        return false;
 
     *vp = OBJECT_TO_JSVAL(obj);
     return JS_WrapValue(cx, vp);
 }
 
 JSObject *
 WrapperFactory::WrapSOWObject(JSContext *cx, JSObject *obj)
 {
--- a/js/src/xpconnect/wrappers/WrapperFactory.h
+++ b/js/src/xpconnect/wrappers/WrapperFactory.h
@@ -64,16 +64,20 @@ class WrapperFactory {
     static bool IsPartiallyTransparent(JSObject *wrapper) {
         return HasWrapperFlag(wrapper, PARTIALLY_TRANSPARENT);
     }
 
     static bool HasWaiveXrayFlag(JSObject *wrapper) {
         return HasWrapperFlag(wrapper, WAIVE_XRAY_WRAPPER_FLAG);
     }
 
+    static JSObject *WaiveXray(JSContext *cx, JSObject *obj);
+
+    static JSObject *DoubleWrap(JSContext *cx, JSObject *obj, uintN flags);
+
     // Prepare a given object for wrapping in a new compartment.
     static JSObject *PrepareForWrapping(JSContext *cx,
                                         JSObject *scope,
                                         JSObject *obj,
                                         uintN flags);
 
     // Rewrap an object that is about to cross compartment boundaries.
     static JSObject *Rewrap(JSContext *cx,