Bug 1091964 - [e10s] Cache isCallable and isConstructor for CPOWs (r=mrbkap)
☠☠ backed out by 9b6a24e2f106 ☠ ☠
authorBill McCloskey <wmccloskey@mozilla.com>
Tue, 04 Nov 2014 17:39:34 -0800
changeset 213947 5992aea01affcabf8ffe6faba1cd697b8d612628
parent 213946 2dbf8f6bd2aa84cd40137ece81e81d6d2cbb7ea8
child 213948 38ca6211d1d4ae7571b1cbc26ae4371b960006c1
push id51389
push userwmccloskey@mozilla.com
push dateWed, 05 Nov 2014 01:40:21 +0000
treeherdermozilla-inbound@38ca6211d1d4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1091964
milestone36.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 1091964 - [e10s] Cache isCallable and isConstructor for CPOWs (r=mrbkap)
js/ipc/JavaScriptBase.h
js/ipc/JavaScriptTypes.ipdlh
js/ipc/PJavaScript.ipdl
js/ipc/WrapperAnswer.cpp
js/ipc/WrapperAnswer.h
js/ipc/WrapperOwner.cpp
js/ipc/WrapperOwner.h
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -111,24 +111,16 @@ class JavaScriptBase : public WrapperOwn
                           ReturnStatus *rs, bool *instanceof) {
         return Answer::RecvInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof);
     }
     bool RecvDOMInstanceOf(const uint64_t &objId, const int &prototypeID, const int &depth,
                              ReturnStatus *rs, bool *instanceof) {
         return Answer::RecvDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof);
     }
 
-    bool RecvIsCallable(const uint64_t &objId, bool *result) {
-        return Answer::RecvIsCallable(ObjectId::deserialize(objId), result);
-    }
-
-    bool RecvIsConstructor(const uint64_t &objId, bool *result) {
-        return Answer::RecvIsConstructor(ObjectId::deserialize(objId), result);
-    }
-
     bool RecvDropObject(const uint64_t &objId) {
         return Answer::RecvDropObject(ObjectId::deserialize(objId));
     }
 
     /*** Dummy call handlers ***/
 
     bool SendDropObject(const ObjectId &objId) {
         return Base::SendDropObject(objId.serialize());
@@ -210,24 +202,16 @@ class JavaScriptBase : public WrapperOwn
                         ReturnStatus *rs, bool *instanceof) {
         return Base::SendInstanceOf(objId.serialize(), iid, rs, instanceof);
     }
     bool SendDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
                            ReturnStatus *rs, bool *instanceof) {
         return Base::SendDOMInstanceOf(objId.serialize(), prototypeID, depth, rs, instanceof);
     }
 
-    bool SendIsCallable(const ObjectId &objId, bool *result) {
-        return Base::SendIsCallable(objId.serialize(), result);
-    }
-
-    bool SendIsConstructor(const ObjectId &objId, bool *result) {
-        return Base::SendIsConstructor(objId.serialize(), result);
-    }
-
     /* The following code is needed to suppress a bogus MSVC warning (C4250). */
 
     virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp) {
         return WrapperOwner::toObjectVariant(cx, obj, objVarp);
     }
     virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar) {
         return WrapperOwner::fromObjectVariant(cx, objVar);
     }
--- a/js/ipc/JavaScriptTypes.ipdlh
+++ b/js/ipc/JavaScriptTypes.ipdlh
@@ -30,16 +30,18 @@ struct JSIID
 struct LocalObject
 {
     uint64_t serializedId;
 };
 
 struct RemoteObject
 {
     uint64_t serializedId;
+    bool isCallable;
+    bool isConstructor;
 };
 
 union ObjectVariant
 {
     LocalObject;
     RemoteObject;
 };
 
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -41,17 +41,14 @@ both:
     prio(high) sync ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
     prio(high) sync ClassName(uint64_t objId) returns (nsString name);
     prio(high) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
 
     prio(high) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, JSIDVariant[] ids);
     prio(high) sync InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
     prio(high) sync DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
 
-    prio(high) sync IsCallable(uint64_t objId) returns (bool result);
-    prio(high) sync IsConstructor(uint64_t objId) returns (bool result);
-
 parent:
     async __delete__();
 };
 
 }
 }
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -658,57 +658,16 @@ WrapperAnswer::RecvDOMInstanceOf(const O
     if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
         return fail(cx, rs);
     *instanceof = tmp;
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::RecvIsCallable(const ObjectId &objId, bool *result)
-{
-    AutoSafeJSContext cx;
-    JSAutoRequest request(cx);
-
-    RootedObject obj(cx, findObjectById(cx, objId));
-    if (!obj) {
-        // This is very unfortunate, but we have no choice.
-        *result = false;
-        return true;
-    }
-    JSAutoCompartment ac(cx, obj); // Not really necessary here, but be safe.
-
-    LOG("%s.isCallable()", ReceiverObj(objId));
-
-    *result = JS::IsCallable(obj);
-    return true;
-}
-
-bool
-WrapperAnswer::RecvIsConstructor(const ObjectId &objId, bool *result)
-{
-    AutoSafeJSContext cx;
-    JSAutoRequest request(cx);
-
-    RootedObject obj(cx, findObjectById(cx, objId));
-    if (!obj) {
-        // This is very unfortunate, but we have no choice.
-        *result = false;
-        return true;
-    }
-    JSAutoCompartment ac(cx, obj); // Not really necessary here, but be safe.
-
-    LOG("%s.isConstructor()", ReceiverObj(objId));
-
-    *result = JS::IsConstructor(obj);
-    return true;
-}
-
-
-bool
 WrapperAnswer::RecvDropObject(const ObjectId &objId)
 {
     JSObject *obj = objects_.find(objId);
     if (obj) {
         objectIdMap(objId.hasXrayWaiver()).remove(obj);
         objects_.remove(objId);
     }
     return true;
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -57,19 +57,16 @@ class WrapperAnswer : public virtual Jav
 
     bool RecvGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
                              ReturnStatus *rs, nsTArray<JSIDVariant> *ids);
     bool RecvInstanceOf(const ObjectId &objId, const JSIID &iid,
                         ReturnStatus *rs, bool *instanceof);
     bool RecvDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
                            ReturnStatus *rs, bool *instanceof);
 
-    bool RecvIsCallable(const ObjectId &objId, bool *result);
-    bool RecvIsConstructor(const ObjectId &objId, bool *result);
-
     bool RecvDropObject(const ObjectId &objId);
 
   private:
     bool fail(JSContext *cx, ReturnStatus *rs);
     bool ok(ReturnStatus *rs);
 };
 
 } // mozilla
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -13,41 +13,57 @@
 #include "xpcprivate.h"
 #include "WrapperFactory.h"
 
 using namespace js;
 using namespace JS;
 using namespace mozilla;
 using namespace mozilla::jsipc;
 
+struct AuxCPOWData
+{
+    ObjectId id;
+    bool isCallable;
+    bool isConstructor;
+
+    AuxCPOWData(ObjectId id, bool isCallable, bool isConstructor)
+      : id(id),
+        isCallable(isCallable),
+        isConstructor(isConstructor)
+    {}
+};
+
 WrapperOwner::WrapperOwner(JSRuntime *rt)
   : JavaScriptShared(rt),
     inactive_(false)
 {
 }
 
+static inline AuxCPOWData *
+AuxCPOWDataOf(JSObject *obj)
+{
+    MOZ_ASSERT(IsCPOW(obj));
+    return static_cast<AuxCPOWData *>(GetProxyExtra(obj, 1).toPrivate());
+}
+
 static inline WrapperOwner *
 OwnerOf(JSObject *obj)
 {
     MOZ_ASSERT(IsCPOW(obj));
     return reinterpret_cast<WrapperOwner *>(GetProxyExtra(obj, 0).toPrivate());
 }
 
 ObjectId
 WrapperOwner::idOfUnchecked(JSObject *obj)
 {
     MOZ_ASSERT(IsCPOW(obj));
 
-    Value v = GetProxyExtra(obj, 1);
-    MOZ_ASSERT(v.isDouble());
-
-    ObjectId objId = ObjectId::deserialize(BitwiseCast<uint64_t>(v.toDouble()));
-    MOZ_ASSERT(!objId.isNull());
-
-    return objId;
+    AuxCPOWData *aux = AuxCPOWDataOf(obj);
+    MOZ_ASSERT(!aux->id.isNull());
+    return aux->id;
 }
 
 ObjectId
 WrapperOwner::idOf(JSObject *obj)
 {
     ObjectId objId = idOfUnchecked(obj);
     MOZ_ASSERT(findCPOWById(objId) == obj);
     return objId;
@@ -684,68 +700,40 @@ WrapperOwner::regexp_toShared(JSContext 
 
     return js::RegExpToSharedNonInline(cx, regexp, g);
 }
 
 void
 CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy) const
 {
     OwnerOf(proxy)->drop(proxy);
+
+    AuxCPOWData *aux = AuxCPOWDataOf(proxy);
+    if (aux)
+        delete aux;
 }
 
 void
 CPOWProxyHandler::objectMoved(JSObject *proxy, const JSObject *old) const
 {
     OwnerOf(proxy)->updatePointer(proxy, old);
 }
 
 bool
 CPOWProxyHandler::isCallable(JSObject *proxy) const
 {
-    WrapperOwner *parent = OwnerOf(proxy);
-    if (!parent->active())
-        return false;
-    return parent->isCallable(proxy);
-}
-
-bool
-WrapperOwner::isCallable(JSObject *obj)
-{
-    ObjectId objId = idOf(obj);
-
-    bool callable = false;
-    if (!SendIsCallable(objId, &callable)) {
-        NS_WARNING("IPC isCallable() failed");
-        return false;
-    }
-
-    return callable;
+    AuxCPOWData *aux = AuxCPOWDataOf(proxy);
+    return aux->isCallable;
 }
 
 bool
 CPOWProxyHandler::isConstructor(JSObject *proxy) const
 {
-    WrapperOwner *parent = OwnerOf(proxy);
-    if (!parent->active())
-        return false;
-    return parent->isConstructor(proxy);
-}
-
-bool
-WrapperOwner::isConstructor(JSObject *obj)
-{
-    ObjectId objId = idOf(obj);
-
-    bool constructor = false;
-    if (!SendIsConstructor(objId, &constructor)) {
-        NS_WARNING("IPC isConstructor() failed");
-        return false;
-    }
-
-    return constructor;
+    AuxCPOWData *aux = AuxCPOWDataOf(proxy);
+    return aux->isConstructor;
 }
 
 void
 WrapperOwner::drop(JSObject *obj)
 {
     ObjectId objId = idOf(obj);
 
     cpows_.remove(objId);
@@ -890,16 +878,22 @@ WrapperOwner::ok(JSContext *cx, const Re
     RootedValue exn(cx);
     if (!fromVariant(cx, status.get_ReturnException().exn(), &exn))
         return false;
 
     JS_SetPendingException(cx, exn);
     return false;
 }
 
+static RemoteObject
+MakeRemoteObject(ObjectId id, JSObject *obj)
+{
+    return RemoteObject(id.serialize(), JS::IsCallable(obj), JS::IsConstructor(obj));
+}
+
 bool
 WrapperOwner::toObjectVariant(JSContext *cx, JSObject *objArg, ObjectVariant *objVarp)
 {
     RootedObject obj(cx, objArg);
     MOZ_ASSERT(obj);
 
     // We always save objects unwrapped in the CPOW table. If we stored
     // wrappers, then the wrapper might be GCed while the target remained alive.
@@ -911,32 +905,32 @@ WrapperOwner::toObjectVariant(JSContext 
         *objVarp = LocalObject(idOf(obj).serialize());
         return true;
     }
     bool waiveXray = wrapperFlags & xpc::WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG;
 
     ObjectId id = objectIdMap(waiveXray).find(obj);
     if (!id.isNull()) {
         MOZ_ASSERT(id.hasXrayWaiver() == waiveXray);
-        *objVarp = RemoteObject(id.serialize());
+        *objVarp = MakeRemoteObject(id, obj);
         return true;
     }
 
     // Need to call PreserveWrapper on |obj| in case it's a reflector.
     // FIXME: What if it's an XPCWrappedNative?
     if (mozilla::dom::IsDOMObject(obj))
         mozilla::dom::TryPreserveWrapper(obj);
 
     id = ObjectId(nextSerialNumber_++, waiveXray);
     if (!objects_.add(id, obj))
         return false;
     if (!objectIdMap(waiveXray).add(cx, obj, id))
         return false;
 
-    *objVarp = RemoteObject(id.serialize());
+    *objVarp = MakeRemoteObject(id, obj);
     return true;
 }
 
 JSObject *
 WrapperOwner::fromObjectVariant(JSContext *cx, ObjectVariant objVar)
 {
     if (objVar.type() == ObjectVariant::TRemoteObject) {
         return fromRemoteObjectVariant(cx, objVar.get_RemoteObject());
@@ -965,18 +959,20 @@ WrapperOwner::fromRemoteObjectVariant(JS
             return nullptr;
 
         if (!cpows_.add(objId, obj))
             return nullptr;
 
         // Incref once we know the decref will be called.
         incref();
 
+        AuxCPOWData *aux = new AuxCPOWData(objId, objVar.isCallable(), objVar.isConstructor());
+
         SetProxyExtra(obj, 0, PrivateValue(this));
-        SetProxyExtra(obj, 1, DoubleValue(BitwiseCast<double>(objId.serialize())));
+        SetProxyExtra(obj, 1, PrivateValue(aux));
     }
 
     if (!JS_WrapObject(cx, &obj))
         return nullptr;
     return obj;
 }
 
 JSObject *
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -56,18 +56,16 @@ class WrapperOwner : public virtual Java
     bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy,
                                       JS::AutoIdVector &props);
     // We use "iterate" provided by the base class here.
     bool hasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp);
     bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
     const char* className(JSContext *cx, JS::HandleObject proxy);
     bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g);
-    bool isCallable(JSObject *obj);
-    bool isConstructor(JSObject *obj);
 
     nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
 
     bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
 
     /*
      * Check that |obj| is a DOM wrapper whose prototype chain contains
      * |prototypeID| at depth |depth|.
@@ -146,19 +144,16 @@ class WrapperOwner : public virtual Java
                                     uint32_t *flags) = 0;
 
     virtual bool SendGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
                                      ReturnStatus *rs, nsTArray<JSIDVariant> *ids) = 0;
     virtual bool SendInstanceOf(const ObjectId &objId, const JSIID &iid,
                                 ReturnStatus *rs, bool *instanceof) = 0;
     virtual bool SendDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
                                    ReturnStatus *rs, bool *instanceof) = 0;
-
-    virtual bool SendIsCallable(const ObjectId &objId, bool *result) = 0;
-    virtual bool SendIsConstructor(const ObjectId &objId, bool *result) = 0;
 };
 
 bool
 IsCPOW(JSObject *obj);
 
 bool
 IsWrappedCPOW(JSObject *obj);