Bug 996785 - Move CPOW wrapper owner code (r=mrbkap)
authorBill McCloskey <wmccloskey@mozilla.com>
Fri, 16 May 2014 16:40:36 -0700
changeset 183646 15ecb06251c8b7e886dec794e42c923fa8ab6217
parent 183645 85e6824afa65a9ab3b1eb7afc705143a7d104f0a
child 183647 05fa4a69cb9818df96d82c9fc37fdad57ed85f68
push id26799
push userphilringnalda@gmail.com
push dateSun, 18 May 2014 00:55:16 +0000
treeherdermozilla-central@00ef3a7d7aa7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs996785
milestone32.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 996785 - Move CPOW wrapper owner code (r=mrbkap)
js/ipc/JavaScriptBase.h
js/ipc/JavaScriptParent.cpp
js/ipc/JavaScriptParent.h
js/ipc/WrapperOwner.cpp
js/ipc/WrapperOwner.h
js/ipc/moz.build
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptBase.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=80:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_jsipc_JavaScriptBase_h__
+#define mozilla_jsipc_JavaScriptBase_h__
+
+#include "WrapperOwner.h"
+#include "mozilla/dom/DOMTypes.h"
+#include "mozilla/jsipc/PJavaScript.h"
+
+namespace mozilla {
+namespace jsipc {
+
+template<class Base>
+class JavaScriptBase : public WrapperOwner, public Base
+{
+    typedef WrapperOwner Shared;
+
+  public:
+    /*** Dummy call handlers ***/
+
+    bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
+        return Base::CallPreventExtensions(objId, rs);
+    }
+    bool CallGetPropertyDescriptor(const ObjectId &objId, const nsString &id,
+                                     ReturnStatus *rs,
+                                     PPropertyDescriptor *out) {
+        return Base::CallGetPropertyDescriptor(objId, id, rs, out);
+    }
+    bool CallGetOwnPropertyDescriptor(const ObjectId &objId,
+                                      const nsString &id,
+                                      ReturnStatus *rs,
+                                      PPropertyDescriptor *out) {
+        return Base::CallGetOwnPropertyDescriptor(objId, id, rs, out);
+    }
+    bool CallDefineProperty(const ObjectId &objId, const nsString &id,
+                            const PPropertyDescriptor &flags,
+                              ReturnStatus *rs) {
+        return Base::CallDefineProperty(objId, id, flags, rs);
+    }
+    bool CallDelete(const ObjectId &objId, const nsString &id,
+                    ReturnStatus *rs, bool *success) {
+        return Base::CallDelete(objId, id, rs, success);
+    }
+
+    bool CallHas(const ObjectId &objId, const nsString &id,
+                   ReturnStatus *rs, bool *bp) {
+        return Base::CallHas(objId, id, rs, bp);
+    }
+    bool CallHasOwn(const ObjectId &objId, const nsString &id,
+                    ReturnStatus *rs, bool *bp) {
+        return Base::CallHasOwn(objId, id, rs, bp);
+    }
+    bool CallGet(const ObjectId &objId, const ObjectId &receiverId,
+                 const nsString &id,
+                 ReturnStatus *rs, JSVariant *result) {
+        return Base::CallGet(objId, receiverId, id, rs, result);
+    }
+    bool CallSet(const ObjectId &objId, const ObjectId &receiverId,
+                 const nsString &id, const bool &strict,
+                 const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
+        return Base::CallSet(objId, receiverId, id, strict, value, rs, result);
+    }
+
+    bool CallIsExtensible(const ObjectId &objId, ReturnStatus *rs,
+                          bool *result) {
+        return Base::CallIsExtensible(objId, rs, result);
+    }
+    bool CallCall(const ObjectId &objId, const nsTArray<JSParam> &argv,
+                  ReturnStatus *rs, JSVariant *result,
+                  nsTArray<JSParam> *outparams) {
+        return Base::CallCall(objId, argv, rs, result, outparams);
+    }
+    bool CallObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
+                           bool *result) {
+        return Base::CallObjectClassIs(objId, classValue, result);
+    }
+    bool CallClassName(const ObjectId &objId, nsString *result) {
+        return Base::CallClassName(objId, result);
+    }
+
+    bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
+                              ReturnStatus *rs, nsTArray<nsString> *names) {
+        return Base::CallGetPropertyNames(objId, flags, rs, names);
+    }
+    bool CallInstanceOf(const ObjectId &objId, const JSIID &iid,
+                        ReturnStatus *rs, bool *instanceof) {
+        return Base::CallInstanceOf(objId, iid, rs, instanceof);
+    }
+    bool CallDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
+                           ReturnStatus *rs, bool *instanceof) {
+        return Base::CallDOMInstanceOf(objId, prototypeID, depth, rs, instanceof);
+    }
+};
+
+} // namespace jsipc
+} // namespace mozilla
+
+#endif
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -17,555 +17,53 @@
 
 using namespace js;
 using namespace JS;
 using namespace mozilla;
 using namespace mozilla::jsipc;
 using namespace mozilla::dom;
 
 JavaScriptParent::JavaScriptParent()
-  : refcount_(1),
-    inactive_(false)
-{
-}
-
-static inline JavaScriptParent *
-ParentOf(JSObject *obj)
-{
-    MOZ_ASSERT(IsCPOW(obj));
-    return reinterpret_cast<JavaScriptParent *>(GetProxyExtra(obj, 0).toPrivate());
-}
-
-ObjectId
-JavaScriptParent::idOf(JSObject *obj)
-{
-    MOZ_ASSERT(IsCPOW(obj));
-
-    Value v = GetProxyExtra(obj, 1);
-    MOZ_ASSERT(v.isDouble());
-
-    ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
-    MOZ_ASSERT(findCPOWById(objId) == obj);
-    MOZ_ASSERT(objId);
-
-    return objId;
-}
-
-int sCPOWProxyHandler;
-
-class CPOWProxyHandler : public BaseProxyHandler
-{
-  public:
-    CPOWProxyHandler()
-      : BaseProxyHandler(&sCPOWProxyHandler) {}
-    virtual ~CPOWProxyHandler() {}
-
-    virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE {
-        return false;
-    }
-
-    virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
-    virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                       MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
-    virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                          MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
-    virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
-    virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
-                                     AutoIdVector &props) MOZ_OVERRIDE;
-    virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
-
-    virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
-    virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
-    virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                     HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
-    virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-                     JS::HandleId id, bool strict, JS::MutableHandleValue vp) MOZ_OVERRIDE;
-    virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
-
-    virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
-    virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
-    virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
-    virtual const char* className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
-    virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
-
-    static CPOWProxyHandler singleton;
-};
-
-CPOWProxyHandler CPOWProxyHandler::singleton;
-
-#define FORWARD(call, args)                                             \
-    JavaScriptParent *parent = ParentOf(proxy);                         \
-    if (!parent->active()) {                                            \
-        JS_ReportError(cx, "cannot use a CPOW whose process is gone");  \
-        return false;                                                   \
-    }                                                                   \
-    return parent->call args;
-
-bool
-CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy)
-{
-    FORWARD(preventExtensions, (cx, proxy));
-}
-
-bool
-JavaScriptParent::preventExtensions(JSContext *cx, HandleObject proxy)
-{
-    ObjectId objId = idOf(proxy);
-
-    ReturnStatus status;
-    if (!CallPreventExtensions(objId, &status))
-        return ipcfail(cx);
-
-    return ok(cx, status);
-}
-
-bool
-CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                        MutableHandle<JSPropertyDescriptor> desc)
-{
-    FORWARD(getPropertyDescriptor, (cx, proxy, id, desc));
-}
-
-bool
-JavaScriptParent::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                        MutableHandle<JSPropertyDescriptor> desc)
-{
-    ObjectId objId = idOf(proxy);
-
-    nsString idstr;
-    if (!convertIdToGeckoString(cx, id, &idstr))
-        return false;
-
-    ReturnStatus status;
-    PPropertyDescriptor result;
-    if (!CallGetPropertyDescriptor(objId, idstr, &status, &result))
-        return ipcfail(cx);
-    if (!ok(cx, status))
-        return false;
-
-    return toDescriptor(cx, result, desc);
-}
-
-bool
-CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
-                                           HandleId id, MutableHandle<JSPropertyDescriptor> desc)
-{
-    FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc));
-}
-
-bool
-JavaScriptParent::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                           MutableHandle<JSPropertyDescriptor> desc)
-{
-    ObjectId objId = idOf(proxy);
-
-    nsString idstr;
-    if (!convertIdToGeckoString(cx, id, &idstr))
-        return false;
-
-    ReturnStatus status;
-    PPropertyDescriptor result;
-    if (!CallGetOwnPropertyDescriptor(objId, idstr, &status, &result))
-        return ipcfail(cx);
-    if (!ok(cx, status))
-        return false;
-
-    return toDescriptor(cx, result, desc);
-}
-
-bool
-CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                 MutableHandle<JSPropertyDescriptor> desc)
-{
-    FORWARD(defineProperty, (cx, proxy, id, desc));
-}
-
-bool
-JavaScriptParent::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                 MutableHandle<JSPropertyDescriptor> desc)
-{
-    ObjectId objId = idOf(proxy);
-
-    nsString idstr;
-    if (!convertIdToGeckoString(cx, id, &idstr))
-        return false;
-
-    PPropertyDescriptor descriptor;
-    if (!fromDescriptor(cx, desc, &descriptor))
-        return false;
-
-    ReturnStatus status;
-    if (!CallDefineProperty(objId, idstr, descriptor, &status))
-        return ipcfail(cx);
-
-    return ok(cx, status);
-}
-
-bool
-CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
-{
-    FORWARD(getOwnPropertyNames, (cx, proxy, props));
-}
-
-bool
-JavaScriptParent::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
-{
-    return getPropertyNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
-}
-
-bool
-CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
-{
-    FORWARD(delete_, (cx, proxy, id, bp));
-}
-
-bool
-JavaScriptParent::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
-{
-    ObjectId objId = idOf(proxy);
-
-    nsString idstr;
-    if (!convertIdToGeckoString(cx, id, &idstr))
-        return false;
-
-    ReturnStatus status;
-    if (!CallDelete(objId, idstr, &status, bp))
-        return ipcfail(cx);
-
-    return ok(cx, status);
-}
-
-bool
-CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
-{
-    FORWARD(enumerate, (cx, proxy, props));
-}
-
-bool
-JavaScriptParent::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
-{
-    return getPropertyNames(cx, proxy, 0, props);
-}
-
-bool
-CPOWProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
-{
-    FORWARD(has, (cx, proxy, id, bp));
-}
-
-bool
-JavaScriptParent::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+  : refcount_(1)
 {
-    ObjectId objId = idOf(proxy);
-
-    nsString idstr;
-    if (!convertIdToGeckoString(cx, id, &idstr))
-        return false;
-
-    ReturnStatus status;
-    if (!CallHas(objId, idstr, &status, bp))
-        return ipcfail(cx);
-
-    return ok(cx, status);
-}
-
-bool
-CPOWProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
-{
-    FORWARD(hasOwn, (cx, proxy, id, bp));
-}
-
-bool
-JavaScriptParent::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
-{
-    ObjectId objId = idOf(proxy);
-
-    nsString idstr;
-    if (!convertIdToGeckoString(cx, id, &idstr))
-        return false;
-
-    ReturnStatus status;
-    if (!CallHasOwn(objId, idstr, &status, bp))
-        return ipcfail(cx);
-
-    return !!ok(cx, status);
-}
-
-bool
-CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                      HandleId id, MutableHandleValue vp)
-{
-    FORWARD(get, (cx, proxy, receiver, id, vp));
-}
-
-bool
-JavaScriptParent::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                      HandleId id, MutableHandleValue vp)
-{
-    ObjectId objId = idOf(proxy);
-    ObjectId receiverId = idOf(receiver);
-
-    nsString idstr;
-    if (!convertIdToGeckoString(cx, id, &idstr))
-        return false;
-
-    JSVariant val;
-    ReturnStatus status;
-    if (!CallGet(objId, receiverId, idstr, &status, &val))
-        return ipcfail(cx);
-
-    if (!ok(cx, status))
-        return false;
-
-    return fromVariant(cx, val, vp);
-}
-
-bool
-CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-                      JS::HandleId id, bool strict, JS::MutableHandleValue vp)
-{
-    FORWARD(set, (cx, proxy, receiver, id, strict, vp));
-}
-
-bool
-JavaScriptParent::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-                      JS::HandleId id, bool strict, JS::MutableHandleValue vp)
-{
-    ObjectId objId = idOf(proxy);
-    ObjectId receiverId = idOf(receiver);
-
-    nsString idstr;
-    if (!convertIdToGeckoString(cx, id, &idstr))
-        return false;
-
-    JSVariant val;
-    if (!toVariant(cx, vp, &val))
-        return false;
-
-    ReturnStatus status;
-    JSVariant result;
-    if (!CallSet(objId, receiverId, idstr, strict, val, &status, &result))
-        return ipcfail(cx);
-
-    if (!ok(cx, status))
-        return false;
-
-    return fromVariant(cx, result, vp);
-}
-
-bool
-CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
-{
-    FORWARD(keys, (cx, proxy, props));
-}
-
-bool
-JavaScriptParent::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
-{
-    return getPropertyNames(cx, proxy, JSITER_OWNONLY, props);
-}
-
-bool
-CPOWProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
-{
-    FORWARD(isExtensible, (cx, proxy, extensible));
-}
-
-bool
-JavaScriptParent::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
-{
-    ObjectId objId = idOf(proxy);
-
-    ReturnStatus status;
-    if (!CallIsExtensible(objId, &status, extensible))
-        return ipcfail(cx);
-
-    return ok(cx, status);
-}
-
-bool
-CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
-{
-    FORWARD(call, (cx, proxy, args));
-}
-
-bool
-JavaScriptParent::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
-{
-    ObjectId objId = idOf(proxy);
-
-    InfallibleTArray<JSParam> vals;
-    AutoValueVector outobjects(cx);
-
-    RootedValue v(cx);
-    for (size_t i = 0; i < args.length() + 2; i++) {
-        v = args.base()[i];
-        if (v.isObject()) {
-            RootedObject obj(cx, &v.toObject());
-            if (xpc::IsOutObject(cx, obj)) {
-                // Make sure it is not an in-out object.
-                bool found;
-                if (!JS_HasProperty(cx, obj, "value", &found))
-                    return false;
-                if (found) {
-                    JS_ReportError(cx, "in-out objects cannot be sent via CPOWs yet");
-                    return false;
-                }
-
-                vals.AppendElement(JSParam(void_t()));
-                if (!outobjects.append(ObjectValue(*obj)))
-                    return false;
-                continue;
-            }
-        }
-        JSVariant val;
-        if (!toVariant(cx, v, &val))
-            return false;
-        vals.AppendElement(JSParam(val));
-    }
-
-    JSVariant result;
-    ReturnStatus status;
-    InfallibleTArray<JSParam> outparams;
-    if (!CallCall(objId, vals, &status, &result, &outparams))
-        return ipcfail(cx);
-    if (!ok(cx, status))
-        return false;
-
-    if (outparams.Length() != outobjects.length())
-        return ipcfail(cx);
-
-    RootedObject obj(cx);
-    for (size_t i = 0; i < outparams.Length(); i++) {
-        // Don't bother doing anything for outparams that weren't set.
-        if (outparams[i].type() == JSParam::Tvoid_t)
-            continue;
-
-        // Take the value the child process returned, and set it on the XPC
-        // object.
-        if (!fromVariant(cx, outparams[i], &v))
-            return false;
-
-        obj = &outobjects[i].toObject();
-        if (!JS_SetProperty(cx, obj, "value", v))
-            return false;
-    }
-
-    if (!fromVariant(cx, result, args.rval()))
-        return false;
-
-    return true;
-}
-
-
-bool
-CPOWProxyHandler::objectClassIs(HandleObject proxy, js::ESClassValue classValue, JSContext *cx)
-{
-    FORWARD(objectClassIs, (cx, proxy, classValue));
-}
-
-bool
-JavaScriptParent::objectClassIs(JSContext *cx, HandleObject proxy, js::ESClassValue classValue)
-{
-    ObjectId objId = idOf(proxy);
-
-    // This function is assumed infallible, so we just return false if the IPC
-    // channel fails.
-    bool result;
-    if (!CallObjectClassIs(objId, classValue, &result))
-        return false;
-
-    return result;
-}
-
-const char *
-CPOWProxyHandler::className(JSContext *cx, HandleObject proxy)
-{
-    JavaScriptParent *parent = ParentOf(proxy);
-    if (!parent->active())
-        return "<dead CPOW>";
-    return parent->className(cx, proxy);
-}
-
-const char *
-JavaScriptParent::className(JSContext *cx, HandleObject proxy)
-{
-    ObjectId objId = idOf(proxy);
-
-    nsString name;
-    if (!CallClassName(objId, &name))
-        return "<error>";
-
-    return ToNewCString(name);
-}
-
-void
-CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
-{
-    ParentOf(proxy)->drop(proxy);
 }
 
 void
 JavaScriptParent::drop(JSObject *obj)
 {
     ObjectId objId = idOf(obj);
 
     cpows_.remove(objId);
-    if (!inactive_ && !SendDropObject(objId))
+    if (active() && !SendDropObject(objId))
         (void)0;
     decref();
 }
 
 bool
 JavaScriptParent::init()
 {
-    if (!JavaScriptShared::init())
+    if (!WrapperOwner::init())
         return false;
 
     return true;
 }
 
 bool
 JavaScriptParent::toId(JSContext *cx, JSObject *obj, ObjectId *idp)
 {
     obj = js::CheckedUnwrap(obj, false);
-    if (!obj || !IsProxy(obj) || GetProxyHandler(obj) != &CPOWProxyHandler::singleton) {
+    if (!obj || !IsCPOW(obj)) {
         JS_ReportError(cx, "cannot ipc non-cpow object");
         return false;
     }
 
     *idp = idOf(obj);
     return true;
 }
 
-bool
-JavaScriptParent::getPropertyNames(JSContext *cx, HandleObject proxy, uint32_t flags, AutoIdVector &props)
-{
-    ObjectId objId = idOf(proxy);
-
-    ReturnStatus status;
-    InfallibleTArray<nsString> names;
-    if (!CallGetPropertyNames(objId, flags, &status, &names))
-        return ipcfail(cx);
-    if (!ok(cx, status))
-        return false;
-
-    for (size_t i = 0; i < names.Length(); i++) {
-        RootedId name(cx);
-        if (!convertGeckoStringToId(cx, names[i], &name))
-            return false;
-        if (!props.append(name))
-            return false;
-    }
-
-    return true;
-}
-
 JSObject *
 JavaScriptParent::fromId(JSContext *cx, ObjectId objId)
 {
     RootedObject obj(cx, findCPOWById(objId));
     if (obj) {
         if (!JS_WrapObject(cx, &obj))
             return nullptr;
         return obj;
@@ -579,17 +77,17 @@ JavaScriptParent::fromId(JSContext *cx, 
     bool callable = !!(objId & OBJECT_IS_CALLABLE);
 
     RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
 
     RootedValue v(cx, UndefinedValue());
     ProxyOptions options;
     options.selectDefaultClass(callable);
     obj = NewProxyObject(cx,
-                         &CPOWProxyHandler::singleton,
+                         ProxyHandler(),
                          v,
                          nullptr,
                          global,
                          options);
     if (!obj)
         return nullptr;
 
     if (!cpows_.add(objId, obj))
@@ -598,117 +96,30 @@ JavaScriptParent::fromId(JSContext *cx, 
     // Incref once we know the decref will be called.
     incref();
 
     SetProxyExtra(obj, 0, PrivateValue(this));
     SetProxyExtra(obj, 1, DoubleValue(BitwiseCast<double>(objId)));
     return obj;
 }
 
-bool
-JavaScriptParent::ipcfail(JSContext *cx)
-{
-    JS_ReportError(cx, "child process crashed or timedout");
-    return false;
-}
-
-bool
-JavaScriptParent::ok(JSContext *cx, const ReturnStatus &status)
-{
-    if (status.type() == ReturnStatus::TReturnSuccess)
-        return true;
-
-    if (status.type() == ReturnStatus::TReturnStopIteration)
-        return JS_ThrowStopIteration(cx);
-
-    RootedValue exn(cx);
-    if (!fromVariant(cx, status.get_ReturnException().exn(), &exn))
-        return false;
-
-    JS_SetPendingException(cx, exn);
-    return false;
-}
-
 void
 JavaScriptParent::decref()
 {
     refcount_--;
     if (!refcount_)
         delete this;
 }
 
 void
 JavaScriptParent::incref()
 {
     refcount_++;
 }
 
-void
-JavaScriptParent::ActorDestroy(ActorDestroyReason why)
-{
-    inactive_ = true;
-}
-
-namespace mozilla {
-namespace jsipc {
-
-bool
-IsCPOW(JSObject *obj)
-{
-    return IsProxy(obj) && GetProxyHandler(obj) == &CPOWProxyHandler::singleton;
-}
-
-nsresult
-InstanceOf(JSObject *proxy, const nsID *id, bool *bp)
-{
-    JavaScriptParent *parent = ParentOf(proxy);
-    if (!parent->active())
-        return NS_ERROR_UNEXPECTED;
-    return parent->instanceOf(proxy, id, bp);
-}
-
-bool
-DOMInstanceOf(JSContext *cx, JSObject *proxy, int prototypeID, int depth, bool *bp)
-{
-    FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp));
-}
-
-} /* namespace jsipc */
-} /* namespace mozilla */
-
-nsresult
-JavaScriptParent::instanceOf(JSObject *obj, const nsID *id, bool *bp)
-{
-    ObjectId objId = idOf(obj);
-
-    JSIID iid;
-    ConvertID(*id, &iid);
-
-    ReturnStatus status;
-    if (!CallInstanceOf(objId, iid, &status, bp))
-        return NS_ERROR_UNEXPECTED;
-
-    if (status.type() != ReturnStatus::TReturnSuccess)
-        return NS_ERROR_UNEXPECTED;
-
-    return NS_OK;
-}
-
-bool
-JavaScriptParent::domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp)
-{
-    ObjectId objId = idOf(obj);
-
-    ReturnStatus status;
-    if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
-        return ipcfail(cx);
-
-    return ok(cx, status);
-}
-
 mozilla::ipc::IProtocol*
 JavaScriptParent::CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx)
 {
     ContentParent *contentParent = aCtx->GetContentParent();
     nsAutoPtr<PJavaScriptParent> actor(contentParent->AllocPJavaScriptParent());
     if (!actor || !contentParent->RecvPJavaScriptConstructor(actor)) {
         return nullptr;
     }
--- a/js/ipc/JavaScriptParent.h
+++ b/js/ipc/JavaScriptParent.h
@@ -3,112 +3,42 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_jsipc_JavaScriptParent__
 #define mozilla_jsipc_JavaScriptParent__
 
-#include "JavaScriptShared.h"
+#include "JavaScriptBase.h"
 #include "mozilla/jsipc/PJavaScriptParent.h"
-#include "js/Class.h"
-
-#ifdef XP_WIN
-#undef GetClassName
-#undef GetClassInfo
-#endif
 
 namespace mozilla {
 namespace jsipc {
 
-class JavaScriptParent
-  : public PJavaScriptParent,
-    public JavaScriptShared
+class JavaScriptParent : public JavaScriptBase<PJavaScriptParent>
 {
   public:
     JavaScriptParent();
 
     bool init();
 
-  public:
-    // Fundamental proxy traps. These are required.
-    // (The traps should be in the same order like js/src/jsproxy.h)
-    bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
-    bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
-                               JS::MutableHandle<JSPropertyDescriptor> desc);
-    bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
-                                  JS::MutableHandle<JSPropertyDescriptor> desc);
-    bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
-                        JS::MutableHandle<JSPropertyDescriptor> desc);
-    bool getOwnPropertyNames(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
-    bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
-    bool enumerate(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
-
-    // Derived proxy traps. Implementing these is useful for perfomance.
-    bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
-    bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
-    bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-             JS::HandleId id, JS::MutableHandleValue vp);
-    bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-             JS::HandleId id, bool strict, JS::MutableHandleValue vp);
-    bool keys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
-    // We use "iterate" provided by the base class here.
-
-    // SpiderMonkey Extensions.
-    bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
-    bool call(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args);
-    bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
-    const char* className(JSContext *cx, JS::HandleObject proxy);
-
-    virtual void ActorDestroy(ActorDestroyReason why);
-
     void decref();
     void incref();
 
-    bool active() { return !inactive_; }
-
     void drop(JSObject *obj);
 
-    nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
-
-    /*
-     * Check that |obj| is a DOM wrapper whose prototype chain contains
-     * |prototypeID| at depth |depth|.
-     */
-    bool domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
-
     mozilla::ipc::IProtocol*
     CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
 
   private:
     JSObject *fromId(JSContext *cx, ObjectId objId);
     bool toId(JSContext *cx, JSObject *obj, ObjectId *idp);
 
-    bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags,
-                          JS::AutoIdVector &props);
-    ObjectId idOf(JSObject *obj);
-
-    // Catastrophic IPC failure.
-    bool ipcfail(JSContext *cx);
-
-    // Check whether a return status is okay, and if not, propagate its error.
-    bool ok(JSContext *cx, const ReturnStatus &status);
-
   private:
     uintptr_t refcount_;
-    bool inactive_;
 };
 
-bool
-IsCPOW(JSObject *obj);
-
-nsresult
-InstanceOf(JSObject *obj, const nsID *id, bool *bp);
-
-bool
-DOMInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
-
 } // jsipc
 } // mozilla
 
 #endif // mozilla_jsipc_JavaScriptWrapper_h__
 
new file mode 100644
--- /dev/null
+++ b/js/ipc/WrapperOwner.cpp
@@ -0,0 +1,624 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=80:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WrapperOwner.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "jsfriendapi.h"
+#include "xpcprivate.h"
+
+using namespace js;
+using namespace JS;
+using namespace mozilla;
+using namespace mozilla::jsipc;
+
+WrapperOwner::WrapperOwner()
+  : inactive_(false)
+{
+}
+
+static inline WrapperOwner *
+OwnerOf(JSObject *obj)
+{
+    MOZ_ASSERT(IsCPOW(obj));
+    return reinterpret_cast<WrapperOwner *>(GetProxyExtra(obj, 0).toPrivate());
+}
+
+ObjectId
+WrapperOwner::idOf(JSObject *obj)
+{
+    MOZ_ASSERT(IsCPOW(obj));
+
+    Value v = GetProxyExtra(obj, 1);
+    MOZ_ASSERT(v.isDouble());
+
+    ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
+    MOZ_ASSERT(findCPOWById(objId) == obj);
+    MOZ_ASSERT(objId);
+
+    return objId;
+}
+
+int sCPOWProxyHandler;
+
+class CPOWProxyHandler : public BaseProxyHandler
+{
+  public:
+    CPOWProxyHandler()
+      : BaseProxyHandler(&sCPOWProxyHandler) {}
+    virtual ~CPOWProxyHandler() {}
+
+    virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE {
+        return false;
+    }
+
+    virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
+    virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                                       MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
+    virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                                          MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
+    virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
+                                MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
+    virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
+                                     AutoIdVector &props) MOZ_OVERRIDE;
+    virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
+    virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
+
+    virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
+    virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
+    virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                     HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
+    virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+                     JS::HandleId id, bool strict, JS::MutableHandleValue vp) MOZ_OVERRIDE;
+    virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
+
+    virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
+    virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
+    virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
+    virtual const char* className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
+    virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
+
+    static CPOWProxyHandler singleton;
+};
+
+CPOWProxyHandler CPOWProxyHandler::singleton;
+
+/* static */ BaseProxyHandler *
+WrapperOwner::ProxyHandler()
+{
+    return &CPOWProxyHandler::singleton;
+}
+
+#define FORWARD(call, args)                                             \
+    WrapperOwner *owner = OwnerOf(proxy);                               \
+    if (!owner->active()) {                                             \
+        JS_ReportError(cx, "cannot use a CPOW whose process is gone");  \
+        return false;                                                   \
+    }                                                                   \
+    return owner->call args;
+
+bool
+CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy)
+{
+    FORWARD(preventExtensions, (cx, proxy));
+}
+
+bool
+WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy)
+{
+    ObjectId objId = idOf(proxy);
+
+    ReturnStatus status;
+    if (!CallPreventExtensions(objId, &status))
+        return ipcfail(cx);
+
+    return ok(cx, status);
+}
+
+bool
+CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                                        MutableHandle<JSPropertyDescriptor> desc)
+{
+    FORWARD(getPropertyDescriptor, (cx, proxy, id, desc));
+}
+
+bool
+WrapperOwner::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+				    MutableHandle<JSPropertyDescriptor> desc)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    ReturnStatus status;
+    PPropertyDescriptor result;
+    if (!CallGetPropertyDescriptor(objId, idstr, &status, &result))
+        return ipcfail(cx);
+    if (!ok(cx, status))
+        return false;
+
+    return toDescriptor(cx, result, desc);
+}
+
+bool
+CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                                           MutableHandle<JSPropertyDescriptor> desc)
+{
+    FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc));
+}
+
+bool
+WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+				       MutableHandle<JSPropertyDescriptor> desc)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    ReturnStatus status;
+    PPropertyDescriptor result;
+    if (!CallGetOwnPropertyDescriptor(objId, idstr, &status, &result))
+        return ipcfail(cx);
+    if (!ok(cx, status))
+        return false;
+
+    return toDescriptor(cx, result, desc);
+}
+
+bool
+CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
+                                 MutableHandle<JSPropertyDescriptor> desc)
+{
+    FORWARD(defineProperty, (cx, proxy, id, desc));
+}
+
+bool
+WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
+			     MutableHandle<JSPropertyDescriptor> desc)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    PPropertyDescriptor descriptor;
+    if (!fromDescriptor(cx, desc, &descriptor))
+        return false;
+
+    ReturnStatus status;
+    if (!CallDefineProperty(objId, idstr, descriptor, &status))
+        return ipcfail(cx);
+
+    return ok(cx, status);
+}
+
+bool
+CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    FORWARD(getOwnPropertyNames, (cx, proxy, props));
+}
+
+bool
+WrapperOwner::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    return getPropertyNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
+}
+
+bool
+CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+{
+    FORWARD(delete_, (cx, proxy, id, bp));
+}
+
+bool
+WrapperOwner::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    ReturnStatus status;
+    if (!CallDelete(objId, idstr, &status, bp))
+        return ipcfail(cx);
+
+    return ok(cx, status);
+}
+
+bool
+CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    FORWARD(enumerate, (cx, proxy, props));
+}
+
+bool
+WrapperOwner::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    return getPropertyNames(cx, proxy, 0, props);
+}
+
+bool
+CPOWProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+{
+    FORWARD(has, (cx, proxy, id, bp));
+}
+
+bool
+WrapperOwner::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    ReturnStatus status;
+    if (!CallHas(objId, idstr, &status, bp))
+        return ipcfail(cx);
+
+    return ok(cx, status);
+}
+
+bool
+CPOWProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+{
+    FORWARD(hasOwn, (cx, proxy, id, bp));
+}
+
+bool
+WrapperOwner::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    ReturnStatus status;
+    if (!CallHasOwn(objId, idstr, &status, bp))
+        return ipcfail(cx);
+
+    return !!ok(cx, status);
+}
+
+bool
+CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                      HandleId id, MutableHandleValue vp)
+{
+    FORWARD(get, (cx, proxy, receiver, id, vp));
+}
+
+bool
+WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
+		  HandleId id, MutableHandleValue vp)
+{
+    ObjectId objId = idOf(proxy);
+    ObjectId receiverId = idOf(receiver);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    JSVariant val;
+    ReturnStatus status;
+    if (!CallGet(objId, receiverId, idstr, &status, &val))
+        return ipcfail(cx);
+
+    if (!ok(cx, status))
+        return false;
+
+    return fromVariant(cx, val, vp);
+}
+
+bool
+CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+                      JS::HandleId id, bool strict, JS::MutableHandleValue vp)
+{
+    FORWARD(set, (cx, proxy, receiver, id, strict, vp));
+}
+
+bool
+WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+		  JS::HandleId id, bool strict, JS::MutableHandleValue vp)
+{
+    ObjectId objId = idOf(proxy);
+    ObjectId receiverId = idOf(receiver);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    JSVariant val;
+    if (!toVariant(cx, vp, &val))
+        return false;
+
+    ReturnStatus status;
+    JSVariant result;
+    if (!CallSet(objId, receiverId, idstr, strict, val, &status, &result))
+        return ipcfail(cx);
+
+    if (!ok(cx, status))
+        return false;
+
+    return fromVariant(cx, result, vp);
+}
+
+bool
+CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    FORWARD(keys, (cx, proxy, props));
+}
+
+bool
+WrapperOwner::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    return getPropertyNames(cx, proxy, JSITER_OWNONLY, props);
+}
+
+bool
+CPOWProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
+{
+    FORWARD(isExtensible, (cx, proxy, extensible));
+}
+
+bool
+WrapperOwner::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
+{
+    ObjectId objId = idOf(proxy);
+
+    ReturnStatus status;
+    if (!CallIsExtensible(objId, &status, extensible))
+        return ipcfail(cx);
+
+    return ok(cx, status);
+}
+
+bool
+CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
+{
+    FORWARD(call, (cx, proxy, args));
+}
+
+bool
+WrapperOwner::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
+{
+    ObjectId objId = idOf(proxy);
+
+    InfallibleTArray<JSParam> vals;
+    AutoValueVector outobjects(cx);
+
+    RootedValue v(cx);
+    for (size_t i = 0; i < args.length() + 2; i++) {
+        v = args.base()[i];
+        if (v.isObject()) {
+            RootedObject obj(cx, &v.toObject());
+            if (xpc::IsOutObject(cx, obj)) {
+                // Make sure it is not an in-out object.
+                bool found;
+                if (!JS_HasProperty(cx, obj, "value", &found))
+                    return false;
+                if (found) {
+                    JS_ReportError(cx, "in-out objects cannot be sent via CPOWs yet");
+                    return false;
+                }
+
+                vals.AppendElement(JSParam(void_t()));
+                if (!outobjects.append(ObjectValue(*obj)))
+                    return false;
+                continue;
+            }
+        }
+        JSVariant val;
+        if (!toVariant(cx, v, &val))
+            return false;
+        vals.AppendElement(JSParam(val));
+    }
+
+    JSVariant result;
+    ReturnStatus status;
+    InfallibleTArray<JSParam> outparams;
+    if (!CallCall(objId, vals, &status, &result, &outparams))
+        return ipcfail(cx);
+    if (!ok(cx, status))
+        return false;
+
+    if (outparams.Length() != outobjects.length())
+        return ipcfail(cx);
+
+    RootedObject obj(cx);
+    for (size_t i = 0; i < outparams.Length(); i++) {
+        // Don't bother doing anything for outparams that weren't set.
+        if (outparams[i].type() == JSParam::Tvoid_t)
+            continue;
+
+        // Take the value the child process returned, and set it on the XPC
+        // object.
+        if (!fromVariant(cx, outparams[i], &v))
+            return false;
+
+        obj = &outobjects[i].toObject();
+        if (!JS_SetProperty(cx, obj, "value", v))
+            return false;
+    }
+
+    if (!fromVariant(cx, result, args.rval()))
+        return false;
+
+    return true;
+}
+
+
+bool
+CPOWProxyHandler::objectClassIs(HandleObject proxy, js::ESClassValue classValue, JSContext *cx)
+{
+    FORWARD(objectClassIs, (cx, proxy, classValue));
+}
+
+bool
+WrapperOwner::objectClassIs(JSContext *cx, HandleObject proxy, js::ESClassValue classValue)
+{
+    ObjectId objId = idOf(proxy);
+
+    // This function is assumed infallible, so we just return false if the IPC
+    // channel fails.
+    bool result;
+    if (!CallObjectClassIs(objId, classValue, &result))
+        return false;
+
+    return result;
+}
+
+const char *
+CPOWProxyHandler::className(JSContext *cx, HandleObject proxy)
+{
+    WrapperOwner *parent = OwnerOf(proxy);
+    if (!parent->active())
+        return "<dead CPOW>";
+    return parent->className(cx, proxy);
+}
+
+const char *
+WrapperOwner::className(JSContext *cx, HandleObject proxy)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString name;
+    if (!CallClassName(objId, &name))
+        return "<error>";
+
+    return ToNewCString(name);
+}
+
+void
+CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
+{
+    OwnerOf(proxy)->drop(proxy);
+}
+
+bool
+WrapperOwner::init()
+{
+    if (!JavaScriptShared::init())
+        return false;
+
+    return true;
+}
+
+bool
+WrapperOwner::getPropertyNames(JSContext *cx, HandleObject proxy, uint32_t flags, AutoIdVector &props)
+{
+    ObjectId objId = idOf(proxy);
+
+    ReturnStatus status;
+    InfallibleTArray<nsString> names;
+    if (!CallGetPropertyNames(objId, flags, &status, &names))
+        return ipcfail(cx);
+    if (!ok(cx, status))
+        return false;
+
+    for (size_t i = 0; i < names.Length(); i++) {
+        RootedId name(cx);
+        if (!convertGeckoStringToId(cx, names[i], &name))
+            return false;
+        if (!props.append(name))
+            return false;
+    }
+
+    return true;
+}
+
+namespace mozilla {
+namespace jsipc {
+
+bool
+IsCPOW(JSObject *obj)
+{
+    return IsProxy(obj) && GetProxyHandler(obj) == &CPOWProxyHandler::singleton;
+}
+
+nsresult
+InstanceOf(JSObject *proxy, const nsID *id, bool *bp)
+{
+    WrapperOwner *parent = OwnerOf(proxy);
+    if (!parent->active())
+        return NS_ERROR_UNEXPECTED;
+    return parent->instanceOf(proxy, id, bp);
+}
+
+bool
+DOMInstanceOf(JSContext *cx, JSObject *proxy, int prototypeID, int depth, bool *bp)
+{
+    FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp));
+}
+
+} /* namespace jsipc */
+} /* namespace mozilla */
+
+nsresult
+WrapperOwner::instanceOf(JSObject *obj, const nsID *id, bool *bp)
+{
+    ObjectId objId = idOf(obj);
+
+    JSIID iid;
+    ConvertID(*id, &iid);
+
+    ReturnStatus status;
+    if (!CallInstanceOf(objId, iid, &status, bp))
+        return NS_ERROR_UNEXPECTED;
+
+    if (status.type() != ReturnStatus::TReturnSuccess)
+        return NS_ERROR_UNEXPECTED;
+
+    return NS_OK;
+}
+
+bool
+WrapperOwner::domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp)
+{
+    ObjectId objId = idOf(obj);
+
+    ReturnStatus status;
+    if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
+        return ipcfail(cx);
+
+    return ok(cx, status);
+}
+
+void
+WrapperOwner::ActorDestroy(ActorDestroyReason why)
+{
+    inactive_ = true;
+}
+
+bool
+WrapperOwner::ipcfail(JSContext *cx)
+{
+    JS_ReportError(cx, "child process crashed or timedout");
+    return false;
+}
+
+bool
+WrapperOwner::ok(JSContext *cx, const ReturnStatus &status)
+{
+    if (status.type() == ReturnStatus::TReturnSuccess)
+        return true;
+
+    if (status.type() == ReturnStatus::TReturnStopIteration)
+        return JS_ThrowStopIteration(cx);
+
+    RootedValue exn(cx);
+    if (!fromVariant(cx, status.get_ReturnException().exn(), &exn))
+        return false;
+
+    JS_SetPendingException(cx, exn);
+    return false;
+}
new file mode 100644
--- /dev/null
+++ b/js/ipc/WrapperOwner.h
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=80:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_jsipc_WrapperOwner_h__
+#define mozilla_jsipc_WrapperOwner_h__
+
+#include "JavaScriptShared.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "js/Class.h"
+
+#ifdef XP_WIN
+#undef GetClassName
+#undef GetClassInfo
+#endif
+
+namespace js {
+class BaseProxyHandler;
+} // js
+
+namespace mozilla {
+namespace jsipc {
+
+class WrapperOwner : public JavaScriptShared
+{
+  public:
+    typedef mozilla::ipc::IProtocolManager<
+                       mozilla::ipc::IProtocol>::ActorDestroyReason
+           ActorDestroyReason;
+
+    WrapperOwner();
+    bool init();
+
+    // Fundamental proxy traps. These are required.
+    // (The traps should be in the same order like js/src/jsproxy.h)
+    bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
+    bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+                               JS::MutableHandle<JSPropertyDescriptor> desc);
+    bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+                                  JS::MutableHandle<JSPropertyDescriptor> desc);
+    bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+                        JS::MutableHandle<JSPropertyDescriptor> desc);
+    bool getOwnPropertyNames(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
+    bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
+    bool enumerate(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
+
+    // Derived proxy traps. Implementing these is useful for perfomance.
+    bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
+    bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
+    bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+             JS::HandleId id, JS::MutableHandleValue vp);
+    bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+             JS::HandleId id, bool strict, JS::MutableHandleValue vp);
+    bool keys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
+    // We use "iterate" provided by the base class here.
+
+    // SpiderMonkey Extensions.
+    bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
+    bool call(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args);
+    bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
+    const char* className(JSContext *cx, JS::HandleObject proxy);
+
+    nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
+
+    /*
+     * Check that |obj| is a DOM wrapper whose prototype chain contains
+     * |prototypeID| at depth |depth|.
+     */
+    bool domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
+
+    bool active() { return !inactive_; }
+
+    virtual void drop(JSObject *obj) = 0;
+
+    virtual void ActorDestroy(ActorDestroyReason why);
+
+  protected:
+    ObjectId idOf(JSObject *obj);
+
+    static js::BaseProxyHandler *ProxyHandler();
+
+  private:
+    bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags,
+                          JS::AutoIdVector &props);
+
+    // Catastrophic IPC failure.
+    bool ipcfail(JSContext *cx);
+
+    // Check whether a return status is okay, and if not, propagate its error.
+    bool ok(JSContext *cx, const ReturnStatus &status);
+
+    bool inactive_;
+
+    /*** Dummy call handlers ***/
+  public:
+    virtual bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) = 0;
+    virtual bool CallGetPropertyDescriptor(const ObjectId &objId, const nsString &id,
+                                           ReturnStatus *rs,
+                                           PPropertyDescriptor *out) = 0;
+    virtual bool CallGetOwnPropertyDescriptor(const ObjectId &objId,
+                                              const nsString &id,
+                                              ReturnStatus *rs,
+                                              PPropertyDescriptor *out) = 0;
+    virtual bool CallDefineProperty(const ObjectId &objId, const nsString &id,
+                                    const PPropertyDescriptor &flags,
+                                    ReturnStatus *rs) = 0;
+    virtual bool CallDelete(const ObjectId &objId, const nsString &id,
+                            ReturnStatus *rs, bool *success) = 0;
+
+    virtual bool CallHas(const ObjectId &objId, const nsString &id,
+                         ReturnStatus *rs, bool *bp) = 0;
+    virtual bool CallHasOwn(const ObjectId &objId, const nsString &id,
+                            ReturnStatus *rs, bool *bp) = 0;
+    virtual bool CallGet(const ObjectId &objId, const ObjectId &receiverId,
+                         const nsString &id,
+                         ReturnStatus *rs, JSVariant *result) = 0;
+    virtual bool CallSet(const ObjectId &objId, const ObjectId &receiverId,
+                         const nsString &id, const bool &strict,
+                         const JSVariant &value, ReturnStatus *rs, JSVariant *result) = 0;
+
+    virtual bool CallIsExtensible(const ObjectId &objId, ReturnStatus *rs,
+                                  bool *result) = 0;
+    virtual bool CallCall(const ObjectId &objId, const nsTArray<JSParam> &argv,
+                          ReturnStatus *rs, JSVariant *result,
+                          nsTArray<JSParam> *outparams) = 0;
+    virtual bool CallObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
+                                   bool *result) = 0;
+    virtual bool CallClassName(const ObjectId &objId, nsString *result) = 0;
+
+    virtual bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
+                                      ReturnStatus *rs, nsTArray<nsString> *names) = 0;
+    virtual bool CallInstanceOf(const ObjectId &objId, const JSIID &iid,
+                                ReturnStatus *rs, bool *instanceof) = 0;
+    virtual bool CallDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
+                                   ReturnStatus *rs, bool *instanceof) = 0;
+};
+
+bool
+IsCPOW(JSObject *obj);
+
+nsresult
+InstanceOf(JSObject *obj, const nsID *id, bool *bp);
+
+bool
+DOMInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
+
+} // jsipc
+} // mozilla
+
+#endif // mozilla_jsipc_WrapperOwner_h__
--- a/js/ipc/moz.build
+++ b/js/ipc/moz.build
@@ -3,16 +3,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 UNIFIED_SOURCES += [
     'JavaScriptChild.cpp',
     'JavaScriptParent.cpp',
     'JavaScriptShared.cpp',
+    'WrapperOwner.cpp',
 ]
 
 IPDL_SOURCES += [
     'JavaScriptTypes.ipdlh',
     'PJavaScript.ipdl',
 ]
 
 FAIL_ON_WARNINGS = True