Rewrite CPOWs to use one actor per process (bug 853209, r=billm,bholley,smaug).
authorDavid Anderson <danderson@mozilla.com>
Wed, 03 Jul 2013 00:24:32 -0700
changeset 137301 0c45375d507ee8699f6a25760263234f7c9e8823
parent 137300 a9329f507dbe8fb857d98a689e9e6b94b0c61e15
child 137302 fafa0adecf8b67a762f9a15abcd1473ed8e0f988
push idunknown
push userunknown
push dateunknown
reviewersbillm, bholley, smaug
bugs853209
milestone25.0a1
Rewrite CPOWs to use one actor per process (bug 853209, r=billm,bholley,smaug).
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/Makefile.in
dom/ipc/PContent.ipdl
ipc/testshell/PTestShell.ipdl
ipc/testshell/TestShellChild.cpp
ipc/testshell/TestShellChild.h
ipc/testshell/TestShellParent.cpp
ipc/testshell/TestShellParent.h
js/ipc/CPOWTypes.h
js/ipc/ContextWrapperChild.h
js/ipc/ContextWrapperParent.h
js/ipc/JavaScriptChild.cpp
js/ipc/JavaScriptChild.h
js/ipc/JavaScriptParent.cpp
js/ipc/JavaScriptParent.h
js/ipc/JavaScriptShared.cpp
js/ipc/JavaScriptShared.h
js/ipc/JavaScriptTypes.ipdlh
js/ipc/Makefile.in
js/ipc/ObjectWrapperChild.cpp
js/ipc/ObjectWrapperChild.h
js/ipc/ObjectWrapperParent.cpp
js/ipc/ObjectWrapperParent.h
js/ipc/PContextWrapper.ipdl
js/ipc/PJavaScript.ipdl
js/ipc/PObjectWrapper.ipdl
js/ipc/ipdl.mk
js/ipc/jar.mn
js/ipc/moz.build
js/ipc/tests/adhoc/child.html
js/ipc/tests/adhoc/test.xul
js/ipc/tests/moz.build
js/ipc/tests/unit/cpow_child.js
js/ipc/tests/unit/test_cpow.js
js/src/gc/RootMarking.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsgc.cpp
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/Makefile.in
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCJSID.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/xpc.msg
js/xpconnect/src/xpcprivate.h
toolkit/xre/nsEmbedFunctions.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/ErrorList.h
xpcom/build/nsXULAppAPI.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -20,17 +20,16 @@
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/Hal.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
-#include "mozilla/jsipc/PContextWrapperChild.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/unused.h"
 
 #include "nsIMemoryReporter.h"
@@ -45,30 +44,32 @@
 #include "nsWeakReference.h"
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsJSEnvironment.h"
 #include "SandboxHal.h"
 #include "nsDebugImpl.h"
 #include "nsHashPropertyBag.h"
 #include "nsLayoutStylesheetCache.h"
+#include "nsIJSRuntimeService.h"
 
 #include "IHistory.h"
 #include "nsDocShellCID.h"
 #include "nsNetUtil.h"
 
 #include "base/message_loop.h"
 #include "base/process_util.h"
 #include "base/task.h"
 
 #include "nsChromeRegistryContent.h"
 #include "mozilla/chrome/RegistryMessageUtils.h"
 #include "nsFrameMessageManager.h"
 
 #include "nsIGeolocationProvider.h"
+#include "JavaScriptParent.h"
 #include "mozilla/dom/PMemoryReportRequestChild.h"
 
 #ifdef MOZ_PERMISSIONS
 #include "nsPermission.h"
 #include "nsPermissionManager.h"
 #endif
 
 #if defined(MOZ_WIDGET_ANDROID)
@@ -104,30 +105,32 @@
 #include "ProcessUtils.h"
 #include "StructuredCloneUtils.h"
 #include "URIUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsDeviceStorage.h"
 #include "AudioChannelService.h"
+#include "JavaScriptChild.h"
 #include "ProcessPriorityManager.h"
 
 using namespace base;
 using namespace mozilla;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
+using namespace mozilla::jsipc;
 #if defined(MOZ_WIDGET_GONK)
 using namespace mozilla::system;
 #endif
 
 namespace mozilla {
 namespace dom {
 
 class MemoryReportRequestChild : public PMemoryReportRequestChild
@@ -547,16 +550,41 @@ static CancelableTask* sFirstIdleTask;
 
 static void FirstIdle(void)
 {
     MOZ_ASSERT(sFirstIdleTask);
     sFirstIdleTask = nullptr;
     ContentChild::GetSingleton()->SendFirstIdle();
 }
 
+mozilla::jsipc::PJavaScriptChild *
+ContentChild::AllocPJavaScript()
+{
+    nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
+    NS_ENSURE_TRUE(svc, NULL);
+
+    JSRuntime *rt;
+    svc->GetRuntime(&rt);
+    NS_ENSURE_TRUE(svc, NULL);
+
+    mozilla::jsipc::JavaScriptChild *child = new mozilla::jsipc::JavaScriptChild(rt);
+    if (!child->init()) {
+        delete child;
+        return NULL;
+    }
+    return child;
+}
+
+bool
+ContentChild::DeallocPJavaScript(PJavaScriptChild *child)
+{
+    delete child;
+    return true;
+}
+
 PBrowserChild*
 ContentChild::AllocPBrowser(const IPCTabContext& aContext,
                             const uint32_t& aChromeFlags)
 {
     // We'll happily accept any kind of IPCTabContext here; we don't need to
     // check that it's of a certain type for security purposes, because we
     // believe whatever the parent process tells us.
 
@@ -755,20 +783,29 @@ ContentChild::AllocPTestShell()
 
 bool
 ContentChild::DeallocPTestShell(PTestShellChild* shell)
 {
     delete shell;
     return true;
 }
 
+jsipc::JavaScriptChild *
+ContentChild::GetCPOWManager()
+{
+    if (ManagedPJavaScriptChild().Length()) {
+        return static_cast<JavaScriptChild*>(ManagedPJavaScriptChild()[0]);
+    }
+    JavaScriptChild* actor = static_cast<JavaScriptChild*>(SendPJavaScriptConstructor());
+    return actor;
+}
+
 bool
 ContentChild::RecvPTestShellConstructor(PTestShellChild* actor)
 {
-    actor->SendPContextWrapperConstructor()->SendPObjectWrapperConstructor(true);
     return true;
 }
 
 PDeviceStorageRequestChild*
 ContentChild::AllocPDeviceStorageRequest(const DeviceStorageParams& aParams)
 {
     return new DeviceStorageRequestChild();
 }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -23,16 +23,20 @@ struct OverrideMapping;
 
 namespace mozilla {
 
 namespace ipc {
 class OptionalURIParams;
 class URIParams;
 }// namespace ipc
 
+namespace jsipc {
+class JavaScriptChild;
+}
+
 namespace layers {
 class PCompositorChild;
 } // namespace layers
 
 namespace dom {
 
 class AlertObserver;
 class PrefObserver;
@@ -121,16 +125,17 @@ public:
                                 const bool& aDumpChildProcesses);
     virtual bool
     RecvDumpGCAndCCLogsToFile(const nsString& aIdentifier,
                               const bool& aDumpChildProcesses);
 
     virtual PTestShellChild* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellChild*);
     virtual bool RecvPTestShellConstructor(PTestShellChild*);
+    jsipc::JavaScriptChild *GetCPOWManager();
 
     virtual PNeckoChild* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoChild*);
 
     virtual PExternalHelperAppChild *AllocPExternalHelperApp(
             const OptionalURIParams& uri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
@@ -151,16 +156,19 @@ public:
     virtual PSpeechSynthesisChild* AllocPSpeechSynthesis();
     virtual bool DeallocPSpeechSynthesis(PSpeechSynthesisChild* aActor);
 
     virtual bool RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
                                     const InfallibleTArray<ResourceMapping>& resources,
                                     const InfallibleTArray<OverrideMapping>& overrides,
                                     const nsCString& locale);
 
+    virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScript();
+    virtual bool DeallocPJavaScript(mozilla::jsipc::PJavaScriptChild*);
+
     virtual bool RecvSetOffline(const bool& offline);
 
     virtual bool RecvNotifyVisited(const URIParams& aURI);
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
     virtual bool RecvPreferenceUpdate(const PrefSetting& aPref);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -114,16 +114,17 @@
 using namespace mozilla::system;
 #endif
 
 #ifdef MOZ_B2G_BT
 #include "BluetoothParent.h"
 #include "BluetoothService.h"
 #endif
 
+#include "JavaScriptParent.h"
 #include "Crypto.h"
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/SpeechSynthesisParent.h"
 #endif
 
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 static const char* sClipboardTextFlavors[] = { kUnicodeMime };
@@ -135,16 +136,17 @@ using namespace mozilla::dom::devicestor
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::dom::power;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::hal;
 using namespace mozilla::idl;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
+using namespace mozilla::jsipc;
 
 namespace mozilla {
 namespace dom {
 
 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
 
 // This represents a single measurement taken by a memory reporter in a child
 // process and passed to this one.  Its process is non-empty, and its amount is
@@ -1003,16 +1005,26 @@ ContentParent::NotifyTabDestroyed(PBrows
     // us down.
     if (ManagedPBrowserParent().Length() == 1) {
         MessageLoop::current()->PostTask(
             FROM_HERE,
             NewRunnableMethod(this, &ContentParent::ShutDownProcess));
     }
 }
 
+jsipc::JavaScriptParent*
+ContentParent::GetCPOWManager()
+{
+    if (ManagedPJavaScriptParent().Length()) {
+        return static_cast<JavaScriptParent*>(ManagedPJavaScriptParent()[0]);
+    }
+    JavaScriptParent* actor = static_cast<JavaScriptParent*>(SendPJavaScriptConstructor());
+    return actor;
+}
+
 TestShellParent*
 ContentParent::CreateTestShell()
 {
   return static_cast<TestShellParent*>(SendPTestShellConstructor());
 }
 
 bool
 ContentParent::DestroyTestShell(TestShellParent* aTestShell)
@@ -1573,16 +1585,34 @@ ContentParent::RecvGetXPCOMProcessAttrib
     nsCOMPtr<nsIIOService> io(do_GetIOService());
     NS_ASSERTION(io, "No IO service?");
     DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
     NS_ASSERTION(NS_SUCCEEDED(rv), "Failed getting offline?");
 
     return true;
 }
 
+mozilla::jsipc::PJavaScriptParent *
+ContentParent::AllocPJavaScript()
+{
+    mozilla::jsipc::JavaScriptParent *parent = new mozilla::jsipc::JavaScriptParent();
+    if (!parent->init()) {
+        delete parent;
+        return NULL;
+    }
+    return parent;
+}
+
+bool
+ContentParent::DeallocPJavaScript(PJavaScriptParent *parent)
+{
+    static_cast<mozilla::jsipc::JavaScriptParent *>(parent)->destroyFromContent();
+    return true;
+}
+
 PBrowserParent*
 ContentParent::AllocPBrowser(const IPCTabContext& aContext,
                              const uint32_t &aChromeFlags)
 {
     unused << aChromeFlags;
 
     const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -39,16 +39,20 @@ class nsIDOMBlob;
 namespace mozilla {
 
 namespace ipc {
 class OptionalURIParams;
 class URIParams;
 class TestShellParent;
 } // namespace ipc
 
+namespace jsipc {
+class JavaScriptParent;
+}
+
 namespace layers {
 class PCompositorParent;
 } // namespace layers
 
 namespace dom {
 
 class TabParent;
 class PStorageParent;
@@ -121,16 +125,17 @@ public:
     void NotifyTabDestroying(PBrowserParent* aTab);
     /** Notify that a tab was destroyed during normal operation. */
     void NotifyTabDestroyed(PBrowserParent* aTab,
                             bool aNotifiedDestroying);
 
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
     TestShellParent* GetTestShellSingleton();
+    jsipc::JavaScriptParent *GetCPOWManager();
 
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
     bool IsForApp();
 
     void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
@@ -189,16 +194,17 @@ private:
                                     hal::ProcessPriority aInitialPriority);
 
     static hal::ProcessPriority GetInitialProcessPriority(nsIDOMElement* aFrameElement);
 
     // Hide the raw constructor methods since we don't want client code
     // using them.
     using PContentParent::SendPBrowserConstructor;
     using PContentParent::SendPTestShellConstructor;
+    using PContentParent::SendPJavaScriptConstructor;
 
     // No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be
     // true.
     ContentParent(mozIApplication* aApp,
                   bool aIsForBrowser,
                   bool aIsForPreallocated,
                   ChildPrivileges aOSPrivileges = base::PRIVILEGES_DEFAULT,
                   hal::ProcessPriority aInitialPriority = hal::PROCESS_PRIORITY_FOREGROUND);
@@ -246,16 +252,19 @@ private:
     AllocPImageBridge(mozilla::ipc::Transport* aTransport,
                       base::ProcessId aOtherProcess) MOZ_OVERRIDE;
 
     virtual bool RecvGetProcessAttributes(uint64_t* aId,
                                           bool* aIsForApp,
                                           bool* aIsForBrowser) MOZ_OVERRIDE;
     virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline) MOZ_OVERRIDE;
 
+    virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScript();
+    virtual bool DeallocPJavaScript(mozilla::jsipc::PJavaScriptParent*);
+
     virtual PBrowserParent* AllocPBrowser(const IPCTabContext& aContext,
                                           const uint32_t& aChromeFlags);
     virtual bool DeallocPBrowser(PBrowserParent* frame);
 
     virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequest(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestParent*);
 
     virtual PBlobParent* AllocPBlob(const BlobConstructorParams& aParams);
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -37,16 +37,17 @@ LOCAL_INCLUDES += \
 	-I$(topsrcdir)/toolkit/xre \
 	-I$(topsrcdir)/hal/sandbox \
 	-I$(topsrcdir)/dom/mobilemessage/src/ipc \
 	-I$(topsrcdir)/dom/devicestorage \
 	-I$(topsrcdir)/widget/xpwidgets \
 	-I$(topsrcdir)/dom/bluetooth \
 	-I$(topsrcdir)/dom/bluetooth/ipc \
 	-I$(topsrcdir)/content/media/webspeech/synth/ipc \
+	-I$(topsrcdir)/js/ipc \
 	$(NULL)
 
 DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),$(findstring $(MOZ_WIDGET_TOOLKIT),android gtk2 gonk qt))
 DEFINES += -DMOZ_ENABLE_FREETYPE
 endif
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -15,16 +15,17 @@ include protocol PHal;
 include protocol PImageBridge;
 include protocol PIndexedDB;
 include protocol PMemoryReportRequest;
 include protocol PNecko;
 include protocol PSms;
 include protocol PSpeechSynthesis;
 include protocol PStorage;
 include protocol PTestShell;
+include protocol PJavaScript;
 include DOMTypes;
 include InputStreamParams;
 include URIParams;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/dom/PermissionMessageUtils.h";
 include "mozilla/dom/TabMessageUtils.h";
 include "mozilla/HalTypes.h";
@@ -247,16 +248,17 @@ rpc protocol PContent
     manages PHal;
     manages PIndexedDB;
     manages PMemoryReportRequest;
     manages PNecko;
     manages PSms;
     manages PSpeechSynthesis;
     manages PStorage;
     manages PTestShell;
+    manages PJavaScript;
 
 both:
     // Depending on exactly how the new browser is being created, it might be
     // created from either the child or parent process!
     //
     // The child creates the PBrowser as part of
     // TabChild::BrowserFrameProvideWindow (which happens when the child's
     // content calls window.open()), and the parent creates the PBrowser as part
@@ -276,16 +278,18 @@ both:
     // This allows the parent to prevent a malicious child from escalating its
     // privileges by requesting a PBrowser corresponding to a highly-privileged
     // app; the child can only request privileges for an app which the child has
     // access to (in the form of a TabChild).
     async PBrowser(IPCTabContext context, uint32_t chromeFlags);
 
     async PBlob(BlobConstructorParams params);
 
+    PJavaScript();
+
 child:
     /**
      * Update OS process privileges to |privs|.  Can usually only be
      * performed zero or one times.  The child will abnormally exit if
      * the privilege update fails.
      */
     async SetProcessPrivileges(ChildPrivileges privs);
 
--- a/ipc/testshell/PTestShell.ipdl
+++ b/ipc/testshell/PTestShell.ipdl
@@ -1,33 +1,27 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* 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 protocol PContent;
 include protocol PTestShellCommand;
-include protocol PContextWrapper;
 
 namespace mozilla {
 namespace ipc {
 
 rpc protocol PTestShell
 {
   manager PContent;
 
   manages PTestShellCommand;
-  manages PContextWrapper;
 
 child:
   __delete__();
 
   ExecuteCommand(nsString aCommand);
 
   PTestShellCommand(nsString aCommand);
-
-parent:
-  PContextWrapper();
-
 };
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/testshell/TestShellChild.cpp
+++ b/ipc/testshell/TestShellChild.cpp
@@ -1,20 +1,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/. */
 
 #include "TestShellChild.h"
-#include "mozilla/jsipc/ContextWrapperChild.h"
 
 using mozilla::ipc::TestShellChild;
 using mozilla::ipc::PTestShellCommandChild;
 using mozilla::ipc::XPCShellEnvironment;
-using mozilla::jsipc::PContextWrapperChild;
-using mozilla::jsipc::ContextWrapperChild;
 
 TestShellChild::TestShellChild()
 : mXPCShell(XPCShellEnvironment::CreateEnvironment())
 {
 }
 
 bool
 TestShellChild::RecvExecuteCommand(const nsString& aCommand)
@@ -52,24 +49,8 @@ TestShellChild::RecvPTestShellCommandCon
   nsString response;
   if (!mXPCShell->EvaluateString(aCommand, &response)) {
     return false;
   }
 
   return PTestShellCommandChild::Send__delete__(aActor, response);
 }
 
-PContextWrapperChild*
-TestShellChild::AllocPContextWrapper()
-{
-  JSContext* cx;
-  if (mXPCShell && (cx = mXPCShell->GetContext())) {
-    return new ContextWrapperChild(cx);
-  }
-  return NULL;
-}
-
-bool
-TestShellChild::DeallocPContextWrapper(PContextWrapperChild* actor)
-{
-  delete actor;
-  return true;
-}
--- a/ipc/testshell/TestShellChild.h
+++ b/ipc/testshell/TestShellChild.h
@@ -8,20 +8,16 @@
 #include "mozilla/ipc/PTestShellChild.h"
 #include "mozilla/ipc/PTestShellCommandChild.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 
 #include "nsAutoPtr.h"
 
 namespace mozilla {
 
-namespace jsipc {
-class PContextWrapperChild;
-}
-
 namespace ipc {
 
 class XPCShellEnvironment;
 
 class TestShellChild : public PTestShellChild
 {
 public:
   TestShellChild();
@@ -34,19 +30,16 @@ public:
 
   bool
   RecvPTestShellCommandConstructor(PTestShellCommandChild* aActor,
                                    const nsString& aCommand);
 
   bool
   DeallocPTestShellCommand(PTestShellCommandChild* aCommand);
 
-  PContextWrapperChild* AllocPContextWrapper();
-  bool DeallocPContextWrapper(PContextWrapperChild* actor);
-  
 private:
   nsAutoPtr<XPCShellEnvironment> mXPCShell;
 };
 
 } /* namespace ipc */
 } /* namespace mozilla */
 
 #endif /* ipc_testshell_TestShellChild_h */
--- a/ipc/testshell/TestShellParent.cpp
+++ b/ipc/testshell/TestShellParent.cpp
@@ -3,27 +3,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TestShellParent.h"
 
 /* This must occur *after* TestShellParent.h to avoid typedefs conflicts. */
 #include "mozilla/Util.h"
 
 #include "mozilla/dom/ContentParent.h"
-#include "mozilla/jsipc/ContextWrapperParent.h"
 
 #include "nsAutoPtr.h"
 
 using namespace mozilla;
 using mozilla::ipc::TestShellParent;
 using mozilla::ipc::TestShellCommandParent;
 using mozilla::ipc::PTestShellCommandParent;
 using mozilla::dom::ContentParent;
-using mozilla::jsipc::PContextWrapperParent;
-using mozilla::jsipc::ContextWrapperParent;
 
 PTestShellCommandParent*
 TestShellParent::AllocPTestShellCommand(const nsString& aCommand)
 {
   return new TestShellCommandParent();
 }
 
 bool
@@ -39,42 +36,16 @@ TestShellParent::CommandDone(TestShellCo
 {
   // XXX what should happen if the callback fails?
   /*JSBool ok = */command->RunCallback(aResponse);
   command->ReleaseCallback();
 
   return true;
 }
 
-PContextWrapperParent*
-TestShellParent::AllocPContextWrapper()
-{
-    return new ContextWrapperParent();
-}
-
-bool
-TestShellParent::DeallocPContextWrapper(PContextWrapperParent* actor)
-{
-    delete actor;
-    return true;
-}
-
-JSBool
-TestShellParent::GetGlobalJSObject(JSContext* cx, JSObject** globalp)
-{
-    // TODO Unify this code with TabParent::GetGlobalJSObject.
-    InfallibleTArray<PContextWrapperParent*> cwps(1);
-    ManagedPContextWrapperParent(cwps);
-    if (cwps.Length() < 1)
-        return JS_FALSE;
-    NS_ASSERTION(cwps.Length() == 1, "More than one PContextWrapper?");
-    ContextWrapperParent* cwp = static_cast<ContextWrapperParent*>(cwps[0]);
-    return cwp->GetGlobalJSObject(cx, globalp);
-}
-
 JSBool
 TestShellCommandParent::SetCallback(JSContext* aCx,
                                     JS::Value aCallback)
 {
   if (!mCallback.Hold(aCx)) {
     return JS_FALSE;
   }
 
--- a/ipc/testshell/TestShellParent.h
+++ b/ipc/testshell/TestShellParent.h
@@ -15,40 +15,31 @@
 #include "nsAutoJSValHolder.h"
 #include "nsStringGlue.h"
 
 struct JSContext;
 class JSObject;
 
 namespace mozilla {
 
-namespace jsipc {
-class PContextWrapperParent;
-}
-
 namespace ipc {
 
 class TestShellCommandParent;
 
 class TestShellParent : public PTestShellParent
 {
 public:
   PTestShellCommandParent*
   AllocPTestShellCommand(const nsString& aCommand);
 
   bool
   DeallocPTestShellCommand(PTestShellCommandParent* aActor);
 
   bool
   CommandDone(TestShellCommandParent* aActor, const nsString& aResponse);
-
-  PContextWrapperParent* AllocPContextWrapper();
-  bool DeallocPContextWrapper(PContextWrapperParent* actor);
-
-  JSBool GetGlobalJSObject(JSContext* cx, JSObject** globalp);
 };
 
 
 class TestShellCommandParent : public PTestShellCommandParent
 {
 public:
   TestShellCommandParent() : mCx(NULL) { }
 
deleted file mode 100644
--- a/js/ipc/CPOWTypes.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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_CPOWTypes_h
-#define mozilla_jsipc_CPOWTypes_h
-
-#include "jsapi.h"
-#include "jspubtd.h"
-
-using mozilla::void_t;
-
-namespace mozilla {
-namespace jsipc {
-
-
-template <typename P>
-struct CPOWSingleton
-{
-    static void Write(IPC::Message*, const P&) {}
-    static bool Read(const IPC::Message*, void**, P*) { return true; }
-};
-
-template <typename Type, typename As>
-struct CPOWConvertible
-{
-    static void Write(IPC::Message* m, const Type& t) {
-        WriteParam(m, As(t));
-    }
-    static bool Read(const IPC::Message* m, void** iter, Type* tp) {
-        As a;
-        return (ReadParam(m, iter, &a) &&
-                (*tp = Type(a), true));
-    }
-}; 
-
-} // namespace jsipc
-} // namespace mozilla
-
-namespace IPC {
-
-
-template <> struct ParamTraits<JSType> : public mozilla::jsipc::CPOWConvertible<JSType, int> {};
-
-}
-
-// TODO Use a more standard logging mechanism.
-#ifdef LOGGING
-#define CPOW_LOG(PRINTF_ARGS) \
-    JS_BEGIN_MACRO            \
-    printf("CPOW | ");        \
-    printf PRINTF_ARGS ;      \
-    printf("\n");             \
-    JS_END_MACRO
-#define JSVAL_TO_CSTR(CX, V) \
-    NS_ConvertUTF16toUTF8(nsString(JS_GetStringChars(JS_ValueToString(CX, V)))).get()
-#else
-#define CPOW_LOG(_) JS_BEGIN_MACRO JS_END_MACRO
-#define JSVAL_TO_CSTR(CX, V) ((char*)0)
-#endif
-
-#endif /* mozilla_jsipc_CPOWTypes_h */
deleted file mode 100644
--- a/js/ipc/ContextWrapperChild.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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_ContextWrapperChild_h
-#define mozilla_jsipc_ContextWrapperChild_h
-
-#include "mozilla/jsipc/PContextWrapperChild.h"
-#include "mozilla/jsipc/ObjectWrapperChild.h"
-
-#include "jsapi.h"
-#include "nsClassHashtable.h"
-#include "nsHashKeys.h"
-
-namespace mozilla {
-namespace jsipc {
-
-class ContextWrapperChild
-    : public PContextWrapperChild
-{
-public:
-
-    ContextWrapperChild(JSContext* cx)
-        : mContext(cx)
-    {
-        mResidentObjectTable.Init();
-    }
-
-    JSContext* GetContext() { return mContext; }
-
-    PObjectWrapperChild* GetOrCreateWrapper(JSObject* obj_,
-                                            bool makeGlobal = false)
-    {
-        if (!obj_) // Don't wrap nothin'!
-            return NULL;
-        JS::RootedObject obj(mContext, obj_);
-        PObjectWrapperChild* wrapper;
-        while (!mResidentObjectTable.Get(obj, &wrapper)) {
-            wrapper = SendPObjectWrapperConstructor(AllocPObjectWrapper(obj),
-                                                    makeGlobal);
-            if (wrapper)
-                mResidentObjectTable.Put(obj, wrapper);
-            else
-                return NULL;
-        }
-        return wrapper;
-    }
-
-protected:
-
-    PObjectWrapperChild* AllocPObjectWrapper(JSObject* obj) {
-        return new ObjectWrapperChild(mContext, obj);
-    }
-    
-    PObjectWrapperChild* AllocPObjectWrapper(const bool&) {
-        // This stuff is unused and billm has a patch to delete it.
-        JSAutoRequest ar(mContext);
-        return AllocPObjectWrapper(JS_GetGlobalForScopeChain(mContext));
-    }
-
-    bool DeallocPObjectWrapper(PObjectWrapperChild* actor) {
-        ObjectWrapperChild* owc = static_cast<ObjectWrapperChild*>(actor);
-        mResidentObjectTable.Remove(owc->GetJSObject());
-        return true;
-    }
-
-private:
-
-    JSContext* const mContext;
-
-    nsClassHashtable<nsPtrHashKey<JSObject>,
-                     PObjectWrapperChild> mResidentObjectTable;
-
-};
-
-}}
-
-#endif /* mozilla_jsipc_ContextWrapperChild_h */
deleted file mode 100644
--- a/js/ipc/ContextWrapperParent.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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_ContextWrapperParent_h
-#define mozilla_jsipc_ContextWrapperParent_h
-
-#include "mozilla/jsipc/PContextWrapperParent.h"
-#include "mozilla/jsipc/ObjectWrapperParent.h"
-#include "mozilla/jsipc/CPOWTypes.h"
-
-#include "mozilla/dom/ContentParent.h"
-
-#include "jsapi.h"
-#include "nsAutoJSValHolder.h"
-
-namespace mozilla {
-namespace jsipc {
-
-using mozilla::dom::ContentParent;
-    
-class ContextWrapperParent
-    : public PContextWrapperParent
-{
-public:
-
-    ContextWrapperParent()
-        : mGlobal(NULL)
-    {}
-
-    JSBool GetGlobalJSObject(JSContext* cx, JSObject** globalp) {
-        if (!mGlobal)
-            return JS_FALSE;
-        mGlobalHolder.Hold(cx);
-        mGlobalHolder = *globalp = mGlobal->GetJSObject(cx);
-        return JS_TRUE;
-    }
-
-    ObjectWrapperParent* GetGlobalObjectWrapper() const {
-        return mGlobal;
-    }
-
-    bool RequestRunToCompletion() {
-        return false;
-    }
-
-private:
-
-    ObjectWrapperParent* mGlobal;
-    nsAutoJSValHolder mGlobalHolder;
-
-    PObjectWrapperParent* AllocPObjectWrapper(const bool&) {
-        return new ObjectWrapperParent();
-    }
-
-    bool RecvPObjectWrapperConstructor(PObjectWrapperParent* actor,
-                                       const bool& makeGlobal)
-    {
-        if (makeGlobal) {
-            mGlobalHolder.Release();
-            mGlobal = static_cast<ObjectWrapperParent*>(actor);
-        }
-        return true;
-    }
-
-    bool DeallocPObjectWrapper(PObjectWrapperParent* actor)
-    {
-        if (mGlobal &&
-            mGlobal == static_cast<ObjectWrapperParent*>(actor)) {
-            mGlobalHolder.Release();
-            mGlobal = NULL;
-        }
-        delete actor;
-        return true;
-    }
-
-};
-
-}}
-
-#endif /* mozilla_jsipc_ContextWrapperParent_h */
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptChild.cpp
@@ -0,0 +1,605 @@
+/* -*- 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 "JavaScriptChild.h"
+#include "mozilla/dom/ContentChild.h"
+#include "nsContentUtils.h"
+#include "xpcprivate.h"
+#include "jsfriendapi.h"
+#include "nsCxPusher.h"
+
+using namespace JS;
+using namespace mozilla;
+using namespace mozilla::jsipc;
+
+using mozilla::AutoSafeJSContext;
+
+JavaScriptChild::JavaScriptChild(JSRuntime *rt)
+  : lastId_(0),
+    rt_(rt)
+{
+}
+
+static void
+Trace(JSTracer *trc, void *data)
+{
+    reinterpret_cast<JavaScriptChild *>(data)->trace(trc);
+}
+
+JavaScriptChild::~JavaScriptChild()
+{
+    JS_RemoveExtraGCRootsTracer(rt_, Trace, this);
+}
+
+void
+JavaScriptChild::trace(JSTracer *trc)
+{
+    objects_.trace(trc);
+    ids_.trace(trc);
+}
+
+bool
+JavaScriptChild::init()
+{
+    if (!JavaScriptShared::init())
+        return false;
+    if (!ids_.init())
+        return false;
+
+    JS_AddExtraGCRootsTracer(rt_, Trace, this);
+    return true;
+}
+
+bool
+JavaScriptChild::RecvDropObject(const ObjectId &objId)
+{
+    JSObject *obj = findObject(objId);
+    if (obj) {
+        ids_.remove(obj);
+        objects_.remove(objId);
+    }
+    return true;
+}
+
+bool
+JavaScriptChild::makeId(JSContext *cx, JSObject *obj, ObjectId *idp)
+{
+    if (!obj) {
+        *idp = 0;
+        return true;
+    }
+
+    ObjectId id = ids_.find(obj);
+    if (id) {
+        *idp = id;
+        return true;
+    }
+
+    id = ++lastId_;
+    if (id > MAX_CPOW_IDS) {
+        JS_ReportError(cx, "CPOW id limit reached");
+        return false;
+    }
+
+    id <<= OBJECT_EXTRA_BITS;
+    if (JS_ObjectIsCallable(cx, obj))
+        id |= OBJECT_IS_CALLABLE;
+
+    if (!objects_.add(id, obj))
+        return false;
+    if (!ids_.add(obj, id))
+        return false;
+
+    *idp = id;
+    return true;
+}
+
+JSObject *
+JavaScriptChild::unwrap(JSContext *cx, ObjectId id)
+{
+    JSObject *obj = findObject(id);
+    MOZ_ASSERT(obj);
+    return obj;
+}
+
+bool
+JavaScriptChild::fail(JSContext *cx, ReturnStatus *rs)
+{
+    // By default, we set |undefined| unless we can get a more meaningful
+    // exception.
+    *rs = ReturnStatus(false, JSVariant(void_t()));
+
+    // Note we always return true from this function, since this propagates
+    // to the IPC code, and we don't want a JS failure to cause the death
+    // of the child process.
+
+    jsval exn;
+    if (!JS_GetPendingException(cx, &exn))
+        return true;
+
+    // If we don't clear the pending exception, JS will try to wrap it as it
+    // leaves the current compartment. Since there is no previous compartment,
+    // that would crash.
+    JS_ClearPendingException(cx);
+
+    if (!toVariant(cx, exn, &rs->exn()))
+        return true;
+
+    return true;
+}
+
+bool
+JavaScriptChild::ok(ReturnStatus *rs)
+{
+    *rs = ReturnStatus(true, JSVariant(void_t()));
+    return true;
+}
+
+bool
+JavaScriptChild::AnswerHas(const ObjectId &objId, const nsString &id,
+                               ReturnStatus *rs, bool *bp)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    RootedId internedId(cx);
+    if (!convertGeckoStringToId(cx, id, &internedId))
+        return fail(cx, rs);
+
+    JSBool found;
+    if (!JS_HasPropertyById(cx, obj, internedId, &found))
+        return fail(cx, rs);
+    *bp = !!found;
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerHasOwn(const ObjectId &objId, const nsString &id,
+                                  ReturnStatus *rs, bool *bp)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    RootedId internedId(cx);
+    if (!convertGeckoStringToId(cx, id, &internedId))
+        return fail(cx, rs);
+
+    JSPropertyDescriptor desc;
+    if (!JS_GetPropertyDescriptorById(cx, obj, internedId, 0, &desc))
+        return fail(cx, rs);
+    *bp = (desc.obj == obj);
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerGet(const ObjectId &objId, const ObjectId &receiverId,
+                               const nsString &id,
+                               ReturnStatus *rs, JSVariant *result)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    RootedObject receiver(cx, findObject(receiverId));
+    if (!receiver)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    RootedId internedId(cx);
+    if (!convertGeckoStringToId(cx, id, &internedId))
+        return fail(cx, rs);
+
+    JS::Value val;
+    if (!JS_ForwardGetPropertyTo(cx, obj, internedId, receiver, &val))
+        return fail(cx, rs);
+
+    if (!toVariant(cx, val, result))
+        return fail(cx, rs);
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerSet(const ObjectId &objId, const ObjectId &receiverId,
+                               const nsString &id, const bool &strict,
+                               const JSVariant &value,
+                               ReturnStatus *rs, JSVariant *result)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    // The outparam will be written to the buffer, so it must be set even if
+    // the parent won't read it.
+    *result = void_t();
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    RootedObject receiver(cx, findObject(receiverId));
+    if (!receiver)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    RootedId internedId(cx);
+    if (!convertGeckoStringToId(cx, id, &internedId))
+        return fail(cx, rs);
+
+    MOZ_ASSERT(obj == receiver);
+
+    RootedValue val(cx);
+
+    if (!toValue(cx, value, &val))
+        return fail(cx, rs);
+
+    if (!JS_SetPropertyById(cx, obj, internedId, val.address()))
+        return fail(cx, rs);
+
+    if (!toVariant(cx, val, result))
+        return fail(cx, rs);
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerCall(const ObjectId &objId,
+                            const nsTArray<JSParam> &argv,
+                            ReturnStatus *rs,
+                            JSVariant *result,
+                            nsTArray<JSParam> *outparams)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    // The outparam will be written to the buffer, so it must be set even if
+    // the parent won't read it.
+    *result = void_t();
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    MOZ_ASSERT(argv.Length() >= 2);
+
+    RootedValue objv(cx);
+    if (!toValue(cx, argv[0], &objv))
+        return fail(cx, rs);
+
+    JSAutoCompartment comp(cx, &objv.toObject());
+
+    *result = JSVariant(void_t());
+
+    JS::AutoValueVector vals(cx);
+    JS::AutoValueVector outobjects(cx);
+    for (size_t i = 0; i < argv.Length(); i++) {
+        if (argv[i].type() == JSParam::Tvoid_t) {
+            // This is an outparam.
+            JSCompartment *compartment = js::GetContextCompartment(cx);
+            RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment));
+            RootedObject obj(cx, xpc::NewOutObject(cx, global));
+            if (!obj)
+                return fail(cx, rs);
+            if (!outobjects.append(ObjectValue(*obj)))
+                return fail(cx, rs);
+            if (!vals.append(ObjectValue(*obj)))
+                return fail(cx, rs);
+        } else {
+            RootedValue v(cx);
+            if (!toValue(cx, argv[i].get_JSVariant(), &v))
+                return fail(cx, rs);
+            if (!vals.append(v))
+                return fail(cx, rs);
+        }
+    }
+
+    uint32_t oldOpts =
+        JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT);
+
+    jsval rval;
+    bool success = JS::Call(cx, vals[1], vals[0], vals.length() - 2, vals.begin() + 2, &rval);
+
+    JS_SetOptions(cx, oldOpts);
+
+    if (!success)
+        return fail(cx, rs);
+
+    if (!toVariant(cx, rval, result))
+        return fail(cx, rs);
+
+    // Prefill everything with a dummy jsval.
+    for (size_t i = 0; i < outobjects.length(); i++)
+        outparams->AppendElement(JSParam(void_t()));
+
+    // Go through each argument that was an outparam, retrieve the "value"
+    // field, and add it to a temporary list. We need to do this separately
+    // because the outparams vector is not rooted.
+    vals.clear();
+    for (size_t i = 0; i < outobjects.length(); i++) {
+        RootedObject obj(cx, &outobjects[i].toObject());
+
+        jsval v;
+        JSBool found;
+        if (JS_HasProperty(cx, obj, "value", &found)) {
+            if (!JS_GetProperty(cx, obj, "value", &v))
+                return fail(cx, rs);
+        } else {
+            v = UndefinedValue();
+        }
+        if (!vals.append(v))
+            return fail(cx, rs);
+    }
+
+    // Copy the outparams. If any outparam is already set to a void_t, we
+    // treat this as the outparam never having been set.
+    for (size_t i = 0; i < vals.length(); i++) {
+        JSVariant variant;
+        if (!toVariant(cx, vals[i], &variant))
+            return fail(cx, rs);
+        outparams->ReplaceElementAt(i, JSParam(variant));
+    }
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerInstanceOf(const ObjectId &objId,
+                                  const JSIID &iid,
+                                  ReturnStatus *rs,
+                                  bool *instanceof)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    nsID nsiid;
+    ConvertID(iid, &nsiid);
+
+    nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
+    if (rv != NS_OK)
+        return fail(cx, rs);
+
+    return ok(rs);
+}
+
+void
+EmptyDesc(PPropertyDescriptor *desc)
+{
+    desc->objId() = 0;
+    desc->attrs() = 0;
+    desc->shortid() = 0;
+    desc->value() = void_t();
+    desc->getter() = 0;
+    desc->setter() = 0;
+}
+
+bool
+JavaScriptChild::AnswerGetPropertyDescriptor(const ObjectId &objId,
+                                             const nsString &id,
+                                             const uint32_t &flags,
+                                             ReturnStatus *rs,
+                                             PPropertyDescriptor *out)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    RootedId internedId(cx);
+    if (!convertGeckoStringToId(cx, id, &internedId))
+        return fail(cx, rs);
+
+    JSPropertyDescriptor desc;
+    if (!JS_GetPropertyDescriptorById(cx, obj, internedId, flags, &desc))
+        return fail(cx, rs);
+
+    if (!desc.obj) {
+        EmptyDesc(out);
+        return ok(rs);
+    }
+
+    if (!fromDescriptor(cx, desc, out))
+        return fail(cx, rs);
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerGetOwnPropertyDescriptor(const ObjectId &objId,
+                                                const nsString &id,
+                                                const uint32_t &flags,
+                                                ReturnStatus *rs,
+                                                PPropertyDescriptor *out)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    RootedId internedId(cx);
+    if (!convertGeckoStringToId(cx, id, &internedId))
+        return fail(cx, rs);
+
+    JSPropertyDescriptor desc;
+    if (!JS_GetPropertyDescriptorById(cx, obj, internedId, flags, &desc))
+        return fail(cx, rs);
+
+    if (desc.obj != obj) {
+        EmptyDesc(out);
+        return ok(rs);
+    }
+
+    if (!fromDescriptor(cx, desc, out))
+        return fail(cx, rs);
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerGetOwnPropertyNames(const ObjectId &objId,
+                                           ReturnStatus *rs,
+                                           nsTArray<nsString> *names)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    AutoIdVector props(cx);
+    if (!js::GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &props))
+        return fail(cx, rs);
+
+    for (size_t i = 0; i < props.length(); i++) {
+        nsString name;
+        if (!convertIdToGeckoString(cx, props.handleAt(i), &name))
+            return false;
+
+        names->AppendElement(name);
+    }
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerKeys(const ObjectId &objId,
+                            ReturnStatus *rs,
+                            nsTArray<nsString> *names)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    AutoIdVector props(cx);
+    if (!js::GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
+        return fail(cx, rs);
+
+    for (size_t i = 0; i < props.length(); i++) {
+        nsString name;
+        if (!convertIdToGeckoString(cx, props.handleAt(i), &name))
+            return false;
+
+        names->AppendElement(name);
+    }
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerObjectClassIs(const ObjectId &objId,
+                                     const uint32_t &classValue,
+                                     bool *result)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    *result = js_ObjectClassIs(cx, obj, (js::ESClassValue)classValue);
+
+    return true;
+}
+
+bool
+JavaScriptChild::AnswerClassName(const ObjectId &objId,
+                                 nsString *name)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    *name = NS_ConvertASCIItoUTF16(js_ObjectClassName(cx, obj));
+    return true;
+}
+
+bool
+JavaScriptChild::AnswerIsExtensible(const ObjectId &objId,
+                                    ReturnStatus *rs,
+                                    bool *result)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    *result = false;
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSBool extensible;
+    if (!JS_IsExtensible(cx, obj, &extensible))
+        return fail(cx, rs);
+
+    *result = !!extensible;
+    return true;
+}
+
+bool
+JavaScriptChild::AnswerPreventExtensions(const ObjectId &objId,
+                                         ReturnStatus *rs)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+    if (!JS_PreventExtensions(cx, obj))
+        return fail(cx, rs);
+
+    return ok(rs);
+}
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptChild.h
@@ -0,0 +1,95 @@
+/* -*- 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/. */
+
+#ifndef mozilla_jsipc_JavaScriptChild_h_
+#define mozilla_jsipc_JavaScriptChild_h_
+
+#include "JavaScriptShared.h"
+#include "mozilla/jsipc/PJavaScriptChild.h"
+
+namespace mozilla {
+namespace jsipc {
+
+class JavaScriptChild
+  : public PJavaScriptChild,
+    public JavaScriptShared
+{
+  public:
+    JavaScriptChild(JSRuntime *rt);
+    ~JavaScriptChild();
+
+    bool init();
+    void trace(JSTracer *trc);
+
+    bool RecvDropObject(const ObjectId &objId);
+
+    bool AnswerHas(const ObjectId &objId, const nsString &id,
+                       ReturnStatus *rs, bool *bp);
+    bool AnswerHasOwn(const ObjectId &objId, const nsString &id,
+                          ReturnStatus *rs, bool *bp);
+    bool AnswerGet(const ObjectId &objId, const ObjectId &receiverId,
+                       const nsString &id,
+                       ReturnStatus *rs, JSVariant *result);
+    bool AnswerSet(const ObjectId &objId, const ObjectId &receiverId,
+                       const nsString &id, const bool &strict,
+                       const JSVariant &value,
+                       ReturnStatus *rs, JSVariant *result);
+    bool AnswerCall(const ObjectId &objId,
+                        const nsTArray<JSParam> &argv,
+                        ReturnStatus *rs,
+                        JSVariant *result,
+                        nsTArray<JSParam> *outparams);
+
+    bool AnswerInstanceOf(const ObjectId &objId,
+                          const JSIID &iid,
+                          ReturnStatus *rs,
+                          bool *instanceof);
+    bool AnswerGetPropertyDescriptor(const ObjectId &objId,
+                                     const nsString &id,
+                                     const uint32_t &flags,
+                                     ReturnStatus *rs,
+                                     PPropertyDescriptor *out);
+    bool AnswerGetOwnPropertyDescriptor(const ObjectId &objId,
+                                        const nsString &id,
+                                        const uint32_t &flags,
+                                        ReturnStatus *rs,
+                                        PPropertyDescriptor *out);
+    bool AnswerGetOwnPropertyNames(const ObjectId &objId,
+                                   ReturnStatus *rs,
+                                   nsTArray<nsString> *names);
+    bool AnswerKeys(const ObjectId &objId,
+                    ReturnStatus *rs,
+                    nsTArray<nsString> *names);
+    bool AnswerObjectClassIs(const ObjectId &objId,
+                             const uint32_t &classValue,
+                             bool *result);
+    bool AnswerClassName(const ObjectId &objId,
+                             nsString *result);
+    bool AnswerIsExtensible(const ObjectId &objId,
+                            ReturnStatus *rs,
+                            bool *result);
+    bool AnswerPreventExtensions(const ObjectId &objId,
+                                 ReturnStatus *rs);
+
+  protected:
+    JSObject *unwrap(JSContext *cx, ObjectId id);
+
+  private:
+    bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
+    bool fail(JSContext *cx, ReturnStatus *rs);
+    bool ok(ReturnStatus *rs);
+
+  private:
+    ObjectId lastId_;
+    JSRuntime *rt_;
+    ObjectIdCache ids_;
+};
+
+} // mozilla
+} // jsipc
+
+#endif
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptParent.cpp
@@ -0,0 +1,635 @@
+/* -*- 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 "JavaScriptParent.h"
+#include "mozilla/dom/ContentParent.h"
+#include "nsJSUtils.h"
+#include "jsfriendapi.h"
+#include "jsproxy.h"
+#include "HeapAPI.h"
+#include "xpcprivate.h"
+#include "mozilla/Casting.h"
+
+using namespace js;
+using namespace JS;
+using namespace mozilla;
+using namespace mozilla::jsipc;
+
+JavaScriptParent::JavaScriptParent()
+  : refcount_(1),
+    inactive_(false)
+{
+}
+
+static inline JavaScriptParent *
+ParentOf(JSObject *obj)
+{
+    MOZ_ASSERT(JavaScriptParent::IsCPOW(obj));
+    return reinterpret_cast<JavaScriptParent *>(GetProxyExtra(obj, 0).toPrivate());
+}
+
+ObjectId
+JavaScriptParent::idOf(JSObject *obj)
+{
+    MOZ_ASSERT(JavaScriptParent::IsCPOW(obj));
+
+    Value v = GetProxyExtra(obj, 1);
+    MOZ_ASSERT(v.isDouble());
+
+    ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
+    MOZ_ASSERT(findObject(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 getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                                       PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+    virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
+                                          HandleId id, PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+    virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
+                                PropertyDescriptor *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 iterate(JSContext *cx, HandleObject proxy, unsigned flags,
+                         MutableHandleValue vp) MOZ_OVERRIDE;
+
+    virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
+    virtual void finalize(JSFreeOp *fop, JSObject *proxy) 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 bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
+    virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
+
+    static CPOWProxyHandler singleton;
+};
+
+CPOWProxyHandler CPOWProxyHandler::singleton;
+
+bool
+CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                                        PropertyDescriptor *desc, unsigned flags)
+{
+    return ParentOf(proxy)->getPropertyDescriptor(cx, proxy, id, desc, flags);
+}
+
+bool
+JavaScriptParent::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                                        PropertyDescriptor *desc, unsigned flags)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    ReturnStatus status;
+    PPropertyDescriptor result;
+    if (!CallGetPropertyDescriptor(objId, idstr, flags, &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, PropertyDescriptor *desc, unsigned flags)
+{
+    return ParentOf(proxy)->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
+}
+
+bool
+JavaScriptParent::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                                           PropertyDescriptor *desc, unsigned flags)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    ReturnStatus status;
+    PPropertyDescriptor result;
+    if (!CallGetOwnPropertyDescriptor(objId, idstr, flags, &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,
+                                 PropertyDescriptor *desc)
+{
+    MOZ_CRASH("unimplemented");
+}
+
+bool
+CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    return ParentOf(proxy)->getOwnPropertyNames(cx, proxy, props);
+}
+
+bool
+JavaScriptParent::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    ObjectId objId = idOf(proxy);
+
+    ReturnStatus status;
+    InfallibleTArray<nsString> names;
+    if (!CallGetOwnPropertyNames(objId, &status, &names))
+        return ipcfail(cx);
+    if (!ok(cx, status))
+        return false;
+
+    RootedId name(cx);
+    for (size_t i = 0; i < names.Length(); i++) {
+        if (!convertGeckoStringToId(cx, names[i], &name))
+            return false;
+        if (!props.append(name))
+            return false;
+    }
+
+    return true;
+}
+
+bool
+CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    return ParentOf(proxy)->keys(cx, proxy, props);
+}
+
+bool
+JavaScriptParent::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    ObjectId objId = idOf(proxy);
+
+    ReturnStatus status;
+    InfallibleTArray<nsString> names;
+    if (!CallKeys(objId, &status, &names))
+        return ipcfail(cx);
+    if (!ok(cx, status))
+        return false;
+
+    RootedId name(cx);
+    for (size_t i = 0; i < names.Length(); i++) {
+        if (!convertGeckoStringToId(cx, names[i], &name))
+            return false;
+        if (!props.append(name))
+            return false;
+    }
+
+    return true;
+}
+
+bool
+CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+{
+    MOZ_CRASH("unimplemented");
+}
+
+bool
+CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    MOZ_CRASH("unimplemented");
+}
+
+bool
+CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy)
+{
+    return ParentOf(proxy)->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::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
+{
+    return ParentOf(proxy)->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::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
+{
+    return ParentOf(proxy)->has(cx, proxy, id, bp);
+}
+
+bool
+JavaScriptParent::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)
+{
+    return ParentOf(proxy)->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)
+{
+    return ParentOf(proxy)->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 toValue(cx, val, vp);
+}
+
+bool
+CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+                      JS::HandleId id, bool strict, JS::MutableHandleValue vp)
+{
+    return ParentOf(proxy)->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 toValue(cx, result, vp);
+}
+
+bool
+CPOWProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
+                          MutableHandleValue vp)
+{
+    MOZ_CRASH("unimplemented");
+}
+
+bool
+CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
+{
+    return ParentOf(proxy)->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()) {
+            JSObject *obj = &v.toObject();
+            if (xpc::IsOutObject(cx, obj)) {
+                // Make sure it is not an in-out object.
+                JSBool 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);
+
+    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 (!toValue(cx, outparams[i], &v))
+            return false;
+
+        JSObject *obj = &outobjects[i].toObject();
+        if (!JS_SetProperty(cx, obj, "value", v.address()))
+            return false;
+    }
+
+    if (!toValue(cx, result, args.rval()))
+        return false;
+
+    return true;
+}
+
+void
+CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
+{
+    ParentOf(proxy)->drop(proxy);
+}
+
+void
+JavaScriptParent::drop(JSObject *obj)
+{
+    if (inactive_)
+        return;
+
+    ObjectId objId = idOf(obj);
+
+    objects_.remove(objId);
+    if (!SendDropObject(objId))
+        MOZ_CRASH();
+    decref();
+}
+
+bool
+CPOWProxyHandler::objectClassIs(HandleObject proxy, js::ESClassValue classValue, JSContext *cx)
+{
+    return ParentOf(proxy)->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)
+{
+    return ParentOf(proxy)->className(cx, proxy);
+}
+
+const char *
+JavaScriptParent::className(JSContext *cx, HandleObject proxy)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString name;
+    if (!CallClassName(objId, &name))
+        return NULL;
+
+    return ToNewCString(name);
+}
+
+bool
+JavaScriptParent::init()
+{
+    if (!JavaScriptShared::init())
+        return false;
+
+    return true;
+}
+
+bool
+JavaScriptParent::makeId(JSContext *cx, JSObject *obj, ObjectId *idp)
+{
+    if (!IsProxy(obj) || GetProxyHandler(obj) != &CPOWProxyHandler::singleton) {
+        JS_ReportError(cx, "cannot ipc non-cpow object");
+        return false;
+    }
+
+    *idp = idOf(obj);
+    return true;
+}
+
+JSObject *
+JavaScriptParent::unwrap(JSContext *cx, ObjectId objId)
+{
+    if (JSObject *obj = findObject(objId)) {
+        if (!JS_WrapObject(cx, &obj))
+            return NULL;
+        return obj;
+    }
+
+    if (objId > MAX_CPOW_IDS) {
+        JS_ReportError(cx, "unusable CPOW id");
+        return NULL;
+    }
+
+    bool callable = !!(objId & OBJECT_IS_CALLABLE);
+
+    RootedValue v(cx, UndefinedValue());
+    JSObject *obj = NewProxyObject(cx,
+                                   &CPOWProxyHandler::singleton,
+                                   v,
+                                   NULL,
+                                   NULL,
+                                   callable ? ProxyIsCallable : ProxyNotCallable);
+    if (!obj)
+        return NULL;
+
+    if (!objects_.add(objId, obj))
+        return NULL;
+
+    // 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, "catastrophic IPC failure");
+    return false;
+}
+
+bool
+JavaScriptParent::ok(JSContext *cx, const ReturnStatus &status)
+{
+    if (status.ok())
+        return true;
+
+    RootedValue exn(cx);
+    if (!toValue(cx, status.exn(), &exn))
+        return false;
+
+    JS_SetPendingException(cx, exn);
+    return false;
+}
+
+void
+JavaScriptParent::decref()
+{
+    refcount_--;
+    if (!refcount_)
+        delete this;
+}
+
+void
+JavaScriptParent::incref()
+{
+    refcount_++;
+}
+
+void
+JavaScriptParent::destroyFromContent()
+{
+    inactive_ = true;
+    decref();
+}
+
+/* static */ bool
+JavaScriptParent::IsCPOW(JSObject *obj)
+{
+    return IsProxy(obj) && GetProxyHandler(obj) == &CPOWProxyHandler::singleton;
+}
+
+/* static */ nsresult
+JavaScriptParent::InstanceOf(JSObject *obj, const nsID *id, bool *bp)
+{
+    return ParentOf(obj)->instanceOf(obj, id, bp);
+}
+
+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.ok())
+        return NS_ERROR_UNEXPECTED;
+
+    return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptParent.h
@@ -0,0 +1,84 @@
+/* -*- 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/. */
+
+#ifndef mozilla_jsipc_JavaScriptParent__
+#define mozilla_jsipc_JavaScriptParent__
+
+#include "JavaScriptShared.h"
+#include "mozilla/jsipc/PJavaScriptParent.h"
+#include "jsclass.h"
+
+#ifdef XP_WIN
+#undef GetClassName
+#undef GetClassInfo
+#endif
+
+namespace mozilla {
+namespace jsipc {
+
+class JavaScriptParent
+  : public PJavaScriptParent,
+    public JavaScriptShared
+{
+  public:
+    JavaScriptParent();
+
+    bool init();
+
+  public:
+    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 call(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args);
+    bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+                               JSPropertyDescriptor *desc, unsigned flags);
+    bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+                                  JSPropertyDescriptor *desc, unsigned flags);
+    bool getOwnPropertyNames(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
+    bool keys(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
+    bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
+    const char* className(JSContext *cx, JS::HandleObject proxy);
+    bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
+    bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
+
+    void decref();
+    void incref();
+    void destroyFromContent();
+
+    void drop(JSObject *obj);
+
+    static bool IsCPOW(JSObject *obj);
+    static nsresult InstanceOf(JSObject *obj, const nsID *id, bool *bp);
+
+    nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
+
+  protected:
+    JSObject *unwrap(JSContext *cx, ObjectId objId);
+
+  private:
+    bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
+    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_;
+};
+
+} // jsipc
+} // mozilla
+
+#endif // mozilla_jsipc_JavaScriptWrapper_h__
+
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptShared.cpp
@@ -0,0 +1,397 @@
+/* -*- 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 "JavaScriptShared.h"
+#include "jsfriendapi.h"
+#include "xpcprivate.h"
+
+using namespace js;
+using namespace JS;
+using namespace mozilla;
+using namespace mozilla::jsipc;
+
+ObjectStore::ObjectStore()
+  : table_(SystemAllocPolicy())
+{
+}
+
+bool
+ObjectStore::init()
+{
+    return table_.init(32);
+}
+
+void
+ObjectStore::trace(JSTracer *trc)
+{
+    for (ObjectTable::Range r(table_.all()); !r.empty(); r.popFront()) {
+        JSObject *obj = r.front().value;
+        JS_CallObjectTracer(trc, &obj, "ipc-object");
+        MOZ_ASSERT(obj == r.front().value);
+    }
+}
+
+JSObject *
+ObjectStore::find(ObjectId id)
+{
+    ObjectTable::Ptr p = table_.lookup(id);
+    if (!p)
+        return NULL;
+    return p->value;
+}
+
+bool
+ObjectStore::add(ObjectId id, JSObject *obj)
+{
+    return table_.put(id, obj);
+}
+
+void
+ObjectStore::remove(ObjectId id)
+{
+    table_.remove(id);
+}
+
+ObjectIdCache::ObjectIdCache()
+  : table_(SystemAllocPolicy())
+{
+}
+
+bool
+ObjectIdCache::init()
+{
+    return table_.init(32);
+}
+
+void
+ObjectIdCache::trace(JSTracer *trc)
+{
+    for (ObjectIdTable::Range r(table_.all()); !r.empty(); r.popFront()) {
+        JSObject *obj = r.front().key;
+        JS_CallObjectTracer(trc, &obj, "ipc-id");
+        MOZ_ASSERT(obj == r.front().key);
+    }
+}
+
+ObjectId
+ObjectIdCache::find(JSObject *obj)
+{
+    ObjectIdTable::Ptr p = table_.lookup(obj);
+    if (!p)
+        return 0;
+    return p->value;
+}
+
+bool
+ObjectIdCache::add(JSObject *obj, ObjectId id)
+{
+    return table_.put(obj, id);
+}
+
+void
+ObjectIdCache::remove(JSObject *obj)
+{
+    table_.remove(obj);
+}
+
+bool
+JavaScriptShared::init()
+{
+    if (!objects_.init())
+        return false;
+    return true;
+}
+
+bool
+JavaScriptShared::convertIdToGeckoString(JSContext *cx, JS::HandleId id, nsString *to)
+{
+    RootedValue idval(cx);
+    if (!JS_IdToValue(cx, id, idval.address()))
+        return false;
+
+    RootedString str(cx, JS_ValueToString(cx, idval));
+    if (!str)
+        return false;
+
+    const jschar *chars = JS_GetStringCharsZ(cx, str);
+    if (!chars)
+        return false;
+
+    *to = chars;
+    return true;
+}
+
+bool
+JavaScriptShared::convertGeckoStringToId(JSContext *cx, const nsString &from, JS::MutableHandleId to)
+{
+    RootedString str(cx, JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length()));
+    if (!str)
+        return false;
+
+    return JS_ValueToId(cx, StringValue(str), to.address());
+}
+
+bool
+JavaScriptShared::toVariant(JSContext *cx, jsval from, JSVariant *to)
+{
+    switch (JS_TypeOfValue(cx, from)) {
+      case JSTYPE_VOID:
+        *to = void_t();
+        return true;
+
+      case JSTYPE_NULL:
+      {
+        *to = uint64_t(0);
+        return true;
+      }
+
+      case JSTYPE_OBJECT:
+      case JSTYPE_FUNCTION:
+      {
+        JSObject *obj = from.toObjectOrNull();
+        if (!obj) {
+            JS_ASSERT(from == JSVAL_NULL);
+            *to = uint64_t(0);
+            return true;
+        }
+
+        if (xpc_JSObjectIsID(cx, obj)) {
+            JSIID iid;
+            const nsID *id = xpc_JSObjectToID(cx, obj);
+            ConvertID(*id, &iid);
+            *to = iid;
+            return true;
+        }
+
+        ObjectId id;
+        if (!makeId(cx, obj, &id))
+            return false;
+        *to = uint64_t(id);
+        return true;
+      }
+
+      case JSTYPE_STRING:
+      {
+        nsDependentJSString dep;
+        if (!dep.init(cx, from))
+            return false;
+        *to = dep;
+        return true;
+      }
+
+      case JSTYPE_NUMBER:
+        if (JSVAL_IS_INT(from))
+            *to = double(from.toInt32());
+        else
+            *to = from.toDouble();
+        return true;
+
+      case JSTYPE_BOOLEAN:
+        *to = from.toBoolean();
+        return true;
+
+      default:
+        MOZ_ASSERT(false);
+        return false;
+    }
+}
+
+bool
+JavaScriptShared::toValue(JSContext *cx, const JSVariant &from, MutableHandleValue to)
+{
+    switch (from.type()) {
+        case JSVariant::Tvoid_t:
+          to.set(UndefinedValue());
+          return true;
+
+        case JSVariant::Tuint64_t:
+        {
+          ObjectId id = from.get_uint64_t();
+          if (id) {
+              JSObject *obj = unwrap(cx, id);
+              if (!obj)
+                  return false;
+              to.set(ObjectValue(*obj));
+          } else {
+              to.set(JSVAL_NULL);
+          }
+          return true;
+        }
+
+        case JSVariant::Tdouble:
+          to.set(JS_NumberValue(from.get_double()));
+          return true;
+
+        case JSVariant::Tbool:
+          to.set(BOOLEAN_TO_JSVAL(from.get_bool()));
+          return true;
+
+        case JSVariant::TnsString:
+        {
+          const nsString &old = from.get_nsString();
+          JSString *str = JS_NewUCStringCopyN(cx, old.BeginReading(), old.Length());
+          if (!str)
+              return false;
+          to.set(StringValue(str));
+          return true;
+        }
+
+        case JSVariant::TJSIID:
+        {
+          nsID iid;
+          const JSIID &id = from.get_JSIID();
+          ConvertID(id, &iid);
+
+          JSCompartment *compartment = GetContextCompartment(cx);
+          RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment));
+          JSObject *obj = xpc_NewIDObject(cx, global, iid);
+          if (!obj)
+              return false;
+          to.set(ObjectValue(*obj));
+          return true;
+        }
+
+        default:
+          return false;
+    }
+}
+
+/* static */ void
+JavaScriptShared::ConvertID(const nsID &from, JSIID *to)
+{
+    to->m0() = from.m0;
+    to->m1() = from.m1;
+    to->m2() = from.m2;
+    to->m3_0() = from.m3[0];
+    to->m3_1() = from.m3[1];
+    to->m3_2() = from.m3[2];
+    to->m3_3() = from.m3[3];
+    to->m3_4() = from.m3[4];
+    to->m3_5() = from.m3[5];
+    to->m3_6() = from.m3[6];
+    to->m3_7() = from.m3[7];
+}
+
+/* static */ void
+JavaScriptShared::ConvertID(const JSIID &from, nsID *to)
+{
+    to->m0 = from.m0();
+    to->m1 = from.m1();
+    to->m2 = from.m2();
+    to->m3[0] = from.m3_0();
+    to->m3[1] = from.m3_1();
+    to->m3[2] = from.m3_2();
+    to->m3[3] = from.m3_3();
+    to->m3[4] = from.m3_4();
+    to->m3[5] = from.m3_5();
+    to->m3[6] = from.m3_6();
+    to->m3[7] = from.m3_7();
+}
+
+static const uint32_t DefaultPropertyOp = 1;
+static const uint32_t GetterOnlyPropertyStub = 2;
+static const uint32_t UnknownPropertyOp = 3;
+
+bool
+JavaScriptShared::fromDescriptor(JSContext *cx, const JSPropertyDescriptor &desc, PPropertyDescriptor *out)
+{
+    out->attrs() = desc.attrs;
+    out->shortid() = desc.shortid;
+    if (!toVariant(cx, desc.value, &out->value()))
+        return false;
+
+    if (!makeId(cx, desc.obj, &out->objId()))
+        return false;
+
+    if (!desc.getter) {
+        out->getter() = 0;
+    } else if (desc.attrs & JSPROP_GETTER) {
+        JSObject *getter = JS_FUNC_TO_DATA_PTR(JSObject *, desc.getter);
+        if (!makeId(cx, getter, &out->getter()))
+            return false;
+    } else {
+        if (desc.getter == JS_PropertyStub)
+            out->getter() = DefaultPropertyOp;
+        else
+            out->getter() = UnknownPropertyOp;
+    }
+
+    if (!desc.setter) {
+        out->setter() = 0;
+    } else if (desc.attrs & JSPROP_SETTER) {
+        JSObject *setter = JS_FUNC_TO_DATA_PTR(JSObject  *, desc.setter);
+        if (!makeId(cx, setter, &out->setter()))
+            return false;
+    } else {
+        if (desc.setter == JS_StrictPropertyStub)
+            out->setter() = DefaultPropertyOp;
+        else if (desc.setter == js_GetterOnlyPropertyStub)
+            out->setter() = GetterOnlyPropertyStub;
+        else
+            out->setter() = UnknownPropertyOp;
+    }
+
+    return true;
+}
+
+JSBool
+UnknownPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
+{
+    JS_ReportError(cx, "getter could not be wrapped via CPOWs");
+    return JS_FALSE;
+}
+
+JSBool
+UnknownStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHandleValue vp)
+{
+    JS_ReportError(cx, "setter could not be wrapped via CPOWs");
+    return JS_FALSE;
+}
+
+bool
+JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in, JSPropertyDescriptor *out)
+{
+    out->attrs = in.attrs();
+    out->shortid = in.shortid();
+    if (!toValue(cx, in.value(), &out->value))
+        return false;
+    if (!unwrap(cx, in.objId(), &out->obj))
+        return false;
+
+    if (!in.getter()) {
+        out->getter = NULL;
+    } else if (in.attrs() & JSPROP_GETTER) {
+        JSObject *getter;
+        if (!unwrap(cx, in.getter(), &getter))
+            return false;
+        out->getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter);
+    } else {
+        if (in.getter() == DefaultPropertyOp)
+            out->getter = JS_PropertyStub;
+        else
+            out->getter = UnknownPropertyStub;
+    }
+
+    if (!in.setter()) {
+        out->setter = NULL;
+    } else if (in.attrs() & JSPROP_SETTER) {
+        JSObject *setter;
+        if (!unwrap(cx, in.setter(), &setter))
+            return false;
+        out->setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter);
+    } else {
+        if (in.setter() == DefaultPropertyOp)
+            out->setter = JS_StrictPropertyStub;
+        else if (in.setter() == GetterOnlyPropertyStub)
+            out->setter = js_GetterOnlyPropertyStub;
+        else
+            out->setter = UnknownStrictPropertyStub;
+    }
+
+    return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptShared.h
@@ -0,0 +1,119 @@
+/* -*- 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_JavaScriptShared_h__
+#define mozilla_jsipc_JavaScriptShared_h__
+
+#include "jsapi.h"
+#include "jspubtd.h"
+#include "js/HashTable.h"
+#include "mozilla/dom/DOMTypes.h"
+#include "mozilla/jsipc/PJavaScript.h"
+#include "nsJSUtils.h"
+#include "nsFrameMessageManager.h"
+
+namespace mozilla {
+namespace jsipc {
+
+typedef uint64_t ObjectId;
+
+// Map ids -> JSObjects
+class ObjectStore
+{
+    typedef js::DefaultHasher<ObjectId> TableKeyHasher;
+
+    typedef js::HashMap<ObjectId, JSObject *, TableKeyHasher, js::SystemAllocPolicy> ObjectTable;
+
+  public:
+    ObjectStore();
+
+    bool init();
+    void trace(JSTracer *trc);
+
+    bool add(ObjectId id, JSObject *obj);
+    JSObject *find(ObjectId id);
+    void remove(ObjectId id);
+
+  private:
+    ObjectTable table_;
+};
+
+// Map JSObjects -> ids
+class ObjectIdCache
+{
+    typedef js::PointerHasher<JSObject *, 3> Hasher;
+    typedef js::HashMap<JSObject *, ObjectId, Hasher, js::SystemAllocPolicy> ObjectIdTable;
+
+  public:
+    ObjectIdCache();
+
+    bool init();
+    void trace(JSTracer *trc);
+
+    bool add(JSObject *, ObjectId id);
+    ObjectId find(JSObject *obj);
+    void remove(JSObject *obj);
+
+  private:
+    ObjectIdTable table_;
+};
+
+class JavaScriptShared
+{
+  public:
+    bool init();
+
+    static const uint32_t OBJECT_EXTRA_BITS  = 1;
+    static const uint32_t OBJECT_IS_CALLABLE = (1 << 0);
+
+  protected:
+    bool toVariant(JSContext *cx, jsval from, JSVariant *to);
+    bool toValue(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
+    bool fromDescriptor(JSContext *cx, const JSPropertyDescriptor &desc, PPropertyDescriptor *out);
+    bool toDescriptor(JSContext *cx, const PPropertyDescriptor &in, JSPropertyDescriptor *out);
+    bool convertIdToGeckoString(JSContext *cx, JS::HandleId id, nsString *to);
+    bool convertGeckoStringToId(JSContext *cx, const nsString &from, JS::MutableHandleId id);
+
+    bool toValue(JSContext *cx, const JSVariant &from, jsval *to) {
+        JS::RootedValue v(cx);
+        if (!toValue(cx, from, &v))
+            return false;
+        *to = v;
+        return true;
+    }
+
+    virtual bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp) = 0;
+    virtual JSObject *unwrap(JSContext *cx, ObjectId id) = 0;
+
+    bool unwrap(JSContext *cx, ObjectId id, JSObject **objp) {
+        if (!id) {
+            *objp = NULL;
+            return true;
+        }
+
+        *objp = unwrap(cx, id);
+        return !!*objp;
+    }
+
+    static void ConvertID(const nsID &from, JSIID *to);
+    static void ConvertID(const JSIID &from, nsID *to);
+
+    JSObject *findObject(uint32_t objId) {
+        return objects_.find(objId);
+    }
+
+  protected:
+    ObjectStore objects_;
+};
+
+// Use 47 at most, to be safe, since jsval privates are encoded as doubles.
+static const uint64_t MAX_CPOW_IDS = (uint64_t(1) << 47) - 1;
+
+} // namespace jsipc
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptTypes.ipdlh
@@ -0,0 +1,78 @@
+/* -*- 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 DOMTypes;
+
+using mozilla::void_t;
+
+namespace mozilla {
+namespace jsipc {
+
+struct JSIID
+{
+    uint32_t m0;
+    uint16_t m1;
+    uint16_t m2;
+    uint8_t m3_0;
+    uint8_t m3_1;
+    uint8_t m3_2;
+    uint8_t m3_3;
+    uint8_t m3_4;
+    uint8_t m3_5;
+    uint8_t m3_6;
+    uint8_t m3_7;
+};
+
+union JSVariant
+{
+    void_t;     /* |undefined| */
+    nsString;   /* StringValue(x) */
+    uint64_t;   /* ID that maps to a JSObject (cpow on parent, original on child). */
+    double;     /* NumberValue(x) */
+    bool;       /* BooleanValue(x) */
+    JSIID;      /* XPC nsIID */
+};
+
+struct ReturnStatus
+{
+    bool ok;        /* True for success, false for failure. */
+    JSVariant exn;  /* Exception, if |ok| is false. */
+};
+
+union JSParam
+{
+    void_t;     /* value is strictly an xpc out param */
+    JSVariant;  /* actual value to pass through */
+};
+
+struct PPropertyDescriptor
+{
+    uint64_t    objId;
+    uint32_t    attrs;
+    uint32_t    shortid;
+    JSVariant   value;
+
+    // How to interpret these values depends on whether JSPROP_GETTER/SETTER
+    // are set. If set, the corresponding value is a CPOW or 0 for NULL.
+    // Otherwise, the following table is used:
+    //
+    //  0 - NULL
+    //  1 - Default getter or setter.
+    //  2 - js_GetterOnlyPropertyStub (setter only)
+    //  3 - Unknown
+    uint64_t    getter;
+    uint64_t    setter;
+};
+
+struct CpowEntry
+{
+  nsString name;
+  JSVariant value;
+};
+
+}
+}
--- a/js/ipc/Makefile.in
+++ b/js/ipc/Makefile.in
@@ -10,18 +10,24 @@ VPATH     = @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = jsipc_s
 LIBXUL_LIBRARY = 1
 FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY = 1
 FAIL_ON_WARNINGS = 1
 
-# For nsDependentJSString
+EXPORTS_mozilla/jsipc = \
+  JavaScriptParent.h \
+  $(NULL)
+
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/dom/base \
+  -I$(topsrcdir)/js/ipc \
+  -I$(topsrcdir)/js/public \
+  -I$(topsrcdir)/js/xpconnect/src \
   $(NULL)
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
deleted file mode 100644
--- a/js/ipc/ObjectWrapperChild.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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 "mozilla/GuardObjects.h"
-
-#include "base/basictypes.h"
-
-#include "mozilla/jsipc/ContextWrapperChild.h"
-#include "mozilla/jsipc/ObjectWrapperChild.h"
-#include "mozilla/jsipc/CPOWTypes.h"
-
-#include "jsapi.h"
-#include "nsAutoPtr.h"
-#include "nsTArray.h"
-#include "nsContentUtils.h"
-#include "nsCxPusher.h"
-#include "nsJSUtils.h"
-
-using namespace mozilla::jsipc;
-using namespace js;
-
-namespace {
-
-    class MOZ_STACK_CLASS AutoContextPusher {
-
-        nsCxPusher mStack;
-        JSContext* const mContext;
-        const uint32_t mSavedOptions;
-        MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-
-    public:
-
-        AutoContextPusher(JSContext* cx
-                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-            : mContext(cx)
-            , mSavedOptions(JS_SetOptions(cx, (JS_GetOptions(cx) |
-                                               JSOPTION_DONT_REPORT_UNCAUGHT)))
-        {
-            MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-            mStack.Push(cx);
-        }
-
-        ~AutoContextPusher() {
-            mStack.Pop();
-            JS_SetOptions(mContext, mSavedOptions);
-        }
-
-    };
-
-    class StatusPtrOwner
-    {
-        OperationStatus* mStatusPtr;
-    public:
-        StatusPtrOwner() : mStatusPtr(NULL) {}
-        void SetStatusPtr(OperationStatus* statusPtr) {
-            mStatusPtr = statusPtr;
-            // By default, initialize mStatusPtr to failure without an
-            // exception.  Doing so only when the union is uninitialized
-            // allows AutoCheckOperation classes to be nested on the
-            // stack, just in case AnswerConstruct, for example, calls
-            // AnswerCall (as it once did, before there were unrelated
-            // problems with that approach).
-            if (mStatusPtr->type() == OperationStatus::T__None)
-                *mStatusPtr = JS_FALSE;
-        }
-        OperationStatus* StatusPtr() {
-            NS_ASSERTION(mStatusPtr, "Should have called SetStatusPtr by now.");
-            return mStatusPtr;
-        }
-    };
-
-    typedef AutoCheckOperationBase<StatusPtrOwner> ACOBase;
-
-    class AutoCheckOperation : public ACOBase
-    {
-        MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-    public:
-        AutoCheckOperation(ObjectWrapperChild* owc,
-                           OperationStatus* statusPtr
-                           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-            : ACOBase(NULL, owc)
-        {
-            MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-            SetStatusPtr(statusPtr);
-        }
-    };
-}
-
-void
-ObjectWrapperChild::CheckOperation(JSContext*,
-                                   OperationStatus* status)
-{
-    NS_PRECONDITION(status->type() != OperationStatus::T__None,
-                    "Checking an uninitialized operation.");
-
-    JSContext* cx = Manager()->GetContext();
-    jsval thrown;
-
-    if (JS_GetPendingException(cx, &thrown)) {
-        NS_ASSERTION(!(status->type() == OperationStatus::TJSBool &&
-                       status->get_JSBool()),
-                     "Operation succeeded but exception was thrown?");
-        JSVariant exception;
-        if (!jsval_to_JSVariant(cx, thrown, &exception))
-            exception = void_t(); // XXX Useful?
-        *status = exception;
-        JS_ClearPendingException(cx);
-    }
-}
-
-ObjectWrapperChild::ObjectWrapperChild(JSContext* cx, JSObject* obj)
-    : mObj(obj)
-{
-    AutoContextPusher acp(cx);
-#ifdef DEBUG
-    bool added =
-#endif
-         JS_AddObjectRoot(cx, &mObj);
-    NS_ASSERTION(added, "ObjectWrapperChild constructor failed to root JSObject*");
-}
-
-void
-ObjectWrapperChild::ActorDestroy(ActorDestroyReason why)
-{
-    JSContext* cx = Manager()->GetContext();
-    AutoContextPusher acp(cx);
-    JS_RemoveObjectRoot(cx, &mObj);
-}
-
-bool
-ObjectWrapperChild::JSObject_to_JSVariant(JSContext* cx, JSObject* from,
-                                          JSVariant* to)
-{
-    *to = Manager()->GetOrCreateWrapper(from);
-    return true;
-}
-
-bool
-ObjectWrapperChild::jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to)
-{
-    switch (JS_TypeOfValue(cx, from)) {
-    case JSTYPE_VOID:
-        *to = void_t();
-        return true;
-    case JSTYPE_NULL:
-        if (from != JSVAL_NULL)
-            return false;
-        // fall through
-    case JSTYPE_FUNCTION:
-        // fall through
-    case JSTYPE_OBJECT:
-        return JSObject_to_JSVariant(cx, JSVAL_TO_OBJECT(from), to);
-    case JSTYPE_STRING:
-        {
-            nsDependentJSString depStr;
-            if (!depStr.init(cx, from))
-                return false;
-            *to = depStr;
-        }
-        return true;
-    case JSTYPE_NUMBER:
-        if (JSVAL_IS_INT(from))
-            *to = JSVAL_TO_INT(from);
-        else if (JSVAL_IS_DOUBLE(from))
-            *to = JSVAL_TO_DOUBLE(from);
-        else return false;
-        return true;
-    case JSTYPE_BOOLEAN:
-        *to = !!JSVAL_TO_BOOLEAN(from);
-        return true;
-    default:
-        return false;
-    }
-}
-
-/*static*/ bool
-ObjectWrapperChild::
-JSObject_from_PObjectWrapperChild(JSContext*,
-                                  const PObjectWrapperChild* from,
-                                  JSObject** to)
-{
-    const ObjectWrapperChild* owc =
-        static_cast<const ObjectWrapperChild*>(from);
-    *to = owc ? owc->mObj : NULL;
-    return true;
-}
-    
-/*static*/ bool
-ObjectWrapperChild::JSObject_from_JSVariant(JSContext* cx,
-                                            const JSVariant& from,
-                                            JSObject** to)
-{
-    if (from.type() != JSVariant::TPObjectWrapperChild)
-        return false;
-    return JSObject_from_PObjectWrapperChild(cx,
-                                             from.get_PObjectWrapperChild(),
-                                             to);
-}
-
-/*static*/ bool
-ObjectWrapperChild::jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
-                                         jsval* to)
-{
-    switch (from.type()) {
-    case JSVariant::Tvoid_t:
-        *to = JSVAL_VOID;
-        return true;
-    case JSVariant::TPObjectWrapperChild:
-        {
-            JSObject* obj;
-            if (!JSObject_from_JSVariant(cx, from, &obj))
-                return false;
-            *to = OBJECT_TO_JSVAL(obj);
-            return true;
-        }
-    case JSVariant::TnsString:
-        {
-            const nsString& str = from.get_nsString();
-            JSString* s = JS_NewUCStringCopyN(cx,
-                                              str.BeginReading(),
-                                              str.Length());
-            if (!s)
-                return false;
-            *to = STRING_TO_JSVAL(s);
-        }
-        return true;
-    case JSVariant::Tint:
-        *to = INT_TO_JSVAL(from.get_int());
-        return true;
-    case JSVariant::Tdouble:
-        *to = JS_NumberValue(from.get_double());
-        return true;
-    case JSVariant::Tbool:
-        *to = BOOLEAN_TO_JSVAL(from.get_bool());
-        return true;
-    default:
-        return false;
-    }
-}
-    
-ContextWrapperChild*
-ObjectWrapperChild::Manager()
-{
-    PContextWrapperChild* pcwc = PObjectWrapperChild::Manager();
-    return static_cast<ContextWrapperChild*>(pcwc);
-}
-
-static bool
-jsid_to_nsString(JSContext* cx, jsid from, nsString* to)
-{
-    if (JSID_IS_STRING(from)) {
-        size_t length;
-        const jschar* chars = JS_GetInternedStringCharsAndLength(JSID_TO_STRING(from), &length);
-        *to = nsDependentString(chars, length);
-        return true;
-    }
-    return false;
-}
-    
-static bool
-jsid_from_nsString(JSContext* cx, const nsString& from, jsid* to)
-{
-    JSString* str = JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length());
-    if (!str)
-        return false;
-    return JS_ValueToId(cx, STRING_TO_JSVAL(str), to);
-}
-
-#if 0
-// The general schema for ObjectWrapperChild::Answer* methods:
-bool
-ObjectWrapperChild::AnswerSomething(/* in-parameters */
-                                    /* out-parameters */)
-{
-    // initialize out-parameters for failure
-    JSContext* cx = Manager()->GetContext();
-    AutoContextPusher acp(cx);
-    // validate in-parameters, else return false
-    // successfully perform local JS operations, else return true
-    // perform out-parameter conversions, else return false
-    return true;
-}
-// There's an important subtlety here: though a local JS operation may
-// fail, leaving out-parameters uninitialized, we must initialize all
-// out-parameters when reporting success (returning true) to the IPC
-// messaging system.  See AnswerGetProperty for illustration.
-#endif
-
-bool
-ObjectWrapperChild::AnswerAddProperty(const nsString& id,
-                                      OperationStatus* status)
-{
-    JSContext* cx = Manager()->GetContext();
-    JS::RootedId interned_id(cx);
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    if (!jsid_from_nsString(cx, id, interned_id.address()))
-        return false;
-
-    *status = JS_DefinePropertyById(cx, mObj, interned_id, JSVAL_VOID,
-                                    NULL, NULL, 0);
-    return true;
-}
-
-bool
-ObjectWrapperChild::AnswerGetProperty(const nsString& id,
-                                      OperationStatus* status, JSVariant* vp)
-{
-    JSContext* cx = Manager()->GetContext();
-    JS::RootedId interned_id(cx);
-    JS::RootedValue val(cx);
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    if (!jsid_from_nsString(cx, id, interned_id.address()))
-        return false;
-
-    *status = JS_GetPropertyById(cx, mObj, interned_id, val.address());
-
-    // Since we fully expect this call to jsval_to_JSVariant to return
-    // true, we can't just leave vp uninitialized when JS_GetPropertyById
-    // returns JS_FALSE.  This pitfall could be avoided in general if IPDL
-    // ensured that outparams were pre-initialized to some default value
-    // (XXXfixme cjones?).
-    return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
-}
-
-bool
-ObjectWrapperChild::AnswerSetProperty(const nsString& id, const JSVariant& v,
-                                      OperationStatus* status, JSVariant* vp)
-{
-    *vp = v;
-
-    JSContext* cx = Manager()->GetContext();
-    JS::RootedId interned_id(cx);
-    JS::RootedValue val(cx);
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    if (!jsid_from_nsString(cx, id, interned_id.address()) ||
-        !jsval_from_JSVariant(cx, v, val.address())) {
-        return false;
-    }
-
-    *status = JS_SetPropertyById(cx, mObj, interned_id, val.address());
-
-    return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
-}
-
-bool
-ObjectWrapperChild::AnswerDelProperty(const nsString& id,
-                                      OperationStatus* status, JSVariant* vp)
-{
-    JSContext* cx = Manager()->GetContext();
-    JS::RootedId interned_id(cx);
-    JS::RootedValue val(cx);
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    if (!jsid_from_nsString(cx, id, interned_id.address()))
-        return false;
-
-    *status = JS_DeletePropertyById2(cx, mObj, interned_id, val.address());
-
-    return jsval_to_JSVariant(cx, aco.Ok() ? val : JSVAL_VOID, vp);
-}
-
-static const uint32_t sNextIdIndexSlot = 0;
-static const uint32_t sNumNewEnumerateStateSlots = 1;
-
-static void
-CPOW_NewEnumerateState_FreeIds(JSObject* state)
-{
-    nsTArray<nsString>* strIds =
-        static_cast<nsTArray<nsString>*>(JS_GetPrivate(state));
-
-    if (strIds) {
-        delete strIds;
-        JS_SetPrivate(state, NULL);
-    }
-}
-
-static void
-CPOW_NewEnumerateState_Finalize(JSFreeOp* fop, JSObject* state)
-{
-    CPOW_NewEnumerateState_FreeIds(state);
-}
-
-// Similar to IteratorClass in XPCWrapper.cpp
-static const JSClass sCPOW_NewEnumerateState_JSClass = {
-    "CPOW NewEnumerate State",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(sNumNewEnumerateStateSlots),
-    JS_PropertyStub,  JS_DeletePropertyStub,
-    JS_PropertyStub,  JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub,
-    JS_ConvertStub,   CPOW_NewEnumerateState_Finalize
-};
-
-bool
-ObjectWrapperChild::AnswerNewEnumerateInit(/* no in-parameters */
-                                           OperationStatus* status, JSVariant* statep, int* idp)
-{
-    *idp = 0;
-
-    JSContext* cx = Manager()->GetContext();
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    JSClass* clasp = const_cast<JSClass*>(&sCPOW_NewEnumerateState_JSClass);
-    JS::Rooted<JSObject*> state(cx, JS_NewObjectWithGivenProto(cx, clasp, NULL, NULL));
-    if (!state)
-        return false;
-
-    for (JS::RootedObject proto(cx, mObj); proto; ) {
-        AutoIdArray ids(cx, JS_Enumerate(cx, proto));
-        for (size_t i = 0; i < ids.length(); ++i)
-            JS_DefinePropertyById(cx, state, ids[i], JSVAL_VOID,
-                                  NULL, NULL, JSPROP_ENUMERATE | JSPROP_SHARED);
-
-        if (!JS_GetPrototype(cx, proto, proto.address()))
-            return false;
-    }
-
-    InfallibleTArray<nsString>* strIds;
-    {
-        AutoIdArray ids(cx, JS_Enumerate(cx, state));
-        if (!ids)
-            return false;
-        strIds = new InfallibleTArray<nsString>(ids.length());
-        for (size_t i = 0; i < ids.length(); ++i)
-            if (!jsid_to_nsString(cx, ids[i], strIds->AppendElement())) {
-                delete strIds;
-                return false;
-            }
-    }
-    *idp = strIds->Length();
-
-    JS_SetPrivate(state, strIds);
-    JS_SetReservedSlot(state, sNextIdIndexSlot, JSVAL_ZERO);
-               
-    *status = JSObject_to_JSVariant(cx, state, statep);
-
-    return true;
-}
-
-bool
-ObjectWrapperChild::AnswerNewEnumerateNext(const JSVariant& in_state,
-                                           OperationStatus* status, JSVariant* statep, nsString* idp)
-{
-    JSObject* state;
-
-    *statep = in_state;
-    idp->Truncate();
-    
-    JSContext* cx = Manager()->GetContext();
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    if (!JSObject_from_JSVariant(cx, in_state, &state))
-        return false;
-
-    InfallibleTArray<nsString>* strIds =
-        static_cast<InfallibleTArray<nsString>*>(JS_GetPrivate(state));
-
-    if (!strIds)
-        return false;
-
-    jsval v = JS_GetReservedSlot(state, sNextIdIndexSlot);
-
-    int32_t i = JSVAL_TO_INT(v);
-    NS_ASSERTION(i >= 0, "Index of next jsid negative?");
-    NS_ASSERTION(size_t(i) <= strIds->Length(), "Index of next jsid too large?");
-
-    if (size_t(i) == strIds->Length()) {
-        *status = JS_TRUE;
-        return JSObject_to_JSVariant(cx, NULL, statep);
-    }
-
-    *idp = strIds->ElementAt(i);
-    JS_SetReservedSlot(state, sNextIdIndexSlot, INT_TO_JSVAL(i + 1));
-    *status = JS_TRUE;
-    return true;
-}
-    
-bool
-ObjectWrapperChild::RecvNewEnumerateDestroy(const JSVariant& in_state)
-{
-    JSObject* state;
-
-    JSContext* cx = Manager()->GetContext();
-    AutoContextPusher acp(cx);
-
-    if (!JSObject_from_JSVariant(cx, in_state, &state))
-        return false;
-
-    CPOW_NewEnumerateState_FreeIds(state);
-
-    return true;
-}
-
-bool
-ObjectWrapperChild::AnswerNewResolve(const nsString& id, const int& flags,
-                                     OperationStatus* status, PObjectWrapperChild** obj2)
-{
-    *obj2 = NULL;
-
-    JSContext* cx = Manager()->GetContext();
-    JS::RootedId interned_id(cx);
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    if (!jsid_from_nsString(cx, id, interned_id.address()))
-        return false;
-
-    CPOW_LOG(("new-resolving \"%s\"...",
-              NS_ConvertUTF16toUTF8(id).get()));
-
-    JS::Rooted<JSPropertyDescriptor> desc(cx);
-    if (!JS_GetPropertyDescriptorById(cx, mObj, interned_id, flags, desc.address()))
-        return true;
-
-    *status = JS_TRUE;
-
-    if (desc.get().obj)
-        *obj2 = Manager()->GetOrCreateWrapper(desc.get().obj);
-
-    return true;
-}
-
-bool
-ObjectWrapperChild::AnswerConvert(const JSType& type,
-                                  OperationStatus* status, JSVariant* vp)
-{
-    JSContext* cx = Manager()->GetContext();
-    JS::RootedValue v(cx);
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-    *status = JS_ConvertValue(cx, OBJECT_TO_JSVAL(mObj), type, v.address());
-    return jsval_to_JSVariant(cx, aco.Ok() ? v : JSVAL_VOID, vp);
-}
-
-namespace {
-    // Should be an overestimate of typical JS function arity.
-    typedef nsAutoTArray<jsval, 5> AutoJSArgs;
-}
-
-bool
-ObjectWrapperChild::AnswerCall(PObjectWrapperChild* receiver, const InfallibleTArray<JSVariant>& argv,
-                               OperationStatus* status, JSVariant* rval)
-{
-    JSContext* cx = Manager()->GetContext();
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    JS::RootedObject obj(cx);
-    if (!JSObject_from_PObjectWrapperChild(cx, receiver, obj.address()))
-        return false;
-
-    AutoJSArgs args;
-    uint32_t argc = argv.Length();
-    jsval *jsargs = args.AppendElements(argc);
-    if (!jsargs)
-        return false;
-    AutoArrayRooter tvr(cx, argc, jsargs);
-
-    for (uint32_t i = 0; i < argc; ++i)
-        if (!jsval_from_JSVariant(cx, argv.ElementAt(i), jsargs + i))
-            return false;
-
-    JS::RootedValue rv(cx);
-    *status = JS_CallFunctionValue(cx, obj, OBJECT_TO_JSVAL(mObj),
-                                   argv.Length(), jsargs, rv.address());
-
-    return jsval_to_JSVariant(cx, aco.Ok() ? rv : JSVAL_VOID, rval);
-}
-
-bool
-ObjectWrapperChild::AnswerConstruct(const InfallibleTArray<JSVariant>& argv,
-                                    OperationStatus* status, PObjectWrapperChild** rval)
-{
-    JSContext* cx = Manager()->GetContext();
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-
-    AutoJSArgs args;
-    uint32_t argc = argv.Length();
-    jsval* jsargs = args.AppendElements(argc);
-    if (!jsargs)
-        return false;
-    AutoArrayRooter tvr(cx, argc, jsargs);
-
-    for (uint32_t i = 0; i < argc; ++i)
-        if (!jsval_from_JSVariant(cx, argv.ElementAt(i), jsargs + i))
-            return false;
-
-    JSObject* obj = JS_New(cx, mObj, argc, jsargs);
-
-    *status = !!obj;
-    *rval = Manager()->GetOrCreateWrapper(obj);
-
-    return true;
-}
-
-bool
-ObjectWrapperChild::AnswerHasInstance(const JSVariant& v,
-                                      OperationStatus* status, JSBool* bp)
-{
-    JSContext* cx = Manager()->GetContext();
-    JS::RootedValue candidate(cx);
-    AutoContextPusher acp(cx);
-    AutoCheckOperation aco(this, status);
-    if (!jsval_from_JSVariant(cx, v, candidate.address()))
-        return false;
-    *status = JS_HasInstance(cx, mObj, candidate, bp);
-    return true;
-}
deleted file mode 100644
--- a/js/ipc/ObjectWrapperChild.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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_ObjectWrapperChild_h
-#define mozilla_jsipc_ObjectWrapperChild_h
-
-#include "mozilla/jsipc/PObjectWrapperChild.h"
-
-// For OperationChecker and AutoCheckOperationBase.
-#include "mozilla/jsipc/ObjectWrapperParent.h"
-
-using mozilla::jsipc::JSVariant;
-
-namespace mozilla {
-namespace jsipc {
-
-class ContextWrapperChild;
-
-class ObjectWrapperChild
-    : public PObjectWrapperChild
-    , public OperationChecker
-{
-public:
-
-    ObjectWrapperChild(JSContext* cx, JSObject* obj);
-
-    JSObject* GetJSObject() const { return mObj; }
-
-    void CheckOperation(JSContext* cx, OperationStatus* status);
-    
-private:
-
-    JSObject* mObj;
-
-    bool JSObject_to_JSVariant(JSContext* cx, JSObject* from, JSVariant* to);
-    bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to);
-
-    static bool JSObject_from_PObjectWrapperChild(JSContext* cx,
-                                                  const PObjectWrapperChild* from,
-                                                  JSObject** to);
-    static bool JSObject_from_JSVariant(JSContext* cx, const JSVariant& from,
-                                        JSObject** to);
-    static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
-                                     jsval* to);
-
-    ContextWrapperChild* Manager();
-
-protected:
-
-    void ActorDestroy(ActorDestroyReason why);
-
-    bool AnswerAddProperty(const nsString& id,
-                           OperationStatus* status);
-
-    bool AnswerGetProperty(const nsString& id,
-                           OperationStatus* status, JSVariant* vp);
-
-    bool AnswerSetProperty(const nsString& id, const JSVariant& v,
-                           OperationStatus* status, JSVariant* vp);
-
-    bool AnswerDelProperty(const nsString& id,
-                           OperationStatus* status, JSVariant* vp);
-
-    bool AnswerNewEnumerateInit(/* no in-parameters */
-                                OperationStatus* status, JSVariant* statep, int* idp);
-
-    bool AnswerNewEnumerateNext(const JSVariant& in_state,
-                                OperationStatus* status, JSVariant* statep, nsString* idp);
-
-    bool RecvNewEnumerateDestroy(const JSVariant& in_state);
-
-    bool AnswerNewResolve(const nsString& id, const int& flags,
-                          OperationStatus* status, PObjectWrapperChild** obj2);
-
-    bool AnswerConvert(const JSType& type,
-                       OperationStatus* status, JSVariant* vp);
-
-    bool AnswerCall(PObjectWrapperChild* receiver, const InfallibleTArray<JSVariant>& argv,
-                    OperationStatus* status, JSVariant* rval);
-
-    bool AnswerConstruct(const InfallibleTArray<JSVariant>& argv,
-                         OperationStatus* status, PObjectWrapperChild** rval);
-
-    bool AnswerHasInstance(const JSVariant& v,
-                           OperationStatus* status, JSBool* bp);
-};
-
-}}
-  
-#endif /* mozilla_jsipc_ObjectWrapperChild_h */
deleted file mode 100644
--- a/js/ipc/ObjectWrapperParent.cpp
+++ /dev/null
@@ -1,733 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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 "mozilla/GuardObjects.h"
-
-#include "mozilla/jsipc/ObjectWrapperParent.h"
-#include "mozilla/jsipc/ContextWrapperParent.h"
-#include "mozilla/jsipc/CPOWTypes.h"
-#include "mozilla/unused.h"
-#include "nsJSUtils.h"
-
-#include "jsutil.h"
-#include "jsfriendapi.h"
-
-using namespace mozilla::jsipc;
-using namespace JS;
-
-namespace {
-
-    // Only need one reserved slot because the ObjectWrapperParent* is
-    // stored in the private slot.
-    static const unsigned sFlagsSlot = 0;
-    static const unsigned sNumSlots = 1;
-    static const unsigned CPOW_FLAG_RESOLVING = 1 << 0;
-
-    class AutoResolveFlag
-    {
-        Rooted<JSObject*> mObj;
-        unsigned mOldFlags;
-        MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-
-        static unsigned GetFlags(JSObject* obj) {
-            jsval v = JS_GetReservedSlot(obj, sFlagsSlot);
-            return JSVAL_TO_INT(v);
-        }
-
-        static unsigned SetFlags(JSObject* obj, unsigned flags) {
-            unsigned oldFlags = GetFlags(obj);
-            if (oldFlags != flags)
-                JS_SetReservedSlot(obj, sFlagsSlot, INT_TO_JSVAL(flags));
-            return oldFlags;
-        }
-
-    public:
-
-        AutoResolveFlag(JSContext *cx, JSObject* obj
-                        MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-            : mObj(cx, obj)
-            , mOldFlags(SetFlags(obj, GetFlags(obj) | CPOW_FLAG_RESOLVING))
-        {
-            MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        }
-
-        ~AutoResolveFlag() {
-            SetFlags(mObj, mOldFlags);
-        }
-
-        static JSBool IsSet(JSObject* obj) {
-            return GetFlags(obj) & CPOW_FLAG_RESOLVING;
-        }
-
-    };
-
-    class StatusMemberOwner
-    {
-        OperationStatus mStatus;
-    public:
-        StatusMemberOwner() : mStatus(JS_FALSE) {}
-        OperationStatus* StatusPtr() {
-            return &mStatus;
-        }
-    };
-
-    typedef AutoCheckOperationBase<StatusMemberOwner> ACOBase;
-
-    class AutoCheckOperation : public ACOBase
-    {
-        MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-    public:
-        AutoCheckOperation(JSContext* cx,
-                           ObjectWrapperParent* owp
-                           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-            : ACOBase(cx, owp)
-        {
-            MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        }
-    };
-
-}
-
-void
-ObjectWrapperParent::CheckOperation(JSContext* cx,
-                                    OperationStatus* status)
-{
-    NS_PRECONDITION(status->type() != OperationStatus::T__None,
-                    "Checking an uninitialized operation.");
-
-    switch (status->type()) {
-    case OperationStatus::TJSVariant:
-        {
-            Rooted<Value> thrown(cx);
-            if (jsval_from_JSVariant(cx, status->get_JSVariant(), thrown.address()))
-                JS_SetPendingException(cx, thrown);
-            *status = JS_FALSE;
-        }
-        break;
-    case OperationStatus::TJSBool:
-        if (!status->get_JSBool() && !JS_IsExceptionPending(cx)) {
-            NS_WARNING("CPOW operation failed without setting an exception.");
-        }
-        break;
-    default:
-        NS_NOTREACHED("Invalid or uninitialized OperationStatus type.");
-        break;
-    }
-}
-
-template <typename RType>
-static RType
-with_error(JSContext* cx,
-               RType rval,
-               const char* error = NULL)
-{
-    if (!JS_IsExceptionPending(cx))
-        JS_ReportError(cx, error ? error : "Unspecified CPOW error");
-    return rval;
-}
-
-const js::Class ObjectWrapperParent::sCPOW_JSClass = {
-      "CrossProcessObjectWrapper",
-      JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE |
-      JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(sNumSlots),
-      ObjectWrapperParent::CPOW_AddProperty,
-      ObjectWrapperParent::CPOW_DelProperty,
-      ObjectWrapperParent::CPOW_GetProperty,
-      ObjectWrapperParent::CPOW_SetProperty,
-      (JSEnumerateOp) ObjectWrapperParent::CPOW_NewEnumerate,
-      (JSResolveOp) ObjectWrapperParent::CPOW_NewResolve,
-      ObjectWrapperParent::CPOW_Convert,
-      ObjectWrapperParent::CPOW_Finalize,
-      nullptr, // checkAccess
-      ObjectWrapperParent::CPOW_Call,
-      ObjectWrapperParent::CPOW_HasInstance,
-      ObjectWrapperParent::CPOW_Construct,
-      nullptr // trace
-};
-
-void
-ObjectWrapperParent::ActorDestroy(ActorDestroyReason)
-{
-    if (mObj) {
-        JS_SetPrivate(mObj, NULL);
-        mObj = NULL;
-    }
-}
-
-ContextWrapperParent*
-ObjectWrapperParent::Manager()
-{
-    PContextWrapperParent* pcwp = PObjectWrapperParent::Manager();
-    return static_cast<ContextWrapperParent*>(pcwp);
-}
-
-JSObject*
-ObjectWrapperParent::GetJSObject(JSContext* cx) const
-{
-    if (!mObj) {
-        js::Class *clasp = const_cast<js::Class *>(&ObjectWrapperParent::sCPOW_JSClass);
-        mObj = JS_NewObject(cx, js::Jsvalify(clasp), NULL, NULL);
-        if (mObj) {
-            JS_SetPrivate(mObj, (void*)this);
-            JS_SetReservedSlot(mObj, sFlagsSlot, JSVAL_ZERO);
-        }
-    }
-    return mObj;
-}
-
-static ObjectWrapperParent*
-Unwrap(JSContext* cx, JSObject* objArg)
-{
-    Rooted<JSObject*> obj(cx, objArg), proto(cx);
-    while (js::GetObjectClass(obj) != &ObjectWrapperParent::sCPOW_JSClass) {
-        if (!js::GetObjectProto(cx, obj, &proto) || !proto)
-            return NULL;
-        obj = proto;
-    }
-
-    ObjectWrapperParent* self =
-        static_cast<ObjectWrapperParent*>(JS_GetPrivate(obj));
-
-    NS_ASSERTION(!self || self->GetJSObjectOrNull() == obj,
-                 "Wrapper and wrapped object disagree?");
-    
-    return self;
-}
-
-/*static*/ bool
-ObjectWrapperParent::jsval_to_JSVariant(JSContext* cx, jsval from,
-                                        JSVariant* to)
-{
-    switch (JS_TypeOfValue(cx, from)) {
-    case JSTYPE_VOID:
-        *to = void_t();
-        return true;
-    case JSTYPE_NULL:
-        if (from != JSVAL_NULL)
-            return false;
-        // fall through
-    case JSTYPE_FUNCTION:
-        // CPOWs can fool JS_TypeOfValue into returning JSTYPE_FUNCTION
-        // because they have a call hook, but CPOWs are really objects, so
-        // fall through to the JSTYPE_OBJECT case:
-    case JSTYPE_OBJECT:
-        {
-            PObjectWrapperParent* powp;
-            if (!JSObject_to_PObjectWrapperParent(cx, JSVAL_TO_OBJECT(from), &powp))
-                return with_error(cx, false, "Cannot pass parent-created object to child");
-            *to = powp;
-        }
-        return true;
-    case JSTYPE_STRING:
-        {
-            nsDependentJSString depStr;
-            if (!depStr.init(cx, from))
-                return false;
-            *to = depStr;
-        }
-        return true;
-    case JSTYPE_NUMBER:
-        if (JSVAL_IS_INT(from))
-            *to = JSVAL_TO_INT(from);
-        else if (JSVAL_IS_DOUBLE(from))
-            *to = JSVAL_TO_DOUBLE(from);
-        else return false;
-        return true;
-    case JSTYPE_BOOLEAN:
-        *to = !!JSVAL_TO_BOOLEAN(from);
-        return true;
-    default:
-        return with_error(cx, false, "Bad jsval type");
-    }
-}
-
-/*static*/ bool
-ObjectWrapperParent::jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
-                                          jsval* to)
-{
-    switch (from.type()) {
-    case JSVariant::Tvoid_t:
-        *to = JSVAL_VOID;
-        return true;
-    case JSVariant::TPObjectWrapperParent:
-        return jsval_from_PObjectWrapperParent(cx, from.get_PObjectWrapperParent(), to);
-    case JSVariant::TnsString:
-        {
-            JSString* str = JS_NewUCStringCopyZ(cx, from.get_nsString().BeginReading());
-            if (!str)
-                return false;
-            *to = STRING_TO_JSVAL(str);
-            return true;
-        }
-    case JSVariant::Tint:
-        *to = INT_TO_JSVAL(from.get_int());
-        return true;
-    case JSVariant::Tdouble:
-        *to = JS_NumberValue(from.get_double());
-        return true;
-    case JSVariant::Tbool:
-        *to = BOOLEAN_TO_JSVAL(from.get_bool());
-        return true;
-    default:
-        return false;
-    }
-}
-
-/*static*/ bool
-ObjectWrapperParent::boolean_from_JSVariant(JSContext* cx, const JSVariant& from,
-                                            JSBool* to)
-{
-    switch (from.type()) {
-    case JSVariant::Tvoid_t:
-        *to = false;
-        return true;
-    case JSVariant::TPObjectWrapperParent: {
-        Rooted<Value> v(cx);
-        if (!jsval_from_PObjectWrapperParent(cx, from.get_PObjectWrapperParent(), v.address()))
-            return false;
-        *to = JS::ToBoolean(v);
-        return true;
-    }
-    case JSVariant::TnsString:
-        {
-            JSString* str = JS_NewUCStringCopyZ(cx, from.get_nsString().BeginReading());
-            if (!str)
-                return false;
-            *to = JS::ToBoolean(JS::StringValue(str));
-            return true;
-        }
-    case JSVariant::Tint:
-        *to = from.get_int() != 0;
-        return true;
-    case JSVariant::Tdouble:
-        *to = JS::ToBoolean(JS::DoubleValue(from.get_double()));
-        return true;
-    case JSVariant::Tbool:
-        *to = from.get_bool();
-        return true;
-    default:
-        return false;
-    }
-}
-
-/*static*/ bool
-ObjectWrapperParent::
-JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from, PObjectWrapperParent** to)
-{
-    if (!from) {
-        *to = NULL;
-        return true;
-    }
-    ObjectWrapperParent* owp = Unwrap(cx, from);
-    if (!owp)
-        return false;
-    *to = owp;
-    return true;
-}
-
-/*static*/ bool
-ObjectWrapperParent::
-JSObject_from_PObjectWrapperParent(JSContext* cx,
-                                   const PObjectWrapperParent* from,
-                                   MutableHandleObject to)
-{
-    const ObjectWrapperParent* owp =
-        static_cast<const ObjectWrapperParent*>(from);
-    to.set(owp
-           ? owp->GetJSObject(cx)
-           : JSVAL_TO_OBJECT(JSVAL_NULL));
-    return true;
-}
-
-/*static*/ bool
-ObjectWrapperParent::
-jsval_from_PObjectWrapperParent(JSContext* cx,
-                                const PObjectWrapperParent* from,
-                                jsval* to)
-{
-    Rooted<JSObject*> obj(cx);
-    if (!JSObject_from_PObjectWrapperParent(cx, from, &obj))
-        return false;
-    *to = OBJECT_TO_JSVAL(obj);
-    return true;
-}
-    
-static bool
-jsid_from_int(JSContext* cx, int from, jsid* to)
-{
-    jsval v = INT_TO_JSVAL(from);
-    return JS_ValueToId(cx, v, to);
-}
-
-static bool
-jsid_from_nsString(JSContext* cx, const nsString& from, jsid* to)
-{
-    JSString* str = JS_NewUCStringCopyZ(cx, from.BeginReading());
-    if (!str)
-        return false;
-    return JS_ValueToId(cx, STRING_TO_JSVAL(str), to);
-}
-
-static bool
-jsval_to_nsString(JSContext* cx, jsid from, nsString* to)
-{
-    JSString* str;
-    const jschar* chars;
-    jsval idval;
-    if (JS_IdToValue(cx, from, &idval) &&
-        (str = JS_ValueToString(cx, idval)) &&
-        (chars = JS_GetStringCharsZ(cx, str))) {
-        *to = chars;
-        return true;
-    }
-    return false;
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, HandleObject obj, HandleId id,
-                                      MutableHandleValue vp)
-{
-    CPOW_LOG(("Calling CPOW_AddProperty (%s)...",
-              JSVAL_TO_CSTR(cx, id)));
-
-    ObjectWrapperParent* self = Unwrap(cx, obj);
-    if (!self)
-        return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_AddProperty");
-
-    if (AutoResolveFlag::IsSet(obj))
-        return JS_TRUE;
-
-    AutoCheckOperation aco(cx, self);
-
-    nsString in_id;
-
-    if (!jsval_to_nsString(cx, id, &in_id))
-        return JS_FALSE;
-
-    return (self->Manager()->RequestRunToCompletion() &&
-            self->CallAddProperty(in_id,
-                                  aco.StatusPtr()) &&
-            aco.Ok());
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, HandleObject obj, HandleId id,
-                                      MutableHandleValue vp)
-{
-    CPOW_LOG(("Calling CPOW_GetProperty (%s)...",
-              JSVAL_TO_CSTR(cx, id)));
-
-    ObjectWrapperParent* self = Unwrap(cx, obj);
-    if (!self)
-        return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_GetProperty");
-
-    AutoCheckOperation aco(cx, self);
-
-    nsString in_id;
-
-    if (!jsval_to_nsString(cx, id, &in_id))
-        return JS_FALSE;
-
-    JSVariant out_v;
-    
-    return (self->Manager()->RequestRunToCompletion() &&
-            self->CallGetProperty(in_id,
-                                  aco.StatusPtr(), &out_v) &&
-            aco.Ok() &&
-            self->jsval_from_JSVariant(cx, out_v, vp.address()));
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, HandleObject obj, HandleId id, 
-                                      JSBool strict, MutableHandleValue vp)
-{
-    CPOW_LOG(("Calling CPOW_SetProperty (%s)...",
-              JSVAL_TO_CSTR(cx, id)));
-
-    ObjectWrapperParent* self = Unwrap(cx, obj);
-    if (!self)
-        return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_SetProperty");
-
-    AutoCheckOperation aco(cx, self);
-
-    nsString in_id;
-    JSVariant in_v;
-
-    if (!jsval_to_nsString(cx, id, &in_id) ||
-        !self->jsval_to_JSVariant(cx, vp, &in_v))
-        return JS_FALSE;
-
-    JSVariant out_v;
-
-    return (self->Manager()->RequestRunToCompletion() &&
-            self->CallSetProperty(in_id, in_v,
-                                  aco.StatusPtr(), &out_v) &&
-            aco.Ok() &&
-            self->jsval_from_JSVariant(cx, out_v, vp.address()));
-}    
-    
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_DelProperty(JSContext *cx, HandleObject obj, HandleId id,
-                                      JSBool *succeeded)
-{
-    CPOW_LOG(("Calling CPOW_DelProperty (%s)...",
-              JSVAL_TO_CSTR(cx, id)));
-
-    ObjectWrapperParent* self = Unwrap(cx, obj);
-    if (!self)
-        return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_DelProperty");
-
-    AutoCheckOperation aco(cx, self);
-
-    nsString in_id;
-
-    if (!jsval_to_nsString(cx, id, &in_id))
-        return JS_FALSE;
-
-    JSVariant out_v;
-    
-    return (self->Manager()->RequestRunToCompletion() &&
-            self->CallDelProperty(in_id,
-                                  aco.StatusPtr(), &out_v) &&
-            aco.Ok() &&
-            boolean_from_JSVariant(cx, out_v, succeeded));
-}
-
-JSBool
-ObjectWrapperParent::NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp)
-{
-    AutoCheckOperation aco(cx, this);
-
-    JSVariant out_state;
-    int out_id;
-
-    return (CallNewEnumerateInit(aco.StatusPtr(), &out_state, &out_id) &&
-            aco.Ok() &&
-            jsval_from_JSVariant(cx, out_state, statep) &&
-            (!idp || jsid_from_int(cx, out_id, idp)));
-}
-
-JSBool
-ObjectWrapperParent::NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp)
-{
-    AutoCheckOperation aco(cx, this);
-
-    JSVariant in_state;
-
-    if (!jsval_to_JSVariant(cx, *statep, &in_state))
-        return JS_FALSE;
-
-    JSVariant out_state;
-    nsString out_id;
-
-    if (CallNewEnumerateNext(in_state,
-                             aco.StatusPtr(), &out_state, &out_id) &&
-        aco.Ok() &&
-        jsval_from_JSVariant(cx, out_state, statep) &&
-        jsid_from_nsString(cx, out_id, idp))
-    {
-        JSObject* obj = GetJSObject(cx);
-        AutoResolveFlag arf(cx, obj);
-        return JS_DefinePropertyById(cx, obj, *idp, JSVAL_VOID, NULL, NULL,
-                                     JSPROP_ENUMERATE);
-    }
-    return JS_FALSE;
-}
-
-JSBool
-ObjectWrapperParent::NewEnumerateDestroy(JSContext* cx, jsval state)
-{
-    AutoCheckOperation aco(cx, this);
-
-    JSVariant in_state;
-
-    if (!jsval_to_JSVariant(cx, state, &in_state))
-        return JS_FALSE;
-
-    return SendNewEnumerateDestroy(in_state);
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_NewEnumerate(JSContext *cx, HandleObject obj,
-                                       JSIterateOp enum_op, jsval *statep,
-                                       jsid *idp)
-{
-    CPOW_LOG(("Calling CPOW_NewEnumerate..."));
-
-    ObjectWrapperParent* self = Unwrap(cx, obj);
-    if (!self)
-        return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewEnumerate");
-
-    switch (enum_op) {
-    case JSENUMERATE_INIT:
-    case JSENUMERATE_INIT_ALL:
-        self->Manager()->RequestRunToCompletion();
-        return self->NewEnumerateInit(cx, statep, idp);
-    case JSENUMERATE_NEXT:
-        return self->NewEnumerateNext(cx, statep, idp);
-    case JSENUMERATE_DESTROY:
-        return self->NewEnumerateDestroy(cx, *statep);
-    }
-
-    NS_NOTREACHED("Unknown enum_op value in CPOW_NewEnumerate");
-    return JS_FALSE;
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_NewResolve(JSContext *cx, HandleObject obj, HandleId id,
-                                     unsigned flags, MutableHandleObject objp)
-{
-    CPOW_LOG(("Calling CPOW_NewResolve (%s)...",
-              JSVAL_TO_CSTR(cx, id)));
-
-    ObjectWrapperParent* self = Unwrap(cx, obj);
-    if (!self)
-        return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewResolve");
-
-    AutoCheckOperation aco(cx, self);
-
-    nsString in_id;
-
-    if (!jsval_to_nsString(cx, id, &in_id))
-        return JS_FALSE;
-
-    PObjectWrapperParent* out_pobj;
-
-    if (!self->Manager()->RequestRunToCompletion() ||
-        !self->CallNewResolve(in_id, flags,
-                              aco.StatusPtr(), &out_pobj) ||
-        !aco.Ok() ||
-        !JSObject_from_PObjectWrapperParent(cx, out_pobj, objp))
-        return JS_FALSE;
-
-    if (objp) {
-        AutoResolveFlag arf(cx, objp.get());
-        Rooted<JSObject*> obj2(cx, objp);
-        JS_DefinePropertyById(cx, obj2, id, JSVAL_VOID, NULL, NULL,
-                              JSPROP_ENUMERATE);
-    }
-    return JS_TRUE;
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_Convert(JSContext *cx, HandleObject obj, JSType type,
-                                  MutableHandleValue vp)
-{
-    CPOW_LOG(("Calling CPOW_Convert (to %s)...",
-              JS_GetTypeName(cx, type)));
-
-    ObjectWrapperParent* self = Unwrap(cx, obj);
-    if (!self)
-        return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Convert");
-
-    vp.set(OBJECT_TO_JSVAL(obj));
-
-    return JS_TRUE;
-}
-
-/*static*/ void
-ObjectWrapperParent::CPOW_Finalize(js::FreeOp* fop, JSObject* obj)
-{
-    CPOW_LOG(("Calling CPOW_Finalize..."));
-
-    MOZ_ASSERT(js::GetObjectClass(obj) == &ObjectWrapperParent::sCPOW_JSClass);
-    ObjectWrapperParent* self =
-        static_cast<ObjectWrapperParent*>(JS_GetPrivate(obj));
-    if (self) {
-        self->mObj = NULL;
-        unused << ObjectWrapperParent::Send__delete__(self);
-    }
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_Call(JSContext* cx, unsigned argc, jsval* vp)
-{
-    CPOW_LOG(("Calling CPOW_Call..."));
-
-    Rooted<JSObject*> thisobj(cx, JS_THIS_OBJECT(cx, vp));
-    if (!thisobj)
-        return JS_FALSE;
-
-    ObjectWrapperParent* function =
-        Unwrap(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
-    if (!function)
-        return with_error(cx, JS_FALSE, "Could not unwrap CPOW function");
-
-    AutoCheckOperation aco(cx, function);
-
-    ObjectWrapperParent* receiver = Unwrap(cx, thisobj);
-    if (!receiver) {
-        // Substitute child global for parent global object.
-        // TODO First make sure we're really replacing the global object?
-        ContextWrapperParent* manager =
-            static_cast<ContextWrapperParent*>(function->Manager());
-        receiver = manager->GetGlobalObjectWrapper();
-    }
-
-    InfallibleTArray<JSVariant> in_argv(argc);
-    jsval* argv = JS_ARGV(cx, vp);
-    for (unsigned i = 0; i < argc; i++)
-        if (!jsval_to_JSVariant(cx, argv[i], in_argv.AppendElement()))
-            return JS_FALSE;
-
-    JSVariant out_rval;
-
-    return (function->Manager()->RequestRunToCompletion() &&
-            function->CallCall(receiver, in_argv,
-                               aco.StatusPtr(), &out_rval) &&
-            aco.Ok() &&
-            jsval_from_JSVariant(cx, out_rval, vp));
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_Construct(JSContext* cx, unsigned argc, jsval* vp)
-{
-    CPOW_LOG(("Calling CPOW_Construct..."));
-    
-    ObjectWrapperParent* constructor = Unwrap(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
-    if (!constructor)
-        return with_error(cx, JS_FALSE, "Could not unwrap CPOW constructor function");
-
-    AutoCheckOperation aco(cx, constructor);
-
-    InfallibleTArray<JSVariant> in_argv(argc);
-    jsval* argv = JS_ARGV(cx, vp);
-    for (unsigned i = 0; i < argc; i++)
-        if (!jsval_to_JSVariant(cx, argv[i], in_argv.AppendElement()))
-            return JS_FALSE;
-
-    PObjectWrapperParent* out_powp;
-
-    return (constructor->Manager()->RequestRunToCompletion() &&
-            constructor->CallConstruct(in_argv, aco.StatusPtr(), &out_powp) &&
-            aco.Ok() &&
-            jsval_from_PObjectWrapperParent(cx, out_powp, vp));
-}
-
-/*static*/ JSBool
-ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, HandleObject obj, MutableHandleValue v,
-                                      JSBool *bp)
-{
-    CPOW_LOG(("Calling CPOW_HasInstance..."));
-
-    *bp = JS_FALSE;
-
-    ObjectWrapperParent* self = Unwrap(cx, obj);
-    if (!self)
-        return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_HasInstance");
-
-    AutoCheckOperation aco(cx, self);
-
-    JSVariant in_v;
-
-    if (!jsval_to_JSVariant(cx, v, &in_v))
-        return JS_FALSE;
-
-    return (self->Manager()->RequestRunToCompletion() &&
-            self->CallHasInstance(in_v,
-                                  aco.StatusPtr(), bp) &&
-            aco.Ok());
-}
deleted file mode 100644
--- a/js/ipc/ObjectWrapperParent.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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_ObjectWrapperParent_h
-#define mozilla_jsipc_ObjectWrapperParent_h
-
-#include "mozilla/jsipc/PObjectWrapperParent.h"
-#include "jsapi.h"
-#include "jsclass.h"
-#include "nsAutoJSValHolder.h"
-
-namespace mozilla {
-namespace jsipc {
-
-class ContextWrapperParent;
-
-class OperationChecker {
-public:
-    virtual void CheckOperation(JSContext* cx,
-                                OperationStatus* status) = 0;
-};
-
-class ObjectWrapperParent
-    : public PObjectWrapperParent
-    , public OperationChecker
-{
-public:
-
-    ObjectWrapperParent()
-        : mObj(NULL)
-    {}
-
-    JSObject* GetJSObject(JSContext* cx) const;
-
-    JSObject* GetJSObjectOrNull() const {
-        return mObj;
-    }
-
-    jsval GetJSVal(JSContext* cx) const {
-        return OBJECT_TO_JSVAL(GetJSObject(cx));
-    }
-
-    void CheckOperation(JSContext* cx,
-                        OperationStatus* status);
-
-    static const js::Class sCPOW_JSClass;
-
-protected:
-
-    void ActorDestroy(ActorDestroyReason why);
-
-    ContextWrapperParent* Manager();
-
-private:
-
-    mutable JSObject* mObj;
-
-    static JSBool
-    CPOW_AddProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-                     JS::MutableHandleValue vp);
-
-    static JSBool
-    CPOW_DelProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JSBool *succeeded);
-
-    static JSBool
-    CPOW_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-                     JS::MutableHandleValue vp);
-
-    static JSBool
-    CPOW_SetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JSBool strict,
-                     JS::MutableHandleValue vp);
-
-    JSBool NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp);
-    JSBool NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp);
-    JSBool NewEnumerateDestroy(JSContext* cx, jsval state);
-    static JSBool
-    CPOW_NewEnumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp enum_op,
-                      jsval *statep, jsid *idp);
-
-    static JSBool
-    CPOW_NewResolve(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned flags,
-                    JS::MutableHandleObject objp);
-
-    static JSBool
-    CPOW_Convert(JSContext *cx, JS::HandleObject obj, JSType type, JS::MutableHandleValue vp);
-
-    static void
-    CPOW_Finalize(js::FreeOp* fop, JSObject* obj);
-
-    static JSBool
-    CPOW_Call(JSContext* cx, unsigned argc, jsval* vp);
-
-    static JSBool
-    CPOW_Construct(JSContext *cx, unsigned argc, jsval *vp);
-
-    static JSBool
-    CPOW_HasInstance(JSContext *cx, JS::HandleObject obj, JS::MutableHandleValue vp, JSBool *bp);
-
-    static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to);
-    static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
-                                     jsval* to);
-    static bool boolean_from_JSVariant(JSContext* cx, const JSVariant& from,
-                                       JSBool* to);
-    static bool
-    JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from,
-                                     PObjectWrapperParent** to);
-    static bool
-    JSObject_from_PObjectWrapperParent(JSContext* cx,
-                                       const PObjectWrapperParent* from,
-                                       JS::MutableHandleObject to);
-    static bool
-    jsval_from_PObjectWrapperParent(JSContext* cx,
-                                    const PObjectWrapperParent* from,
-                                    jsval* to);
-};
-
-template <class StatusOwnerPolicy>
-class AutoCheckOperationBase
-    : public StatusOwnerPolicy
-{
-    JSContext* const mContext;
-    OperationChecker* const mChecker;
-
-protected:
-
-    AutoCheckOperationBase(JSContext* cx,
-                           OperationChecker* checker)
-        : mContext(cx)
-        , mChecker(checker)
-    {}
-
-    virtual ~AutoCheckOperationBase() {
-        mChecker->CheckOperation(mContext, StatusOwnerPolicy::StatusPtr());
-    }
-
-public:
-
-    bool Ok() {
-        return (StatusOwnerPolicy::StatusPtr()->type() == OperationStatus::TJSBool &&
-                StatusOwnerPolicy::StatusPtr()->get_JSBool());
-    }
-};
-
-}}
-
-#endif /* mozilla_jsipc_ObjectWrapperParent_h */
deleted file mode 100644
--- a/js/ipc/PContextWrapper.ipdl
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- 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/. */
-
-include protocol PTestShell;
-include protocol PObjectWrapper;
-
-namespace mozilla {
-namespace jsipc {
-
-rpc protocol PContextWrapper
-{
-    manager PTestShell;
-    manages PObjectWrapper;
-parent:
-    async __delete__();
-    async PObjectWrapper(bool makeGlobal);
-};
-
-}}
new file mode 100644
--- /dev/null
+++ b/js/ipc/PJavaScript.ipdl
@@ -0,0 +1,47 @@
+/* -*- 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 protocol PContent;
+include DOMTypes;
+include JavaScriptTypes;
+
+using mozilla::void_t;
+
+namespace mozilla {
+namespace jsipc {
+
+rpc protocol PJavaScript
+{
+    manager PContent;
+
+child:
+    // The parent process no longer holds any references to the child object.
+    async DropObject(uint64_t objId);
+
+    // These roughly map to the ProxyHandler hooks that CPOWs need.
+    urgent Has(uint64_t objId, nsString id) returns (ReturnStatus rs, bool has);
+    urgent HasOwn(uint64_t objId, nsString id) returns (ReturnStatus rs, bool has);
+    urgent Get(uint64_t objId, uint64_t receiverId, nsString id) returns (ReturnStatus rs, JSVariant result);
+    urgent Set(uint64_t objId, uint64_t receiverId, nsString id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
+    urgent Call(uint64_t objId, JSParam[] argv) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
+
+    urgent InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
+    urgent GetPropertyDescriptor(uint64_t objId, nsString id, uint32_t flags) returns (ReturnStatus rs, PPropertyDescriptor result);
+    urgent GetOwnPropertyDescriptor(uint64_t objId, nsString id, uint32_t flags) returns (ReturnStatus rs, PPropertyDescriptor result);
+    urgent GetOwnPropertyNames(uint64_t objId) returns (ReturnStatus rs, nsString[] names);
+    urgent Keys(uint64_t objId) returns (ReturnStatus rs, nsString[] names);
+    urgent ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
+    urgent ClassName(uint64_t objId) returns (nsString name);
+    urgent IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
+    urgent PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
+
+parent:
+    async __delete__();
+};
+
+}
+}
deleted file mode 100644
--- a/js/ipc/PObjectWrapper.ipdl
+++ /dev/null
@@ -1,92 +0,0 @@
-/* -*- 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/. */
-
-include protocol PContextWrapper;
-
-include "mozilla/jsipc/CPOWTypes.h";
-
-using mozilla::void_t;
-using JSType;
-using JSBool;
-
-namespace mozilla {
-namespace jsipc {
-
-union JSVariant {
-    void_t;
-    nullable PObjectWrapper;
-    nsString;
-    int;
-    double;
-    bool; // We'd like to use JSBool here, but IPC::ParamTraits would
-          // treat JSBool as int.
-};
-
-union OperationStatus {
-    JSBool;
-    JSVariant; // Exception thrown.
-};
-
-rpc protocol PObjectWrapper
-{
-    manager PContextWrapper;
-
-child:
-    __delete__(); // unroot
-
-    rpc AddProperty(nsString id)
-        returns (OperationStatus status);
-
-    rpc GetProperty(nsString id)
-        returns (OperationStatus status,
-                 JSVariant vp);
-
-    rpc SetProperty(nsString id,
-                    JSVariant v)
-        returns (OperationStatus status,
-                 JSVariant vp);
-
-    rpc DelProperty(nsString id)
-        returns (OperationStatus status,
-                 JSVariant vp);
-
-    rpc NewEnumerateInit()
-        returns (OperationStatus status,
-                 JSVariant statep,
-                 int idp);
-
-    rpc NewEnumerateNext(JSVariant in_state)
-        returns (OperationStatus status,
-                 JSVariant statep,
-                 nsString idp);
-
-    async NewEnumerateDestroy(JSVariant in_state);
-
-    rpc NewResolve(nsString id,
-                   int flags)
-        returns (OperationStatus status,
-                 nullable PObjectWrapper obj2);
-
-    rpc Convert(JSType type)
-        returns (OperationStatus status,
-                 JSVariant vp);
-
-    rpc Call(PObjectWrapper receiver,
-             JSVariant[] argv)
-        returns (OperationStatus status,
-                 JSVariant rval);
-
-    rpc Construct(JSVariant[] argv)
-        returns (OperationStatus status,
-                 nullable PObjectWrapper rval);
-
-    rpc HasInstance(JSVariant v)
-        returns (OperationStatus status,
-                 JSBool bp);
-};
-
-}}
--- a/js/ipc/ipdl.mk
+++ b/js/ipc/ipdl.mk
@@ -1,8 +1,8 @@
 # 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/.
 
 IPDLSRCS = \
-  PContextWrapper.ipdl \
-  PObjectWrapper.ipdl \
+  JavaScriptTypes.ipdlh \
+  PJavaScript.ipdl \
   $(NULL)
deleted file mode 100644
--- a/js/ipc/jar.mn
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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/.
-
-toolkit.jar:
-        content/global/cpow/test.xul (tests/adhoc/test.xul)
-        content/global/cpow/child.html (tests/adhoc/child.html)
--- a/js/ipc/moz.build
+++ b/js/ipc/moz.build
@@ -1,21 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 MODULE = 'js'
 
-EXPORTS.mozilla.jsipc += [
-    'CPOWTypes.h',
-    'ContextWrapperChild.h',
-    'ContextWrapperParent.h',
-    'ObjectWrapperChild.h',
-    'ObjectWrapperParent.h',
+CPP_SOURCES += [
+    'JavaScriptChild.cpp',
+    'JavaScriptParent.cpp',
+    'JavaScriptShared.cpp',
 ]
 
-CPP_SOURCES += [
-    'ObjectWrapperChild.cpp',
-    'ObjectWrapperParent.cpp',
-]
-
deleted file mode 100644
--- a/js/ipc/tests/adhoc/child.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<html>
-  <head>
-  </head>
-  <body>
-    <script>
-      window.foo = {
-        a: 42,
-        b: 37 * 73,
-        ctor: function(name, value) {
-          this[name] = value;
-        },
-        fakector: function(name, value) {
-          window[name] = "oyez";
-          this[name] = value;
-          return window;
-        },
-        f: function(x) {
-          document.body.appendChild(document.createElement("div")).innerHTML =
-            "called f(" + x + ")";
-          return x + Math.PI;
-        },
-        pitch: function(ball) {
-          throw ball;
-        }
-      };
-      window.foo.self = window.foo;
-    </script>
-    oyez
-  </body>
-</html>
deleted file mode 100644
--- a/js/ipc/tests/adhoc/test.xul
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        width="800" height="600" orient="vertical">
-
-  <script type="application/javascript">
-
-    var cpow_tests = {
-      resolve: function(obj, keys) {
-        alert("resolving");
-        keys = keys.split(" ");
-        for (var i = 0; i != keys.length; ++i)
-          alert("has " + keys[i] + "? " + (keys[i] in obj));
-        alert("done resolving");
-      },
-      iterate: function(obj) {
-        alert("iterating");
-        for (var k in obj)
-          alert("key: " + k);
-        alert("done iterating");
-      },
-      navigate: function(child) {
-        alert("navigating");
-        child.location = prompt("Where to?");
-        setTimeout(function() {
-          alert(child.location.href);
-        }, 2000);
-      },
-      construct: function(foo) {
-        alert(new foo.ctor("answer", 42).answer);
-        alert(new foo.fakector("answer", 42).answer);
-      },
-      indirect_eval: function(child) {
-        alert(child.eval("location.href"));
-        alert(new child.Function("x", "return x+1")(42));
-      },
-      funcalls: function(foo) {
-        var fn = foo.f;
-        alert(foo.f(2));
-        alert(fn.call.call(fn, foo, 3));
-      },
-      equality: function(child) {
-        var foo = child.foo,
-            self = foo.self;
-        alert("foo == self? " + (foo == self));
-        alert("foo === self? " + (foo === self));
-      },
-      exceptions: function(child) {
-        var ball = "ball";
-        try {
-          child.foo.pitch(ball);
-          alert("shouldn't reach this point");
-        } catch (x) {
-          alert("ball === x? " + (ball === x));
-        }
-      }
-    }
-
-    function getCPOW() {
-      if (!getCPOW.cpow) {
-        var page = document.getElementById("page"),
-            owner = page.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
-        getCPOW.cpow = owner.crossProcessObjectWrapper;
-        alert("got fresh CPOW");
-      }
-      return getCPOW.cpow;
-    }
-    
-    function test_cpow() {
-      var child = getCPOW();
-      cpow_tests.construct(child.foo);
-      cpow_tests.resolve(child.location, "href hostname");
-      cpow_tests.iterate(child.location);
-      cpow_tests.iterate(child.foo);
-      cpow_tests.funcalls(child.foo);
-      cpow_tests.navigate(child);
-      cpow_tests.equality(child);
-      cpow_tests.exceptions(child);
-      setTimeout(function() {
-        alert("going back");
-        child.history.back();
-      }, 3000);
-    }
-
-    function show_location() {
-      var child = getCPOW();
-      child.location += "#fragment";
-      alert(child.location.href);
-      alert(child.document.documentURI);
-    }
-  </script>
-
-  <toolbar id="controls">
-    <toolbarbutton onclick="test_cpow()" label="Run tests."/>
-    <toolbarbutton onclick="show_location()" label="Show location."/>
-  </toolbar>
-
-  <browser remote="true" width="200" height="200"
-           type="content"
-           src="child.html"
-           id="page" />
-
-</window>
deleted file mode 100644
--- a/js/ipc/tests/moz.build
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-MODULE = 'test_jsipc'
-
-# FIXME/bug 575918: out-of-process xpcshell is broken on OS X
-if CONFIG['OS_ARCH'] != 'Darwin':
-    XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
deleted file mode 100644
--- a/js/ipc/tests/unit/cpow_child.js
+++ /dev/null
@@ -1,66 +0,0 @@
-var data = {
-  answer: 42,
-  nested: { objects: { work: "yes they do" } },
-  arr: [
-    "zeroeth",
-    { foo: "bar" },
-    function() { return data },
-    { toString: function() { return "last" } }
-  ],
-  toString: function() {
-    return "CPOW";
-  }
-};
-
-var empty = function() {
-  this.try_to_delete = "just try";
-};
-empty.prototype = {
-  try_to_delete: "bwahaha",
-  inherited: "inherited",
-  method: function() {
-    return "called"
-  }
-};
-data.derived = new empty;
-
-(data.constructor = function(value) {
-  var self = this;
-  this.value = value;
-  this.check = function(that) {
-    do_check_eq(this.value, that.value);
-    do_check_eq(this, self);
-    do_check_eq(this, that);
-    do_check_false(this.isGlobal());
-  };
-}).prototype = {
-  isGlobal: function() {
-    return (function() { return this })() == this;
-  }
-};
-
-function A() {
-  this.a = A;
-  this.b = A;
-}
-function B() {
-  this.b = B;
-  this.c = B;
-}
-B.prototype = new A;
-
-function pitch(ball) {
-  throw ball;
-}
-
-get_set = {
-  get foo() { return 42; },
-  get foo_throws() { throw "BAM"; },
-  set one(val) { this.two = val + 1; }
-};
-
-function type(x) {
-  return typeof x;
-}
-
-function run_test() {}
deleted file mode 100644
--- a/js/ipc/tests/unit/test_cpow.js
+++ /dev/null
@@ -1,277 +0,0 @@
-function run_test() {
-  run_test_in_child("cpow_child.js", run_actual_tests);
-}
-
-function run_actual_tests() {
-  var obj = getChildGlobalObject();
-
-  test_properties(obj.data);
-  test_delete(obj.data);
-  test_toString(obj.data);
-  test_inheritance(obj.data.derived);
-  test_constructor(obj.data.constructor,
-                   obj.Function,
-                   obj.Object,
-                   obj.Date);
-  test_instanceof(obj.A, obj.B);
-  test_enumeration(obj.A, obj.B);
-  test_Array(obj.Array);
-  test_Function(obj.Function);
-  test_exceptions(obj.pitch, obj.Object);
-  test_generators(obj.Function);
-  test_Iterator(obj.data, obj.Iterator, obj.StopIteration);
-  test_getters_setters(obj.get_set, obj.Function);
-  test_forbidden_things(obj);
-
-  do_test_finished();
-}
-
-function test_properties(data) {
-  do_check_true("answer" in data);
-  do_check_false("cnefhasefho" in data.nested);
-
-  do_check_eq(data.answer, 42);
-  do_check_eq(data.nested.objects.work,
-              "yes they do");
-  do_check_eq(data.asodfijasdiofj, void(0));
-
-  do_check_eq(data.arr.length, 4);
-  do_check_eq(data.arr[4], void(0));
-  do_check_eq(data.arr[0], "zeroeth");
-  do_check_eq(data.arr[1].foo, "bar");
-
-  do_check_true(2 in data.arr);
-  do_check_eq(data.arr[2], data.arr[2]); // ensure reuse
-  do_check_true(data.arr[2]() === data);
-  do_check_eq(data.arr[2]().arr[0], "zeroeth");
-  do_check_true("call" in data.arr[2]);
-
-  do_check_eq(data.arr[3], "last");
-}
-
-function test_delete(data) {
-  do_check_eq(data.derived.try_to_delete, "just try");
-  do_check_true(delete data.derived.try_to_delete);
-  do_check_eq(data.derived.try_to_delete, "bwahaha");
-  do_check_true(delete data.derived.try_to_delete);
-  do_check_eq(data.derived.try_to_delete, "bwahaha");
-}
-
-function test_toString(data) {
-  do_check_eq(data.toString(), "CPOW");
-  do_check_eq(data + "asdf", "CPOWasdf");
-  do_check_eq(new String(data), "CPOW");
-}
-
-function test_inheritance(derived) {
-  do_check_true("inherited" in derived);
-  do_check_false(derived.hasOwnProperty("inherited"));
-  var base = derived.__proto__;
-  do_check_true(base.hasOwnProperty("inherited"));
-  do_check_eq(derived.inherited, "inherited");
-  do_check_eq(derived.method(), "called");
-  do_check_eq(base.method, derived.method);
-  do_check_true(base.method === derived.method);
-}
-
-function test_constructor(ctor,
-                          ChildFunction,
-                          ChildObject,
-                          ChildDate) {
-  var obj = new ctor(42);
-  obj.check(obj);
-
-  // Re-run test_inheritance, creating locally everything that
-  // test_inheritance expects to be created in the child process:
-  var empty = new ChildFunction(),
-      proto = new ChildObject();
-  proto.inherited = "inherited";
-  proto.method = new ChildFunction("return 'called'");
-  empty.prototype = proto;
-  test_inheritance(new empty);
-
-  var cd = new ChildDate,
-      tolerance_ms = 20000; // Ridiculously large to accommodate gcZeal delays.
-  do_check_eq(Math.max(Math.abs(cd.getTime() - new Date),
-                       tolerance_ms),
-              tolerance_ms);
-  do_check_true(cd instanceof ChildDate);
-}
-
-function test_enumeration(A, B) {
-  function check(obj, nk, s) {
-    var keys = [];
-    for (var k in obj)
-      keys[keys.length] = k;
-    do_check_eq(keys.length, nk);
-    do_check_eq(keys.sort().join("~"), s);
-  }
-  check(new B, 3, "a~b~c");
-  check(B.prototype, 2, "a~b");
-  B.prototype = A.prototype;
-  A.prototype = new B;
-  check(new A, 3, "a~b~c");
-  check(new B, 2, "b~c");
-
-  // Put things back the way they were, mostly:
-  A.prototype = B.prototype;
-  B.prototype = new A;
-}
-
-function test_instanceof(A, B) {
-  var a = new A, b = new B;
-  do_check_true(a instanceof A);
-  do_check_false(a instanceof B);
-  do_check_true(b instanceof A);
-  do_check_true(b instanceof B);
-}
-
-function test_Array(ChildArray) {
-  do_check_true(!!ChildArray);
-  var arr = new ChildArray(1, new ChildArray(2, 3), 4);
-  do_check_eq(arr.length, 3);
-  do_check_eq(arr.slice(1).shift()[1], 3);
-  arr[2] = arr[1];
-  do_check_eq(arr.pop()[0], 2);
-}
-
-function test_Function(ChildFunction) {
-  var succ = new ChildFunction("x", "return x + 1");
-  do_check_eq(succ(succ(3)), 5);
-  do_check_eq(succ + "", "" + new Function("x", "return x + 1"));
-}
-
-function test_exceptions(pitch, ChildObject) {
-  try {
-    throw "parent-only";
-  } catch (x) {
-    do_check_eq(x, "parent-only");
-  }
-  var ball = new ChildObject(),
-      thrown = false;
-  ball.sport = "baseball";
-  try {
-    pitch(ball);
-    do_throw("Should have thrown.");
-  } catch (x) {
-    thrown = true;
-    do_check_eq(x.sport, "baseball");
-    do_check_eq(x, ball);
-    do_check_true(x === ball);
-  }
-  do_check_true(thrown);
-}
-
-function test_generators(ChildFunction) {
-  // Run the test with own Function just to keep sane:
-  if (ChildFunction != Function)
-    test_generators(Function);
-
-  var count = 0, sum = 0,
-      genFn = new ChildFunction("for(var i = 1; i < 4; i++) yield i");
-
-  var gen = genFn();
-  do try { sum += gen.next(); }
-     catch (x) { break; }
-  while ((count += 1));
-  do_check_eq(count, 3);
-  do_check_eq(sum, 6);
-
-  try {
-    for (var n in genFn()) {
-      count += 1;
-      sum += n;
-    }
-  } catch (x) {}
-  do_check_eq(count, 6);
-  do_check_eq(sum, 12);
-}
-
-function test_Iterator(data, ChildIterator, ChildStopIteration) {
-  do_check_true(data && ChildIterator && true);
-  var copy = {},
-      thrown = null;
-  try {
-    for (var kv in ChildIterator(data)) {
-      do_check_true(kv[0] in data);
-      do_check_eq(data[kv[0]], kv[1]);
-      copy[kv[0]] = kv[1];
-    }
-    // XXX I shouldn't have to be catching this, should I?
-  } catch (x) { thrown = x; }
-  do_check_true(thrown != null);
-  do_check_true(thrown instanceof ChildStopIteration);
-  do_check_eq(copy + "", "CPOW");
-}
-
-function test_getters_setters(get_set, ChildFunction) {
-  do_check_eq(get_set.foo, 42);
-  var thrown = null;
-  try { get_set.bar = get_set.foo_throws; }
-  catch (x) { thrown = x; }
-  do_check_true(thrown != null);
-  do_check_eq(thrown, "BAM");
-  do_check_false("bar" in get_set);
-
-  get_set.two = 2222;
-  get_set.one = 1;
-  do_check_eq(get_set.two, 2);
-
-  var getter = new ChildFunction("return 'you got me'");
-  get_set.__defineGetter__("defined_getter", getter);
-  do_check_eq(get_set.defined_getter, "you got me");
-  do_check_eq(get_set.__lookupGetter__("defined_getter"),
-              getter);
-
-  var setter = new ChildFunction("val", "this.side_effect = val");
-  get_set.__defineSetter__("defined_setter", setter);
-  get_set.side_effect = "can't touch this";
-  get_set.defined_setter = "you set me";
-  do_check_eq(get_set.side_effect, "you set me");
-  do_check_eq(get_set.__lookupSetter__("defined_setter"),
-              setter);
-}
-
-function test_forbidden_things(child) {
-  var x_count = 0;
-
-  do_check_eq(child.type(42), "number");
-
-  try {
-    child.type(function(){});
-    do_throw("Should not have been able to pass a parent-created " +
-             "function to the child");
-  } catch (x) {
-    print(x);
-    x_count += 1;
-  }
-
-  try {
-    child.type({});
-    do_throw("Should not have been able to pass a parent-created " +
-             "object to the child");
-  } catch (x) {
-    print(x);
-    x_count += 1;
-  }
-
-  try {
-    child.type.prop = {};
-    do_throw("Should not have been able to set a property of a child " +
-             "object to a parent-created object value");
-  } catch (x) {
-    print(x);
-    x_count += 1;
-  }
-
-  try {
-    child.type.prop = function(){};
-    do_throw("Should not have been able to set a property of a child " +
-             "object to a parent-created function value");
-  } catch (x) {
-    print(x);
-    x_count += 1;
-  }
-
-  do_check_eq(x_count, 4);
-}
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -755,28 +755,30 @@ js::gc::MarkRuntime(JSTracer *trc, bool 
          * which have been entered. Globals aren't nursery allocated so there's
          * no need to do this for minor GCs.
          */
         for (CompartmentsIter c(rt); !c.done(); c.next())
             c->mark(trc);
     }
 
     /* The embedding can register additional roots here. */
-    if (JSTraceDataOp op = rt->gcBlackRootsTraceOp)
-        (*op)(trc, rt->gcBlackRootsData);
+    for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) {
+        const JSRuntime::ExtraTracer &e = rt->gcBlackRootTracers[i];
+        (*e.op)(trc, e.data);
+    }
 
     /* During GC, we don't mark gray roots at this stage. */
-    if (JSTraceDataOp op = rt->gcGrayRootsTraceOp) {
+    if (JSTraceDataOp op = rt->gcGrayRootTracer.op) {
         if (!IS_GC_MARKING_TRACER(trc))
-            (*op)(trc, rt->gcGrayRootsData);
+            (*op)(trc, rt->gcGrayRootTracer.data);
     }
 }
 
 void
 js::gc::BufferGrayRoots(GCMarker *gcmarker)
 {
     JSRuntime *rt = gcmarker->runtime;
-    if (JSTraceDataOp op = rt->gcGrayRootsTraceOp) {
+    if (JSTraceDataOp op = rt->gcGrayRootTracer.op) {
         gcmarker->startBufferingGrayRoots();
-        (*op)(gcmarker, rt->gcGrayRootsData);
+        (*op)(gcmarker, rt->gcGrayRootTracer.data);
         gcmarker->endBufferingGrayRoots();
     }
 }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -811,20 +811,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     gcValidate(true),
     gcFullCompartmentChecks(false),
     gcCallback(NULL),
     gcSliceCallback(NULL),
     gcFinalizeCallback(NULL),
     analysisPurgeCallback(NULL),
     analysisPurgeTriggerBytes(0),
     gcMallocBytes(0),
-    gcBlackRootsTraceOp(NULL),
-    gcBlackRootsData(NULL),
-    gcGrayRootsTraceOp(NULL),
-    gcGrayRootsData(NULL),
     autoGCRooters(NULL),
     scriptAndCountsVector(NULL),
     NaNValue(UndefinedValue()),
     negativeInfinityValue(UndefinedValue()),
     positiveInfinityValue(UndefinedValue()),
     emptyString(NULL),
     sourceHook(NULL),
     debugMode(false),
@@ -2287,22 +2283,34 @@ JS_RemoveScriptRootRT(JSRuntime *rt, JSS
     js_RemoveRoot(rt, (void *)rp);
 }
 
 JS_NEVER_INLINE JS_PUBLIC_API(void)
 JS_AnchorPtr(void *p)
 {
 }
 
-JS_PUBLIC_API(void)
-JS_SetExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
+JS_PUBLIC_API(JSBool)
+JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
 {
     AssertHeapIsIdle(rt);
-    rt->gcBlackRootsTraceOp = traceOp;
-    rt->gcBlackRootsData = data;
+    return !!rt->gcBlackRootTracers.append(JSRuntime::ExtraTracer(traceOp, data));
+}
+
+JS_PUBLIC_API(void)
+JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
+{
+    AssertHeapIsIdle(rt);
+    for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) {
+        JSRuntime::ExtraTracer *e = &rt->gcBlackRootTracers[i];
+        if (e->op == traceOp && e->data == data) {
+            rt->gcBlackRootTracers.erase(e);
+            break;
+        }
+    }
 }
 
 JS_PUBLIC_API(void)
 JS_CallValueTracer(JSTracer *trc, Value *valuep, const char *name)
 {
     MarkValueUnbarriered(trc, valuep, name);
 }
 
@@ -7152,8 +7160,20 @@ JS_PUBLIC_API(JSObject *)
 JS_GetScriptedGlobal(JSContext *cx)
 {
     ScriptFrameIter i(cx);
     if (i.done())
         return cx->global();
     return &i.scopeChain()->global();
 }
 
+JS_PUBLIC_API(JSBool)
+JS_PreventExtensions(JSContext *cx, JS::HandleObject obj)
+{
+    JSBool extensible;
+    if (!JS_IsExtensible(cx, obj, &extensible))
+        return JS_TRUE;
+    if (extensible)
+        return JS_TRUE;
+
+    return JSObject::preventExtensions(cx, obj);
+}
+
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2368,18 +2368,22 @@ JS_AnchorPtr(void *p);
 
 /*
  * Register externally maintained GC roots.
  *
  * traceOp: the trace operation. For each root the implementation should call
  *          JS_CallTracer whenever the root contains a traceable thing.
  * data:    the data argument to pass to each invocation of traceOp.
  */
+extern JS_PUBLIC_API(JSBool)
+JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
+
+/* Undo a call to JS_AddExtraGCRootsTracer. */
 extern JS_PUBLIC_API(void)
-JS_SetExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
+JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
 
 /*
  * JS_CallTracer API and related macros for implementors of JSTraceOp, to
  * enumerate all references to traceable things reachable via a property or
  * other strong ref identified for debugging purposes by name or index or
  * a naming callback.
  *
  * See the JSTraceOp typedef.
@@ -3212,16 +3216,19 @@ extern JS_PUBLIC_API(JSBool)
 JS_DeepFreezeObject(JSContext *cx, JSObject *obj);
 
 /*
  * Freezes an object; see ES5's Object.freeze(obj) method.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_FreezeObject(JSContext *cx, JSObject *obj);
 
+extern JS_PUBLIC_API(JSBool)
+JS_PreventExtensions(JSContext *cx, JS::HandleObject obj);
+
 extern JS_PUBLIC_API(JSObject *)
 JS_New(JSContext *cx, JSObject *ctor, unsigned argc, jsval *argv);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
                 JSObject *proto, unsigned attrs);
 
 extern JS_PUBLIC_API(JSBool)
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1160,26 +1160,37 @@ struct JSRuntime : public JS::shadow::Ru
     void setNeedsBarrier(bool needs) {
         needsBarrier_ = needs;
     }
 
     bool needsBarrier() const {
         return needsBarrier_;
     }
 
+    struct ExtraTracer {
+        JSTraceDataOp op;
+        void *data;
+
+        ExtraTracer()
+          : op(NULL), data(NULL)
+        {}
+        ExtraTracer(JSTraceDataOp op, void *data)
+          : op(op), data(data)
+        {}
+    };
+
     /*
      * The trace operations to trace embedding-specific GC roots. One is for
      * tracing through black roots and the other is for tracing through gray
      * roots. The black/gray distinction is only relevant to the cycle
      * collector.
      */
-    JSTraceDataOp       gcBlackRootsTraceOp;
-    void                *gcBlackRootsData;
-    JSTraceDataOp       gcGrayRootsTraceOp;
-    void                *gcGrayRootsData;
+    typedef js::Vector<ExtraTracer, 4, js::SystemAllocPolicy> ExtraTracerVector;
+    ExtraTracerVector   gcBlackRootTracers;
+    ExtraTracer         gcGrayRootTracer;
 
     /* Stack of thread-stack-allocated GC roots. */
     js::AutoGCRooter   *autoGCRooters;
 
     /*
      * The GC can only safely decommit memory when the page size of the
      * running process matches the compiled arena size.
      */
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -47,18 +47,18 @@ JS_FRIEND_API(void)
 JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook)
 {
     rt->sourceHook = hook;
 }
 
 JS_FRIEND_API(void)
 JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
 {
-    rt->gcGrayRootsTraceOp = traceOp;
-    rt->gcGrayRootsData = data;
+    rt->gcGrayRootTracer.op = traceOp;
+    rt->gcGrayRootTracer.data = data;
 }
 
 JS_FRIEND_API(JSString *)
 JS_GetAnonymousString(JSRuntime *rt)
 {
     JS_ASSERT(rt->hasContexts());
     return rt->atomState.anonymous;
 }
@@ -297,16 +297,28 @@ JS_DefineFunctionsWithHelp(JSContext *cx
             if (!DefineHelpProperty(cx, fun, "help", fs->help))
                 return false;
         }
     }
 
     return true;
 }
 
+JS_FRIEND_API(bool)
+js_ObjectClassIs(JSContext *cx, HandleObject obj, ESClassValue classValue)
+{
+    return ObjectClassIs(obj, classValue, cx);
+}
+
+JS_FRIEND_API(const char *)
+js_ObjectClassName(JSContext *cx, HandleObject obj)
+{
+    return JSObject::className(cx, obj);
+}
+
 AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment
                                              MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : cx(cx), oldCompartment(cx->compartment())
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     cx->setCompartment(newCompartment);
 }
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -128,16 +128,22 @@ JS_BasicObjectToString(JSContext *cx, JS
 
 extern JS_FRIEND_API(JSBool)
 js_GetterOnlyPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JSBool strict,
                           JS::MutableHandleValue vp);
 
 JS_FRIEND_API(void)
 js_ReportOverRecursed(JSContext *maybecx);
 
+JS_FRIEND_API(bool)
+js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
+
+JS_FRIEND_API(const char *)
+js_ObjectClassName(JSContext *cx, JS::HandleObject obj);
+
 #ifdef DEBUG
 
 /*
  * Routines to print out values during debugging.  These are FRIEND_API to help
  * the debugger find them and to support temporarily hacking js_Dump* calls
  * into other code.
  */
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2912,18 +2912,18 @@ MarkGrayReferences(JSRuntime *rt)
         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_MARK);
         gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_SWEEP_MARK_GRAY);
         gcmarker->setMarkColorGray();
         if (gcmarker->hasBufferedGrayRoots()) {
             for (ZoneIterT zone(rt); !zone.done(); zone.next())
                 gcmarker->markBufferedGrayRoots(zone);
         } else {
             JS_ASSERT(!rt->gcIsIncremental);
-            if (JSTraceDataOp op = rt->gcGrayRootsTraceOp)
-                (*op)(gcmarker, rt->gcGrayRootsData);
+            if (JSTraceDataOp op = rt->gcGrayRootTracer.op)
+                (*op)(gcmarker, rt->gcGrayRootTracer.data);
         }
         SliceBudget budget;
         gcmarker->drainMarkStack(budget);
     }
 
     MarkWeakReferences<CompartmentIterT>(rt, gcstats::PHASE_SWEEP_MARK_GRAY_WEAK);
 
     JS_ASSERT(gcmarker->isDrained());
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -675,29 +675,16 @@ SendCommand(JSContext* cx,
         JS_ReportError(cx, "Couldn't send command!");
         return false;
     }
 
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
-static JSBool
-GetChildGlobalObject(JSContext* cx,
-                     unsigned,
-                     jsval* vp)
-{
-    JS::Rooted<JSObject*> global(cx);
-    if (XRE_GetChildGlobalObject(cx, global.address())) {
-        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(global));
-        return true;
-    }
-    return false;
-}
-
 /*
  * JSContext option name to flag map. The option names are in alphabetical
  * order for better reporting.
  */
 static const struct JSOption {
     const char  *name;
     uint32_t    flag;
 } js_options[] = {
@@ -914,17 +901,16 @@ static const JSFunctionSpec glob_functio
     JS_FS("gczeal",          GCZeal,         1,0),
 #endif
     JS_FS("options",         Options,        0,0),
     JS_FN("parent",          Parent,         1,0),
 #ifdef DEBUG
     JS_FS("dumpHeap",        DumpHeap,       5,0),
 #endif
     JS_FS("sendCommand",     SendCommand,    1,0),
-    JS_FS("getChildGlobalObject", GetChildGlobalObject, 0,0),
     JS_FS("atob",            Atob,           1,0),
     JS_FS("btoa",            Btoa,           1,0),
     JS_FS("Blob",            Blob,           2,JSFUN_CONSTRUCTOR),
     JS_FS("File",            File,           2,JSFUN_CONSTRUCTOR),
     JS_FS_END
 };
 
 JSClass global_class = {
--- a/js/xpconnect/src/Makefile.in
+++ b/js/xpconnect/src/Makefile.in
@@ -27,18 +27,21 @@ LOCAL_INCLUDES = \
 		-I$(topsrcdir)/content/events/src \
 		-I$(topsrcdir)/content/html/content/src \
 		-I$(topsrcdir)/content/html/document/src \
 		-I$(topsrcdir)/content/svg/content/src \
 		-I$(topsrcdir)/layout/style \
 		-I$(topsrcdir)/layout/base \
 		-I$(topsrcdir)/dom/base \
 		-I$(topsrcdir)/xpcom/ds \
+		-I$(topsrcdir)/js/ipc \
 		$(NULL)
 
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+
 SHARED_LIBRARY_LIBS = \
   ../loader/$(LIB_PREFIX)jsloader_s.$(LIB_SUFFIX) \
   ../wrappers/$(LIB_PREFIX)xpcwrappers_s.$(LIB_SUFFIX) \
   $(NULL)
 
 EXTRA_MDDEPEND_FILES = dom_qsgen.pp dictionary_helper_gen.pp event_impl_gen.pp
 
 include $(topsrcdir)/config/rules.mk
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -18,16 +18,17 @@
 #include "AccessCheck.h"
 #include "nsJSUtils.h"
 #include "WrapperFactory.h"
 
 #include "nsWrapperCacheInlines.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "JavaScriptParent.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/PrimitiveConversions.h"
 
 using namespace xpc;
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace JS;
@@ -57,16 +58,28 @@ XPCConvert::IsMethodReflectable(const XP
         // Reflected methods can't use native types. All native types end up
         // getting tagged as void*, so this check is easy.
         if (type.TagPart() == nsXPTType::T_VOID)
             return false;
     }
     return true;
 }
 
+static JSObject*
+UnwrapNativeCPOW(nsISupports* wrapper)
+{
+    nsCOMPtr<nsIXPConnectWrappedJS> underware = do_QueryInterface(wrapper);
+    if (underware) {
+        JSObject* mainObj = underware->GetJSObject();
+        if (mainObj && mozilla::jsipc::JavaScriptParent::IsCPOW(mainObj))
+            return mainObj;
+    }
+    return nullptr;
+}
+
 /***************************************************************************/
 
 // static
 JSBool
 XPCConvert::GetISupportsFromJSObject(JSObject* obj, nsISupports** iface)
 {
     JSClass* jsclass = js::GetObjectJSClass(obj);
     NS_ASSERTION(jsclass, "obj has no class");
@@ -788,18 +801,17 @@ XPCConvert::NativeInterface2JSObject(jsv
                                      nsresult* pErr)
 {
     NS_ASSERTION(!Interface || iid,
                  "Need the iid if you pass in an XPCNativeInterface cache.");
 
     *d = JSVAL_NULL;
     if (dest)
         *dest = nullptr;
-    nsISupports *src = aHelper.Object();
-    if (!src)
+    if (!aHelper.Object())
         return true;
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
 
     // We used to have code here that unwrapped and simply exposed the
     // underlying JSObject. That caused anomolies when JSComponents were
     // accessed from other JS code - they didn't act like other xpconnect
     // wrapped components. So, instead, we create "double wrapped" objects
@@ -834,16 +846,27 @@ XPCConvert::NativeInterface2JSObject(jsv
                 return false;
 
             return CreateHolderIfNeeded(flat, d, dest);
         }
     } else {
         flat = nullptr;
     }
 
+    // Don't double wrap CPOWs. This is a temporary measure for compatibility
+    // with objects that don't provide necessary QIs (such as objects under
+    // the new DOM bindings). We expect the other side of the CPOW to have
+    // the appropriate wrappers in place.
+    if (JSObject *cpow = UnwrapNativeCPOW(aHelper.Object())) {
+        if (!JS_WrapObject(cx, &cpow))
+            return false;
+        *d = OBJECT_TO_JSVAL(cpow);
+        return true;
+    }
+
     // We can't simply construct a slim wrapper. Go ahead and create an
     // XPCWrappedNative for this object. At this point, |flat| could be
     // non-null, meaning that either we already have a wrapped native from
     // the cache (which might need to be QI'd to the new interface) or that
     // we found a slim wrapper that we'll have to morph.
     AutoMarkingNativeInterfacePtr iface(cx);
     if (iid) {
         if (Interface)
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -6,16 +6,17 @@
 
 /* An xpcom implementation of the JavaScript nsIID and nsCID objects. */
 
 #include "xpcprivate.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Attributes.h"
 #include "XPCWrapper.h"
+#include "JavaScriptParent.h"
 
 using namespace mozilla::dom;
 using namespace JS;
 
 /***************************************************************************/
 // nsJSID
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsJSID, nsIJSID)
@@ -471,90 +472,100 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNa
  *
  * This static method handles both complexities, returning either an XPCWN, a
  * DOM object, or null. The object may well be cross-compartment from |cx|.
  */
 static JSObject *
 FindObjectForHasInstance(JSContext *cx, HandleObject objArg)
 {
     RootedObject obj(cx, objArg), proto(cx);
-    while (obj && !IS_WN_REFLECTOR(obj) && !IsDOMObject(obj)) {
+
+    while (obj && !IS_WN_REFLECTOR(obj) &&
+           !IsDOMObject(obj) && !mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
+    {
         if (js::IsWrapper(obj)) {
             obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
             continue;
         }
         if (!js::GetObjectProto(cx, obj, &proto))
             return nullptr;
         obj = proto;
     }
     return obj;
 }
 
+nsresult
+xpc::HasInstance(JSContext *cx, HandleObject objArg, const nsID *iid, bool *bp)
+{
+    *bp = false;
+
+    RootedObject obj(cx, FindObjectForHasInstance(cx, objArg));
+    if (!obj)
+        return NS_OK;
+
+    if (IsDOMObject(obj)) {
+        // Not all DOM objects implement nsISupports. But if they don't,
+        // there's nothing to do in this HasInstance hook.
+        nsISupports *identity = UnwrapDOMObjectToISupports(obj);
+        if (!identity)
+            return NS_OK;;
+        nsCOMPtr<nsISupports> supp;
+        identity->QueryInterface(*iid, getter_AddRefs(supp));
+        *bp = supp;
+        return NS_OK;
+    }
+
+    if (mozilla::jsipc::JavaScriptParent::IsCPOW(obj))
+        return mozilla::jsipc::JavaScriptParent::InstanceOf(obj, iid, bp);
+
+    MOZ_ASSERT(IS_WN_REFLECTOR(obj));
+    XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
+    if (!other_wrapper)
+        return NS_OK;
+
+    // We'll trust the interface set of the wrapper if this is known
+    // to be an interface that the objects *expects* to be able to
+    // handle.
+    if (other_wrapper->HasInterfaceNoQI(*iid)) {
+        *bp = true;
+        return NS_OK;
+    }
+
+    // Otherwise, we'll end up Querying the native object to be sure.
+    XPCCallContext ccx(JS_CALLER, cx);
+
+    AutoMarkingNativeInterfacePtr iface(ccx);
+    iface = XPCNativeInterface::GetNewOrUsed(iid);
+
+    nsresult findResult = NS_OK;
+    if (iface && other_wrapper->FindTearOff(iface, false, &findResult))
+        *bp = true;
+    if (NS_FAILED(findResult) && findResult != NS_ERROR_NO_INTERFACE)
+        return findResult;
+
+    return NS_OK;
+}
 
 /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
 NS_IMETHODIMP
 nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
                      JSContext * cx, JSObject * /* unused */,
                      const jsval &val, bool *bp, bool *_retval)
 {
     *bp = false;
-    nsresult rv = NS_OK;
 
-    if (!JSVAL_IS_PRIMITIVE(val)) {
-        // we have a JSObject
-        RootedObject obj(cx, JSVAL_TO_OBJECT(val));
-
-        NS_ASSERTION(obj, "when is an object not an object?");
-
-        // is this really a native xpcom object with a wrapper?
-        const nsIID* iid;
-        mInfo->GetIIDShared(&iid);
-
-        obj = FindObjectForHasInstance(cx, obj);
-        if (!obj)
-            return NS_OK;
+    if (JSVAL_IS_PRIMITIVE(val))
+        return NS_OK;
 
-        if (IsDOMObject(obj)) {
-            // Not all DOM objects implement nsISupports. But if they don't,
-            // there's nothing to do in this HasInstance hook.
-            nsISupports *identity = UnwrapDOMObjectToISupports(obj);
-            if (!identity)
-                return NS_OK;
-            nsCOMPtr<nsISupports> supp;
-            identity->QueryInterface(*iid, getter_AddRefs(supp));
-            *bp = supp;
-            return NS_OK;
-        }
-
-        MOZ_ASSERT(IS_WN_REFLECTOR(obj));
-        XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
-        if (!other_wrapper)
-            return NS_OK;
+    // we have a JSObject
+    RootedObject obj(cx, JSVAL_TO_OBJECT(val));
 
-        // We'll trust the interface set of the wrapper if this is known
-        // to be an interface that the objects *expects* to be able to
-        // handle.
-        if (other_wrapper->HasInterfaceNoQI(*iid)) {
-            *bp = true;
-            return NS_OK;
-        }
-
-        // Otherwise, we'll end up Querying the native object to be sure.
-        XPCCallContext ccx(JS_CALLER, cx);
-
-        AutoMarkingNativeInterfacePtr iface(ccx);
-        iface = XPCNativeInterface::GetNewOrUsed(iid);
-
-        nsresult findResult = NS_OK;
-        if (iface && other_wrapper->FindTearOff(iface, false, &findResult))
-            *bp = true;
-        if (NS_FAILED(findResult) && findResult != NS_ERROR_NO_INTERFACE)
-            rv = findResult;
-    }
-    return rv;
+    const nsIID* iid;
+    mInfo->GetIIDShared(&iid);
+    return xpc::HasInstance(cx, obj, iid, bp);
 }
 
 /* string canCreateWrapper (in nsIIDPtr iid); */
 NS_IMETHODIMP
 nsJSIID::CanCreateWrapper(const nsIID * iid, char **_retval)
 {
     // We let anyone do this...
     *_retval = xpc_CloneAllAccess();
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -11,16 +11,17 @@
 #include "nsArrayEnumerator.h"
 #include "nsWrapperCache.h"
 #include "XPCWrapper.h"
 #include "AccessCheck.h"
 #include "nsJSUtils.h"
 #include "mozilla/Attributes.h"
 
 #include "jsapi.h"
+#include "jsfriendapi.h"
 
 using namespace xpc;
 using namespace JS;
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
 
 // the value of this variable is never used - we use its address as a sentinel
 static uint32_t zero_methods_descriptor;
@@ -1644,18 +1645,47 @@ pre_call_clean_up:
 const char*
 nsXPCWrappedJSClass::GetInterfaceName()
 {
     if (!mName)
         mInfo->GetName(&mName);
     return mName;
 }
 
+static void
+FinalizeStub(JSFreeOp *fop, JSObject *obj)
+{
+}
+
+static JSClass XPCOutParamClass = {
+    "XPCOutParam",
+    0,
+    JS_PropertyStub,
+    JS_DeletePropertyStub,
+    JS_PropertyStub,
+    JS_StrictPropertyStub,
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    FinalizeStub,
+    NULL,   /* checkAccess */
+    NULL,   /* call */
+    NULL,   /* hasInstance */
+    NULL,   /* construct */
+    NULL    /* trace */
+};
+
+bool
+xpc::IsOutObject(JSContext* cx, JSObject* obj)
+{
+    return js::GetObjectJSClass(obj) == &XPCOutParamClass;
+}
+
 JSObject*
-nsXPCWrappedJSClass::NewOutObject(JSContext* cx, JSObject* scope)
+xpc::NewOutObject(JSContext* cx, JSObject* scope)
 {
     return JS_NewObject(cx, nullptr, nullptr, JS_GetGlobalForObject(cx, scope));
 }
 
 
 NS_IMETHODIMP
 nsXPCWrappedJSClass::DebugDump(int16_t depth)
 {
--- a/js/xpconnect/src/xpc.msg
+++ b/js/xpconnect/src/xpc.msg
@@ -57,16 +57,17 @@ XPC_MSG_DEF(NS_ERROR_XPC_CANT_SET_READ_O
 XPC_MSG_DEF(NS_ERROR_XPC_CANT_ADD_PROP_TO_WRAPPED_NATIVE, "Cannot add property to WrappedNative object")
 XPC_MSG_DEF(NS_ERROR_XPC_CALL_TO_SCRIPTABLE_FAILED      , "Call to nsIXPCScriptable interface for WrappedNative failed unexpecedly")
 XPC_MSG_DEF(NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED , "JavaScript component does not have a method named:")
 XPC_MSG_DEF(NS_ERROR_XPC_BAD_ID_STRING                  , "Bad ID string")
 XPC_MSG_DEF(NS_ERROR_XPC_BAD_INITIALIZER_NAME           , "Bad initializer name in Constructor - Component has no method with that name")
 XPC_MSG_DEF(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN              , "Operation failed because the XPConnect subsystem has been shutdown")
 XPC_MSG_DEF(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN         , "Cannot modify properties of a WrappedNative")
 XPC_MSG_DEF(NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL , "Could not convert JavaScript argument - 0 was passed, expected object. Did you mean null?")
+XPC_MSG_DEF(NS_ERROR_XPC_CANT_PASS_CPOW_TO_NATIVE       , "It's illegal to pass a CPOW to native code")
 
 
 /* common global codes (from nsError.h) */
 
 XPC_MSG_DEF(NS_OK                                  , "Success")
 XPC_MSG_DEF(NS_ERROR_NOT_INITIALIZED               , "Component not initialized")
 XPC_MSG_DEF(NS_ERROR_ALREADY_INITIALIZED           , "Component already initialized")
 XPC_MSG_DEF(NS_ERROR_NOT_IMPLEMENTED               , "Method not implemented")
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2703,18 +2703,16 @@ public:
                                       const char * aPropertyName,
                                       const char * anInterfaceName,
                                       bool aForceReport);
 private:
     nsXPCWrappedJSClass();   // not implemented
     nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
                         nsIInterfaceInfo* aInfo);
 
-    JSObject*  NewOutObject(JSContext* cx, JSObject* scope);
-
     JSBool IsReflectable(uint16_t i) const
         {return (JSBool)(mDescriptors[i/32] & (1 << (i%32)));}
     void SetReflectable(uint16_t i, JSBool b)
         {if (b) mDescriptors[i/32] |= (1 << (i%32));
          else mDescriptors[i/32] &= ~(1 << (i%32));}
 
     JSBool GetArraySizeFromParam(JSContext* cx,
                                  const XPTMethodDescriptor* method,
@@ -3862,16 +3860,21 @@ inline XPCWrappedNativeScope*
 GetObjectScope(JSObject *obj)
 {
     return EnsureCompartmentPrivate(obj)->scope;
 }
 
 extern JSBool gDebugMode;
 extern JSBool gDesiredDebugMode;
 
+JSObject* NewOutObject(JSContext* cx, JSObject* scope);
+bool IsOutObject(JSContext* cx, JSObject* obj);
+
+nsresult HasInstance(JSContext *cx, JS::HandleObject objArg, const nsID *iid, bool *bp);
+
 // Internal use only.
 bool PushJSContext(JSContext *aCx);
 void PopJSContext();
 bool IsJSContextOnStack(JSContext *aCx);
 
 } // namespace xpc
 
 /***************************************************************************/
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -64,18 +64,16 @@
 #include "mozilla/ipc/ProcessChild.h"
 #include "ScopedXREEmbed.h"
 
 #include "mozilla/plugins/PluginProcessChild.h"
 #include "mozilla/dom/ContentProcess.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 
-#include "mozilla/jsipc/ContextWrapperParent.h"
-
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 
 #include "GeckoProfiler.h"
 
 #ifdef MOZ_IPDL_TESTS
 #include "mozilla/_ipdltest/IPDLUnitTests.h"
 #include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
@@ -91,19 +89,16 @@ using mozilla::ipc::IOThreadChild;
 using mozilla::ipc::ProcessChild;
 using mozilla::ipc::ScopedXREEmbed;
 
 using mozilla::plugins::PluginProcessChild;
 using mozilla::dom::ContentProcess;
 using mozilla::dom::ContentParent;
 using mozilla::dom::ContentChild;
 
-using mozilla::jsipc::PContextWrapperParent;
-using mozilla::jsipc::ContextWrapperParent;
-
 using mozilla::ipc::TestShellParent;
 using mozilla::ipc::TestShellCommandParent;
 using mozilla::ipc::XPCShellEnvironment;
 
 using mozilla::startup::sChildProcessType;
 
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
@@ -759,23 +754,16 @@ XRE_SendTestShellCommand(JSContext* aCx,
 
     JS::Value callbackVal = *reinterpret_cast<JS::Value*>(aCallback);
     NS_ENSURE_TRUE(callback->SetCallback(aCx, callbackVal), false);
 
     return true;
 }
 
 bool
-XRE_GetChildGlobalObject(JSContext* aCx, JSObject** aGlobalP)
-{
-    TestShellParent* tsp = GetOrCreateTestShellParent();
-    return tsp && tsp->GetGlobalJSObject(aCx, aGlobalP);
-}
-
-bool
 XRE_ShutdownTestShell()
 {
     if (!gContentParent) {
         return true;
     }
     bool ret = true;
     if (gContentParent->IsAlive()) {
         ret = gContentParent->DestroyTestShell(
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -459,17 +459,19 @@ CycleCollectedJSRuntime::CycleCollectedJ
   , mExpectUnrootedGlobals(aExpectUnrootedGlobals)
 #endif
 {
   mJSRuntime = JS_NewRuntime(aMaxbytes, aUseHelperThreads);
   if (!mJSRuntime) {
     MOZ_CRASH();
   }
 
-  JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this);
+  if (!JS_AddExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this)) {
+    MOZ_CRASH();
+  }
   JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
 
   mJSHolders.Init(512);
 
   nsCycleCollector_registerJSRuntime(this);
 }
 
 CycleCollectedJSRuntime::~CycleCollectedJSRuntime()
--- a/xpcom/base/ErrorList.h
+++ b/xpcom/base/ErrorList.h
@@ -587,16 +587,17 @@
   ERROR(NS_ERROR_XPC_CANT_ADD_PROP_TO_WRAPPED_NATIVE,  FAILURE(46)),
   ERROR(NS_ERROR_XPC_CALL_TO_SCRIPTABLE_FAILED,        FAILURE(47)),
   ERROR(NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED,   FAILURE(48)),
   ERROR(NS_ERROR_XPC_BAD_ID_STRING,                    FAILURE(49)),
   ERROR(NS_ERROR_XPC_BAD_INITIALIZER_NAME,             FAILURE(50)),
   ERROR(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN,                FAILURE(51)),
   ERROR(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN,           FAILURE(52)),
   ERROR(NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL,   FAILURE(53)),
+  ERROR(NS_ERROR_XPC_CANT_PASS_CPOW_TO_NATIVE,         FAILURE(54)),
   /* any new errors here should have an associated entry added in xpc.msg */
 
   ERROR(NS_SUCCESS_I_DID_SOMETHING,      SUCCESS(1)),
   /* Classes that want to only be touched by chrome (or from code whose
    * filename begins with chrome://global/) shoudl return this from their
    * scriptable helper's PreCreate hook. */
   ERROR(NS_SUCCESS_CHROME_ACCESS_ONLY,   SUCCESS(2)),
 #undef MODULE
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -431,20 +431,16 @@ class JSString;
 
 XRE_API(bool,
         XRE_SendTestShellCommand, (JSContext* aCx,
                                    JSString* aCommand,
                                    void* aCallback))
 class JSObject;
 
 XRE_API(bool,
-        XRE_GetChildGlobalObject, (JSContext* aCx,
-                                   JSObject** globalp))
-
-XRE_API(bool,
         XRE_ShutdownTestShell, ())
 
 XRE_API(void,
         XRE_InstallX11ErrorHandler, ())
 
 #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
 #define XRE_HAS_DLL_BLOCKLIST
 XRE_API(void,