Rewrite CPOWs to use one actor per process (bug 853209, r=billm,bholley,smaug).
authorDavid Anderson <danderson@mozilla.com>
Wed, 31 Jul 2013 10:59:23 -0700
changeset 149022 9b4975efc31f58c991816f95f26e42a762a84e0f
parent 149021 ade6bee5d94f1ca75e03c35d98ad0fde1c55989f
child 149023 6938e78dbe4f01583644cfb2c7340e7b9cae1094
push id368
push userbbajaj@mozilla.com
push dateMon, 09 Sep 2013 22:57:58 +0000
treeherdermozilla-release@5a4f47ae1217 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm, bholley, smaug
bugs853209
milestone24.0a2
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;
@@ -120,16 +124,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);
@@ -188,16 +193,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);
@@ -245,16 +251,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,598 @@
+/* -*- 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,
+                                    bool *result)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    *result = !!JS_IsExtensible(obj);
+    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,94 @@
+/* -*- 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,
+                            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,636 @@
+/* -*- 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(JSObject *proxy) 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();
+}
+
+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();
+}
+
+bool
+CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    MOZ_CRASH();
+}
+
+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(JSObject *proxy)
+{
+    return ParentOf(proxy)->isExtensible(proxy);
+}
+
+bool
+JavaScriptParent::isExtensible(JSObject *proxy)
+{
+    ObjectId objId = idOf(proxy);
+
+    // This function is assumed infallible, so we just return false if the IPC
+    // channel fails.
+    bool extensible;
+    if (!CallIsExtensible(objId, &extensible))
+        return false;
+    return extensible;
+}
+
+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();
+}
+
+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(JSObject *proxy);
+
+    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 (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
@@ -742,28 +742,30 @@ js::gc::MarkRuntime(JSTracer *trc, bool 
 #ifdef JS_ION
     ion::MarkJitActivations(rt, trc);
 #endif
 
     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
@@ -792,20 +792,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),
@@ -2274,22 +2270,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);
 }
 
@@ -7108,8 +7116,17 @@ 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)
+{
+    if (!JS_IsExtensible(obj))
+        return JS_TRUE;
+
+    return JSObject::preventExtensions(cx, obj);
+}
+
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2353,18 +2353,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.
@@ -3192,16 +3196,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
@@ -1154,26 +1154,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
@@ -46,18 +46,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;
 }
@@ -296,16 +296,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
@@ -126,16 +126,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
@@ -2903,18 +2903,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
@@ -2690,18 +2690,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,
@@ -3868,16 +3866,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);
+
 } // namespace xpc
 
 /***************************************************************************/
 // Inlines use the above - include last.
 
 #include "XPCInlines.h"
 
 /***************************************************************************/
--- 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
@@ -458,17 +458,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,