Bug 831076 - Outerize at the very beginning of XPConnect wrapping and remove other outerization checks. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Mon, 04 Feb 2013 15:13:13 +0000
changeset 130635 e9a083011b5a3606ddc7befdaf48bd4decb80d57
parent 130634 54f8e15ab69885bba56825beec46b690b81f0f04
child 130636 5df7f6f7c9324d689aad0046262551184db437fb
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs831076
milestone21.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 831076 - Outerize at the very beginning of XPConnect wrapping and remove other outerization checks. r=mrbkap
js/src/jsfriendapi.h
js/xpconnect/wrappers/WrapperFactory.cpp
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -367,16 +367,26 @@ GetObjectClass(RawObject obj)
 }
 
 inline JSClass *
 GetObjectJSClass(RawObject obj)
 {
     return js::Jsvalify(GetObjectClass(obj));
 }
 
+inline bool
+IsInnerObject(JSObject *obj) {
+    return !!GetObjectClass(obj)->ext.outerObject;
+}
+
+inline bool
+IsOuterObject(JSObject *obj) {
+    return !!GetObjectClass(obj)->ext.innerObject;
+}
+
 JS_FRIEND_API(bool)
 IsScopeObject(RawObject obj);
 
 inline JSObject *
 GetObjectParent(RawObject obj)
 {
     JS_ASSERT(!IsScopeObject(obj));
     return reinterpret_cast<shadow::Object*>(obj)->shape->base->parent;
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -33,32 +33,16 @@ namespace xpc {
 Wrapper XrayWaiver(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
 
 // 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.
 WaiveXrayWrapper WaiveXrayWrapper::singleton(0);
 
-static JSObject *
-GetCurrentOuter(JSContext *cx, JSObject *obj)
-{
-    obj = JS_ObjectToOuterObject(cx, obj);
-    if (!obj)
-        return nullptr;
-
-    if (IsWrapper(obj) && !js::GetObjectClass(obj)->ext.innerObject) {
-        obj = UnwrapObject(obj);
-        NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject,
-                     "weird object, expecting an outer window proxy");
-    }
-
-    return obj;
-}
-
 JSObject *
 WrapperFactory::GetXrayWaiver(JSObject *obj)
 {
     // Object should come fully unwrapped but outerized.
     MOZ_ASSERT(obj == UnwrapObject(obj));
     MOZ_ASSERT(!js::GetObjectClass(obj)->ext.outerObject);
     XPCWrappedNativeScope *scope = GetObjectScope(obj);
     MOZ_ASSERT(scope);
@@ -104,20 +88,17 @@ WrapperFactory::CreateXrayWaiver(JSConte
         return nullptr;
     return waiver;
 }
 
 JSObject *
 WrapperFactory::WaiveXray(JSContext *cx, JSObject *obj)
 {
     obj = UnwrapObject(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);
+    MOZ_ASSERT(!js::IsInnerObject(obj));
 
     JSObject *waiver = GetXrayWaiver(obj);
     if (waiver)
         return waiver;
     return CreateXrayWaiver(cx, obj);
 }
 
 // DoubleWrap is called from PrepareForWrapping to maintain the state that
@@ -132,37 +113,43 @@ WrapperFactory::DoubleWrap(JSContext *cx
         return WaiveXray(cx, obj);
     }
     return obj;
 }
 
 JSObject *
 WrapperFactory::PrepareForWrapping(JSContext *cx, JSObject *scope, JSObject *obj, unsigned flags)
 {
-    // Don't unwrap an outer window, just double wrap it if needed.
-    if (js::GetObjectClass(obj)->ext.innerObject)
+    // Outerize any raw inner objects at the entry point here, so that we don't
+    // have to worry about them for the rest of the wrapping code.
+    if (js::IsInnerObject(obj)) {
+        JSAutoCompartment ac(cx, obj);
+        obj = JS_ObjectToOuterObject(cx, obj);
+        NS_ENSURE_TRUE(obj, nullptr);
+        // The outerization hook wraps, which means that we can end up with a
+        // CCW here if |obj| was a navigated-away-from inner. Strip any CCWs.
+        obj = js::UnwrapObject(obj);
+        MOZ_ASSERT(js::IsOuterObject(obj));
+    }
+
+    // If we've got an outer window, there's nothing special that needs to be
+    // done here, and we can move on to the next phase of wrapping. We handle
+    // this case first to allow us to assert against wrappers below.
+    if (js::IsOuterObject(obj))
         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).
     MOZ_ASSERT(!IsWrapper(obj));
 
     // As soon as an object is wrapped in a security wrapper, it morphs to be
     // a fat wrapper. (see also: bug XXX).
     if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj))
         return nullptr;
 
-    // We only hand out outer objects to script.
-    obj = GetCurrentOuter(cx, obj);
-    if (!obj)
-        return nullptr;
-
-    if (js::GetObjectClass(obj)->ext.innerObject)
-        return DoubleWrap(cx, obj, flags);
-
     // Now, our object is ready to be wrapped, but several objects (notably
     // nsJSIIDs) have a wrapper per scope. If we are about to wrap one of
     // those objects in a security wrapper, then we need to hand back the
     // wrapper for the new scope instead. Also, global objects don't move
     // between scopes so for those we also want to return the wrapper. So...
     if (!IS_WN_WRAPPER(obj) || !js::GetObjectParent(obj))
         return DoubleWrap(cx, obj, flags);
 
@@ -347,16 +334,17 @@ WrapperFactory::Rewrap(JSContext *cx, JS
                        JSObject *wrappedProto, JSObject *parent,
                        unsigned flags)
 {
     MOZ_ASSERT(!IsWrapper(obj) ||
                GetProxyHandler(obj) == &XrayWaiver ||
                js::GetObjectClass(obj)->ext.innerObject,
                "wrapped object passed to rewrap");
     MOZ_ASSERT(JS_GetClass(obj) != &XrayUtils::HolderClass, "trying to wrap a holder");
+    MOZ_ASSERT(!js::IsInnerObject(obj));
 
     // Compute the information we need to select the right wrapper.
     JSCompartment *origin = js::GetObjectCompartment(obj);
     JSCompartment *target = js::GetContextCompartment(cx);
     bool originIsChrome = AccessCheck::isChrome(origin);
     bool targetIsChrome = AccessCheck::isChrome(target);
     bool originSubsumesTarget = AccessCheck::subsumes(origin, target);
     bool targetSubsumesOrigin = AccessCheck::subsumes(target, origin);
@@ -513,17 +501,17 @@ WrapperFactory::WrapForSameCompartment(J
 // correct compartment, then this returns the unwrapped object.
 bool
 WrapperFactory::WaiveXrayAndWrap(JSContext *cx, jsval *vp)
 {
     if (JSVAL_IS_PRIMITIVE(*vp))
         return JS_WrapValue(cx, vp);
 
     JSObject *obj = js::UnwrapObject(JSVAL_TO_OBJECT(*vp));
-    obj = GetCurrentOuter(cx, obj);
+    MOZ_ASSERT(!js::IsInnerObject(obj));
     if (js::IsObjectInContextCompartment(obj, cx)) {
         *vp = OBJECT_TO_JSVAL(obj);
         return true;
     }
 
     obj = WaiveXray(cx, obj);
     if (!obj)
         return false;