Bug 1091964 - [e10s] Cache isCallable and isConstructor for CPOWs (r=mrbkap)
authorBill McCloskey <wmccloskey@mozilla.com>
Tue, 04 Nov 2014 17:39:34 -0800
changeset 214223 054f17d341c1cc190480ef74438a3863f4d82d57
parent 214222 22047daf1460115a1c8e56a6d0ced3b9177aa989
child 214224 c97553c13fb65447505f83ccd950190cbe830c63
push id51437
push userwmccloskey@mozilla.com
push dateThu, 06 Nov 2014 00:10:46 +0000
treeherdermozilla-inbound@9fa06a2e1a98 [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);