Bug 761695 - Move wrapper preservation stuff into a virtual trap. r=peterv
authorBobby Holley <bobbyholley@gmail.com>
Fri, 05 Oct 2012 18:59:23 +0200
changeset 109400 509ebfec55a1cf2006e49b8d7897c4e9d0a949ae
parent 109399 5763702031329ea3e5072bde2d73be170f5c50ef
child 109401 bc5648cb99722667dc9ea4dca572214504b1c16d
push id16008
push userbobbyholley@gmail.com
push dateFri, 05 Oct 2012 16:59:43 +0000
treeherdermozilla-inbound@3b4562fd4f20 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs761695
milestone18.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 761695 - Move wrapper preservation stuff into a virtual trap. r=peterv I'm not sure this stuff is correct for non-WN objects. Hopefully that will come out in review. Anyway, with this change, the expando infrastructure in XrayTraits is now fully generic and non-WN-specific. To make things work for other objects, we now need to implement the virtual traps and hoist the code that calls the expando machinery out of XPCWrappedNativeXrayTraits.
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -8,16 +8,17 @@
 #include "XrayWrapper.h"
 #include "AccessCheck.h"
 #include "FilteringWrapper.h"
 #include "WaiveXrayWrapper.h"
 #include "WrapperFactory.h"
 
 #include "nsINode.h"
 #include "nsIDocument.h"
+#include "nsContentUtils.h"
 
 #include "XPCWrapper.h"
 #include "xpcprivate.h"
 
 #include "jsapi.h"
 #include "nsJSUtils.h"
 
 #include "mozilla/dom/BindingUtils.h"
@@ -138,16 +139,18 @@ public:
         MOZ_NOT_REACHED("Call trap currently implemented only for XPCWNs");
     }
     static bool construct(JSContext *cx, JSObject *wrapper, unsigned argc,
                           Value *argv, Value *rval)
     {
         MOZ_NOT_REACHED("Call trap currently implemented only for XPCWNs");
     }
 
+    virtual void preserveWrapper(JSObject *target) = 0;
+
     JSObject* getExpandoObject(JSContext *cx, JSObject *target,
                                JSObject *consumer);
     JSObject* ensureExpandoObject(JSContext *cx, JSObject *wrapper,
                                   JSObject *target);
 
     JSObject* getHolder(JSObject *wrapper);
     JSObject* ensureHolder(JSContext *cx, JSObject *wrapper);
     virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper) = 0;
@@ -189,16 +192,18 @@ public:
 
     static bool resolveDOMCollectionProperty(JSContext *cx, JSObject *wrapper, JSObject *holder,
                                              jsid id, bool set, PropertyDescriptor *desc);
 
     static XPCWrappedNative* getWN(JSObject *wrapper) {
         return GetWrappedNative(getTargetObject(wrapper));
     }
 
+    virtual void preserveWrapper(JSObject *target);
+
     typedef ResolvingId ResolvingIdImpl;
 
     virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
     virtual JSObject* getExpandoChain(JSObject *obj) {
         return GetWNExpandoChain(obj);
     }
     virtual void setExpandoChain(JSObject *obj, JSObject *chain) {
         SetWNExpandoChain(obj, chain);
@@ -221,16 +226,18 @@ public:
     static bool enumerateNames(JSContext *cx, JSObject *wrapper, unsigned flags,
                                JS::AutoIdVector &props);
 
     static bool isResolving(JSContext *cx, JSObject *holder, jsid id)
     {
         return false;
     }
 
+    virtual void preserveWrapper(JSObject *target) { };
+
     typedef ResolvingIdDummy ResolvingIdImpl;
 
     virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
 
     virtual JSObject* getExpandoChain(JSObject *obj) {
         MOZ_NOT_REACHED("Expando chain not yet implemented for non-WN objects");
         return NULL;
     }
@@ -257,16 +264,18 @@ public:
 
     static bool isResolving(JSContext *cx, JSObject *holder, jsid id)
     {
         return false;
     }
 
     typedef ResolvingIdDummy ResolvingIdImpl;
 
+    virtual void preserveWrapper(JSObject *target);
+
     virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
 
     virtual JSObject* getExpandoChain(JSObject *obj) {
         MOZ_NOT_REACHED("Expando chain not yet implemented for non-WN objects");
         return NULL;
     }
     virtual void setExpandoChain(JSObject *obj, JSObject *chain) {
         MOZ_NOT_REACHED("Expando chain not yet implemented for non-WN objects");
@@ -414,19 +423,16 @@ XrayTraits::getExpandoObject(JSContext *
 JSObject *
 XrayTraits::attachExpandoObject(JSContext *cx, JSObject *target,
                                 nsIPrincipal *origin, JSObject *exclusiveGlobal)
 {
     // Make sure the compartments are sane.
     MOZ_ASSERT(js::IsObjectInContextCompartment(target, cx));
     MOZ_ASSERT(!exclusiveGlobal || js::IsObjectInContextCompartment(exclusiveGlobal, cx));
 
-    // We should only be used for WNs.
-    MOZ_ASSERT(IS_WN_WRAPPER(target));
-
     // No duplicates allowed.
     MOZ_ASSERT(!getExpandoObjectInternal(cx, target, origin, exclusiveGlobal));
 
     // Create the expando object. We parent it directly to the target object.
     JSObject *expandoObject = JS_NewObjectWithGivenProto(cx, &ExpandoObjectClass,
                                                          nullptr, target);
     if (!expandoObject)
         return nullptr;
@@ -438,24 +444,18 @@ XrayTraits::attachExpandoObject(JSContex
     // Note the exclusive global, if any.
     JS_SetReservedSlot(expandoObject, JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL,
                        OBJECT_TO_JSVAL(exclusiveGlobal));
 
     // If this is our first expando object, take the opportunity to preserve
     // the wrapper. This keeps our expandos alive even if the Xray wrapper gets
     // collected.
     JSObject *chain = getExpandoChain(target);
-    if (!chain) {
-        XPCWrappedNative *wn =
-          static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(target));
-        nsRefPtr<nsXPCClassInfo> ci;
-        CallQueryInterface(wn->Native(), getter_AddRefs(ci));
-        if (ci)
-            ci->PreserveWrapper(wn->Native());
-    }
+    if (!chain)
+        preserveWrapper(target);
 
     // Insert it at the front of the chain.
     JS_SetReservedSlot(expandoObject, JSSLOT_EXPANDO_NEXT, OBJECT_TO_JSVAL(chain));
     setExpandoChain(target, expandoObject);
 
     return expandoObject;
 }
 
@@ -745,16 +745,27 @@ mozMatchesSelectorStub(JSContext *cx, un
         XPCThrower::Throw(rv, cx);
         return false;
     }
 
     JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(ret));
     return true;
 }
 
+void
+XPCWrappedNativeXrayTraits::preserveWrapper(JSObject *target)
+{
+    XPCWrappedNative *wn =
+      static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(target));
+    nsRefPtr<nsXPCClassInfo> ci;
+    CallQueryInterface(wn->Native(), getter_AddRefs(ci));
+    if (ci)
+        ci->PreserveWrapper(wn->Native());
+}
+
 bool
 XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext *cx, JSObject *wrapper,
                                                   JSObject *holder, jsid id, bool set,
                                                   JSPropertyDescriptor *desc)
 {
     MOZ_ASSERT(js::GetObjectJSClass(holder) == &HolderClass);
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     if (!set &&
@@ -1353,16 +1364,28 @@ DOMXrayTraits::enumerateNames(JSContext 
         if (!nativeHooks->mEnumerateProperties(cx, wrapper, props)) {
             return false;
         }
     } while ((nativeHooks = nativeHooks->mProtoHooks));
 
     return true;
 }
 
+void
+DOMXrayTraits::preserveWrapper(JSObject *target)
+{
+    nsISupports *identity;
+    if (!mozilla::dom::UnwrapDOMObjectToISupports(target, identity))
+        return;
+    nsWrapperCache* cache = nullptr;
+    CallQueryInterface(identity, &cache);
+    if (cache)
+        nsContentUtils::PreserveWrapper(identity, cache);
+}
+
 JSObject*
 DOMXrayTraits::createHolder(JSContext *cx, JSObject *wrapper)
 {
     return JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
                                       JS_GetGlobalForObject(cx, wrapper));
 }
 
 template <typename Base, typename Traits>