Rework ipcshell to become xpcshell
authorBen Turner <bent.mozilla@gmail.com>
Fri, 28 Aug 2009 16:16:19 -0700
changeset 35880 5956e487d0c8087e2577c4db2bdfef6689a0f01b
parent 35879 c25f8028ecdfb8ae73daa4a896be2fe1081fb45c
child 35881 051aa0b4321be1bde40066f2031eb82708e9e8b3
push idunknown
push userunknown
push dateunknown
milestone1.9.3a1pre
Rework ipcshell to become xpcshell
dom/ipc/ContentProcessChild.cpp
ipc/testshell/Makefile.in
ipc/testshell/TestShellChild.cpp
ipc/testshell/TestShellChild.h
ipc/testshell/TestShellParent.cpp
ipc/testshell/TestShellParent.h
ipc/testshell/XPCShellEnvironment.cpp
ipc/testshell/XPCShellEnvironment.h
ipc/testshell/app/Makefile.in
ipc/testshell/app/TestShellApp.cpp
js/src/xpconnect/public/nsAutoJSValHolder.h
js/src/xpconnect/shell/Makefile.in
js/src/xpconnect/shell/xpcshell.cpp
toolkit/library/dlldeps-xul.cpp
toolkit/xre/nsEmbedFunctions.cpp
xpcom/build/nsXPComInit.cpp
xpcom/build/nsXULAppAPI.h
--- a/dom/ipc/ContentProcessChild.cpp
+++ b/dom/ipc/ContentProcessChild.cpp
@@ -70,14 +70,12 @@ ContentProcessChild::TestShellDestructor
     return NS_OK;
 }
 
 void
 ContentProcessChild::Quit()
 {
     mIFrames.Clear();
     mTestShells.Clear();
-
-    XRE_ShutdownChildProcess();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/ipc/testshell/Makefile.in
+++ b/ipc/testshell/Makefile.in
@@ -63,13 +63,11 @@ CPPSRCS += \
 
 
 # For xpcshell error messages and nsDependentJSString
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/js/src/xpconnect/shell \
   -I$(topsrcdir)/dom/base \
   $(NULL)
 
-TOOL_DIRS += app
-
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
--- a/ipc/testshell/TestShellChild.cpp
+++ b/ipc/testshell/TestShellChild.cpp
@@ -31,41 +31,23 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "TestShellChild.h"
 
-#include "XPCShellEnvironment.h"
-
 using mozilla::ipc::TestShellChild;
 using mozilla::ipc::TestShellCommandProtocolChild;
 using mozilla::ipc::XPCShellEnvironment;
 
 TestShellChild::TestShellChild()
-: mXPCShell(nsnull)
+: mXPCShell(XPCShellEnvironment::CreateEnvironment())
 {
-  XPCShellEnvironment* env = XPCShellEnvironment::CreateEnvironment();
-  if (env) {
-    if (env->DefineIPCCommands(this)) {
-      mXPCShell = env;
-    }
-    else {
-      XPCShellEnvironment::DestroyEnvironment(env);
-    }
-  }
-}
-
-TestShellChild::~TestShellChild()
-{
-  if (mXPCShell) {
-    XPCShellEnvironment::DestroyEnvironment(mXPCShell);
-  }
 }
 
 nsresult
 TestShellChild::RecvExecuteCommand(const nsString& aCommand)
 {
   if (mXPCShell->IsQuitting()) {
     NS_WARNING("Commands sent after quit command issued!");
     return NS_ERROR_UNEXPECTED;
--- a/ipc/testshell/TestShellChild.h
+++ b/ipc/testshell/TestShellChild.h
@@ -34,27 +34,29 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _IPC_TESTSHELL_TESTSHELLCHILD_H_
 #define _IPC_TESTSHELL_TESTSHELLCHILD_H_
 
 #include "mozilla/ipc/TestShellProtocolChild.h"
 #include "mozilla/ipc/TestShellCommandProtocolChild.h"
+#include "mozilla/ipc/XPCShellEnvironment.h"
+
+#include "nsAutoPtr.h"
 
 namespace mozilla {
 namespace ipc {
 
 class XPCShellEnvironment;
 
 class TestShellChild : public TestShellProtocolChild
 {
 public:
   TestShellChild();
-  ~TestShellChild();
 
   nsresult
   RecvExecuteCommand(const nsString& aCommand);
 
   TestShellCommandProtocolChild*
   TestShellCommandConstructor(const nsString& aCommand);
 
   nsresult
@@ -65,15 +67,15 @@ public:
   TestShellCommandDestructor(TestShellCommandProtocolChild* aCommand,
                              const nsString& aResponse);
 
   void SetXPCShell(XPCShellEnvironment* aXPCShell) {
     mXPCShell = aXPCShell;
   }
 
 private:
-  XPCShellEnvironment* mXPCShell;
+  nsAutoPtr<XPCShellEnvironment> mXPCShell;
 };
 
 } /* namespace ipc */
 } /* namespace mozilla */
 
 #endif /* _IPC_TESTSHELL_TESTSHELLCHILD_H_ */
--- a/ipc/testshell/TestShellParent.cpp
+++ b/ipc/testshell/TestShellParent.cpp
@@ -32,22 +32,20 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "TestShellParent.h"
 
 #include "nsAutoPtr.h"
-#include "XPCShellEnvironment.h"
 
 using mozilla::ipc::TestShellParent;
 using mozilla::ipc::TestShellCommandParent;
 using mozilla::ipc::TestShellCommandProtocolParent;
-using mozilla::ipc::XPCShellEnvironment;
 
 TestShellCommandProtocolParent*
 TestShellParent::TestShellCommandConstructor(const nsString& aCommand)
 {
   return new TestShellCommandParent();
 }
 
 nsresult
@@ -61,34 +59,21 @@ TestShellParent::TestShellCommandDestruc
 
 nsresult
 TestShellParent::RecvTestShellCommandDestructor(TestShellCommandProtocolParent* aActor,
                                                 const nsString& aResponse)
 {
   NS_ENSURE_ARG_POINTER(aActor);
 
   TestShellCommandParent* command =
-    static_cast<TestShellCommandParent*>(aActor);
+    reinterpret_cast<TestShellCommandParent*>(aActor);
 
   JSBool ok = command->RunCallback(aResponse);
   command->ReleaseCallback();
 
-  if (!mXPCShell) {
-    NS_WARNING("Processing a child message after exiting, need to spin events "
-               "somehow to process this result");
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  NS_WARN_IF_FALSE(mXPCShell->EventLoopDepth(), "EventLoopDepth mismatch!");
-  if (mXPCShell->EventLoopDepth()) {
-    mXPCShell->DecrementEventLoopDepth();
-  }
-
-  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
-
   return NS_OK;
 }
 
 JSBool
 TestShellCommandParent::SetCallback(JSContext* aCx,
                                     jsval aCallback)
 {
   if (!mCallback.Hold(aCx)) {
--- a/ipc/testshell/TestShellParent.h
+++ b/ipc/testshell/TestShellParent.h
@@ -42,18 +42,16 @@
 
 #include "jsapi.h"
 #include "nsAutoJSValHolder.h"
 #include "nsStringGlue.h"
 
 namespace mozilla {
 namespace ipc {
 
-class XPCShellEnvironment;
-
 class TestShellCommandParent : public TestShellCommandProtocolParent
 {
 public:
   TestShellCommandParent() : mCx(NULL) { }
 
   JSBool SetCallback(JSContext* aCx,
                      jsval aCallback);
 
@@ -64,34 +62,24 @@ public:
 private:
   JSContext* mCx;
   nsAutoJSValHolder mCallback;
 };
 
 class TestShellParent : public TestShellProtocolParent
 {
 public:
-  TestShellParent() : mXPCShell(nsnull) { }
-
-  void
-  SetXPCShell(XPCShellEnvironment* aXPCShell) {
-    mXPCShell = aXPCShell;
-  }
-
   TestShellCommandProtocolParent*
   TestShellCommandConstructor(const nsString& aCommand);
 
   nsresult
   TestShellCommandDestructor(TestShellCommandProtocolParent* aActor,
                              const nsString& aResponse);
 
   nsresult
   RecvTestShellCommandDestructor(TestShellCommandProtocolParent* aActor,
                                  const nsString& aResponse);
-
-private:
-  XPCShellEnvironment* mXPCShell;
 };
 
 } /* namespace ipc */
 } /* namespace mozilla */
 
 #endif /* _IPC_TESTSHELL_TESTSHELLPARENT_H_ */
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -75,17 +75,17 @@
 
 using mozilla::ipc::XPCShellEnvironment;
 using mozilla::ipc::TestShellChild;
 using mozilla::ipc::TestShellParent;
 using mozilla::ipc::TestShellCommandProtocolParent;
 
 namespace {
 
-static const char kDefaultRuntimeScriptFilename[] = "ipcshell.js";
+static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
 
 class FullTrustSecMan : public nsIScriptSecurityManager
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIXPCSECURITYMANAGER
     NS_DECL_NSISCRIPTSECURITYMANAGER
 
@@ -273,62 +273,16 @@ GetLine(char *bufp,
     fflush(stdout);
     if (!fgets(line, sizeof line, file))
         return JS_FALSE;
     strcpy(bufp, line);
     return JS_TRUE;
 }
 
 static JSBool
-ReadLine(JSContext *cx,
-         JSObject *obj,
-         uintN argc,
-         jsval *argv,
-         jsval *rval)
-{
-    // While 4096 might be quite arbitrary, this is something to be fixed in
-    // bug 105707. It is also the same limit as in ProcessFile.
-    char buf[4096];
-    JSString *str;
-
-    /* If a prompt was specified, construct the string */
-    if (argc > 0) {
-        str = JS_ValueToString(cx, argv[0]);
-        if (!str)
-            return JS_FALSE;
-        argv[0] = STRING_TO_JSVAL(str);
-    } else {
-        str = JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
-    }
-
-    /* Get a line from the infile */
-    if (!GetLine(buf, stdin, JS_GetStringBytes(str)))
-        return JS_FALSE;
-
-    /* Strip newline character added by GetLine() */
-    unsigned int buflen = strlen(buf);
-    if (buflen == 0) {
-        if (feof(stdin)) {
-            *rval = JSVAL_NULL;
-            return JS_TRUE;
-        }
-    } else if (buf[buflen - 1] == '\n') {
-        --buflen;
-    }
-
-    /* Turn buf into a JSString */
-    str = JS_NewStringCopyN(cx, buf, buflen);
-    if (!str)
-        return JS_FALSE;
-
-    *rval = STRING_TO_JSVAL(str);
-    return JS_TRUE;
-}
-
-static JSBool
 Dump(JSContext *cx,
      JSObject *obj,
      uintN argc,
      jsval *argv,
      jsval *rval)
 {
     JSString *str;
     if (!argc)
@@ -571,17 +525,16 @@ Clear(JSContext *cx,
         return JS_FALSE;
     }
     return JS_TRUE;
 }
 
 JSFunctionSpec gGlobalFunctions[] =
 {
     {"print",           Print,          0,0,0},
-    {"readline",        ReadLine,       1,0,0},
     {"load",            Load,           1,0,0},
     {"quit",            Quit,           0,0,0},
     {"version",         Version,        1,0,0},
     {"build",           BuildDate,      0,0,0},
     {"dumpXPC",         DumpXPC,        1,0,0},
     {"dump",            Dump,           1,0,0},
     {"gc",              GC,             0,0,0},
     {"clear",           Clear,          1,0,0},
@@ -597,145 +550,16 @@ JSFunctionSpec gGlobalFunctions[] =
 #ifdef MOZ_CALLGRIND
     {"startCallgrind",  js_StartCallgrind,  0,0,0},
     {"stopCallgrind",   js_StopCallgrind,   0,0,0},
     {"dumpCallgrind",   js_DumpCallgrind,   1,0,0},
 #endif
     {nsnull,nsnull,0,0,0}
 };
 
-JSClass gGlobalClass =
-{
-    "global", 0,
-    JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
-    JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub
-};
-
-static JSBool
-EnvironmentSetProperty(JSContext *cx,
-                       JSObject *obj,
-                       jsval id,
-                       jsval *vp)
-{
-/* XXX porting may be easy, but these don't seem to supply setenv by default */
-#if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS
-    JSString *idstr, *valstr;
-    const char *name, *value;
-    int rv;
-
-    idstr = JS_ValueToString(cx, id);
-    valstr = JS_ValueToString(cx, *vp);
-    if (!idstr || !valstr)
-        return JS_FALSE;
-    name = JS_GetStringBytes(idstr);
-    value = JS_GetStringBytes(valstr);
-#if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX \
-    || defined SCO
-    {
-        char *waste = JS_smprintf("%s=%s", name, value);
-        if (!waste) {
-            JS_ReportOutOfMemory(cx);
-            return JS_FALSE;
-        }
-        rv = putenv(waste);
-#ifdef XP_WIN
-        /*
-         * HPUX9 at least still has the bad old non-copying putenv.
-         *
-         * Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
-         * that will crash if you pass it an auto char array (so it must place
-         * its argument directly in the char *environ[] array).
-         */
-        free(waste);
-#endif
-    }
-#else
-    rv = setenv(name, value, 1);
-#endif
-    if (rv < 0) {
-        JS_ReportError(cx, "can't set envariable %s to %s", name, value);
-        return JS_FALSE;
-    }
-    *vp = STRING_TO_JSVAL(valstr);
-#endif /* !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS */
-    return JS_TRUE;
-}
-
-static JSBool
-EnvironmentEnumerate(JSContext *cx,
-                     JSObject *obj)
-{
-    static JSBool reflected;
-    char **evp, *name, *value;
-    JSString *valstr;
-    JSBool ok;
-
-    if (reflected)
-        return JS_TRUE;
-
-    for (evp = (char **)JS_GetPrivate(cx, obj); (name = *evp) != NULL; evp++) {
-        value = strchr(name, '=');
-        if (!value)
-            continue;
-        *value++ = '\0';
-        valstr = JS_NewStringCopyZ(cx, value);
-        if (!valstr) {
-            ok = JS_FALSE;
-        } else {
-            ok = JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
-                                   NULL, NULL, JSPROP_ENUMERATE);
-        }
-        value[-1] = '=';
-        if (!ok)
-            return JS_FALSE;
-    }
-
-    reflected = JS_TRUE;
-    return JS_TRUE;
-}
-
-static JSBool
-EnvironmentResolve(JSContext *cx,
-                   JSObject *obj,
-                   jsval id,
-                   uintN flags,
-            JSObject **objp)
-{
-    JSString *idstr, *valstr;
-    const char *name, *value;
-
-    if (flags & JSRESOLVE_ASSIGNING)
-        return JS_TRUE;
-
-    idstr = JS_ValueToString(cx, id);
-    if (!idstr)
-        return JS_FALSE;
-    name = JS_GetStringBytes(idstr);
-    value = getenv(name);
-    if (value) {
-        valstr = JS_NewStringCopyZ(cx, value);
-        if (!valstr)
-            return JS_FALSE;
-        if (!JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
-                               NULL, NULL, JSPROP_ENUMERATE)) {
-            return JS_FALSE;
-        }
-        *objp = obj;
-    }
-    return JS_TRUE;
-}
-
-JSClass gEnvironmentClass =
-{
-    "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
-    JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, EnvironmentSetProperty,
-    EnvironmentEnumerate, (JSResolveOp) EnvironmentResolve, JS_ConvertStub,
-    JS_FinalizeStub
-};
-
 typedef enum JSShellErrNum
 {
 #define MSG_DEF(name, number, count, exception, format) \
     name = number,
 #include "jsshell.msg"
 #undef MSG_DEF
     JSShellErr_Limit
 #undef MSGDEF
@@ -755,24 +579,16 @@ GetErrorMessage(void *userRef,
                 const uintN errorNumber)
 {
     if ((errorNumber > 0) && (errorNumber < JSShellErr_Limit))
         return &gErrorFormatString[errorNumber];
 
     return NULL;
 }
 
-static int
-PrintUsage(void)
-{
-    fprintf(stderr, "%s\n", JS_GetImplementationVersion());
-    fprintf(stderr, "usage: xpcshell [-g gredir] [-PswWxCij] [-v version] [-f scriptfile] [-e script] [scriptfile] [scriptarg...]\n");
-    return 2;
-}
-
 static void
 ProcessFile(JSContext *cx,
             JSObject *obj,
             const char *filename,
             FILE *file,
             JSBool forceTTY)
 {
     XPCShellEnvironment* env = Environment(cx);
@@ -873,96 +689,16 @@ ProcessFile(JSContext *cx,
             }
             JS_DestroyScript(cx, script);
         }
     } while (!hitEOF && !env->IsQuitting());
 
     fprintf(stdout, "\n");
 }
 
-static JSBool
-SendCommand(JSContext *cx,
-            JSObject *obj,
-            uintN argc,
-            jsval *argv,
-            jsval *rval)
-{
-    if (argc == 0) {
-        JS_ReportError(cx, "Function takes at least one argument!");
-        return JS_FALSE;
-    }
-
-    JSString* str = JS_ValueToString(cx, argv[0]);
-    if (!str) {
-        JS_ReportError(cx, "Could not convert argument 1 to string!");
-        return JS_FALSE;
-    }
-
-    nsDependentJSString command(str);
-    JSBool ok;
-
-    if (argc > 1) {
-        if (JS_TypeOfValue(cx, argv[1]) != JSTYPE_FUNCTION) {
-            JS_ReportError(cx, "Could not convert argument 2 to function!");
-            return JS_FALSE;
-        }
-        ok = Environment(cx)->DoSendCommand(command, cx, argv[1]);
-        if (ok) {
-            Environment(cx)->IncrementEventLoopDepth();
-        }
-    }
-    else {
-        ok = Environment(cx)->DoSendCommand(command);
-    }
-
-    if (!ok) {
-        JS_ReportError(cx, "Failed to send command!");
-        return JS_FALSE;
-    }
-
-    return JS_TRUE;
-}
-
-static JSBool
-RunEventLoop(JSContext *cx,
-             JSObject *obj,
-             uintN argc,
-             jsval *argv,
-             jsval *rval)
-{
-    NS_ASSERTION(Environment(cx)->EventLoopDepth() >= 0, "Bad depth!");
-    Environment(cx)->IncrementEventLoopDepth();
-    return JS_TRUE;
-}
-
-static JSBool
-StopEventLoop(JSContext *cx,
-              JSObject *obj,
-              uintN argc,
-              jsval *argv,
-              jsval *rval)
-{
-    XPCShellEnvironment* env = Environment(cx);
-    if (env->EventLoopDepth() < 1) {
-        JS_ReportError(cx, "Mismatched call to DecrementEventLoopDepth");
-        return JS_FALSE;
-    }
-
-    env->DecrementEventLoopDepth();
-    return JS_TRUE;
-}
-
-JSFunctionSpec gParentFunctions[] =
-{
-    {"sendCommand",             SendCommand,             1, 0, 0},
-    {"runEventLoop",            RunEventLoop,            0, 0, 0},
-    {"stopEventLoop",           StopEventLoop,           0, 0, 0},
-    {nsnull,                    nsnull,                  0, 0, 0}
-};
-
 } /* anonymous namespace */
 
 NS_INTERFACE_MAP_BEGIN(FullTrustSecMan)
     NS_INTERFACE_MAP_ENTRY(nsIXPCSecurityManager)
     NS_INTERFACE_MAP_ENTRY(nsIScriptSecurityManager)
     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCSecurityManager)
 NS_INTERFACE_MAP_END
 
@@ -1289,32 +1025,23 @@ XPCShellEnvironment::CreateEnvironment()
     XPCShellEnvironment* env = new XPCShellEnvironment();
     if (env && !env->Init()) {
         delete env;
         env = nsnull;
     }
     return env;
 }
 
-// static
-void
-XPCShellEnvironment::DestroyEnvironment(XPCShellEnvironment* aEnv)
-{
-    delete aEnv;
-}
-
 XPCShellEnvironment::XPCShellEnvironment()
 :   mCx(NULL),
     mJSPrincipals(NULL),
     mExitCode(0),
-    mEventLoopDepth(0),
     mQuitting(JS_FALSE),
     mReportWarnings(JS_TRUE),
-    mCompileOnly(JS_FALSE),
-    mParent(nsnull)
+    mCompileOnly(JS_FALSE)
 {
 }
 
 XPCShellEnvironment::~XPCShellEnvironment()
 {
     if (mCx) {
         JS_BeginRequest(mCx);
 
@@ -1456,126 +1183,31 @@ XPCShellEnvironment::Init()
 
     {
         JSAutoRequest ar(cx);
 
         if (!JS_DefineFunctions(cx, globalObj, gGlobalFunctions)) {
             NS_ERROR("JS_DefineFunctions failed!");
             return false;
         }
-
-#if 0 // Just until we care enough to get then environment strings.
-        JSObject *envObj = JS_DefineObject(cx, globalObj, "environment",
-                                           &gEnvironmentClass, NULL, 0);
-        if (!envObj || !JS_SetPrivate(cx, envObj, envp)) {
-            NS_ERROR("Failed to make environment object!");
-            return false;
-        }
-#endif
-
     }
 
     mGlobalHolder = globalObj;
 
     FILE* runtimeScriptFile = fopen(kDefaultRuntimeScriptFilename, "r");
     if (runtimeScriptFile) {
         fprintf(stdout, "[loading '%s'...]\n", kDefaultRuntimeScriptFilename);
         ProcessFile(cx, globalObj, kDefaultRuntimeScriptFilename,
                     runtimeScriptFile, JS_FALSE);
         fclose(runtimeScriptFile);
     }
 
     return true;
 }
 
-void
-XPCShellEnvironment::Process(const char* aFilename)
-{
-    NS_ASSERTION(GetGlobalObject(), "Should never be null!");
-
-    FILE* file;
-    if (!aFilename) {
-        file = stdin;
-    } else {
-        file = fopen(aFilename, "r");
-        if (!file) {
-            JS_ReportErrorNumber(mCx, GetErrorMessage, NULL,
-                                 JSSMSG_CANT_OPEN,
-                                 aFilename, strerror(errno));
-            mExitCode = EXITCODE_FILE_NOT_FOUND;
-            return;
-        }
-    }
-
-    ProcessFile(mCx, GetGlobalObject(), aFilename, file, !aFilename);
-    if (file != stdin) {
-        fclose(file);
-    }
-
-    if (EventLoopDepth()) {
-        nsCOMPtr<nsIThread> currentThread;
-        NS_GetCurrentThread(getter_AddRefs(currentThread));
-
-        while (EventLoopDepth()) {
-            NS_ProcessNextEvent(currentThread, PR_TRUE);
-        }
-    }
-}
-
-bool
-XPCShellEnvironment::DefineIPCCommands(TestShellChild* aChild)
-{
-    NS_ASSERTION(aChild, "Don't hand me null!");
-
-    // XXXbent Nothing here yet, soon though!
-    return true;
-}
-
-bool
-XPCShellEnvironment::DefineIPCCommands(TestShellParent* aParent)
-{
-    NS_ASSERTION(aParent, "Don't hand me null!");
-
-    mParent = aParent;
-
-    JSObject* global = GetGlobalObject();
-
-    JSAutoRequest ar(mCx);
-
-    if (!JS_DefineFunctions(mCx, global, gParentFunctions)) {
-        NS_ERROR("JS_DefineFunctions failed!");
-        return false;
-    }
-
-    return true;
-}
-
-JSBool
-XPCShellEnvironment::DoSendCommand(const nsString& aCommand,
-                                   JSContext* aCx,
-                                   jsval aCallback)
-{
-  if (aCx) {
-      TestShellCommandParent* command = static_cast<TestShellCommandParent*>(
-          mParent->SendTestShellCommandConstructor(aCommand));
-      NS_ENSURE_TRUE(command, JS_FALSE);
-
-      if (!command->SetCallback(aCx, aCallback)) {
-          NS_WARNING("Failed to set callback!");
-          return JS_FALSE;
-      }
-  }
-  else {
-      nsresult rv = mParent->SendExecuteCommand(aCommand);
-      NS_ENSURE_SUCCESS(rv, JS_FALSE);
-  }
-
-  return JS_TRUE;
-}
-
 bool
 XPCShellEnvironment::EvaluateString(const nsString& aString,
                                     nsString* aResult)
 {
   JSAutoRequest ar(mCx);
 
   JS_ClearPendingException(mCx);
 
--- a/ipc/testshell/XPCShellEnvironment.h
+++ b/ipc/testshell/XPCShellEnvironment.h
@@ -36,48 +36,36 @@
 
 #ifndef _IPC_TESTSHELL_XPCSHELLENVIRONMENT_H_
 #define _IPC_TESTSHELL_XPCSHELLENVIRONMENT_H_
 
 #include "base/basictypes.h"
 
 #include <string>
 #include <stdio.h>
+
+#include "nsAutoJSValHolder.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
-#include "nsAutoJSValHolder.h"
-
-#include "mozilla/ipc/TestShellProtocol.h"
+#include "nsStringGlue.h"
 
 struct JSContext;
 struct JSObject;
 struct JSPrincipals;
 
 class nsIJSContextStack;
 
 namespace mozilla {
 namespace ipc {
 
-class TestShellChild;
-class TestShellParent;
-
 class XPCShellEnvironment
 {
 public:
     static XPCShellEnvironment* CreateEnvironment();
-    static void DestroyEnvironment(XPCShellEnvironment* aEnv);
-
-    void Process(const char* aFilename = nsnull);
-
-    bool DefineIPCCommands(TestShellChild* aChild);
-    bool DefineIPCCommands(TestShellParent* aParent);
-
-    JSBool DoSendCommand(const nsString& aCommand,
-                         JSContext* aCx = nsnull,
-                         jsval aCallback = JSVAL_VOID);
+    ~XPCShellEnvironment();
 
     bool EvaluateString(const nsString& aString,
                         nsString* aResult = nsnull);
 
     JSPrincipals* GetPrincipal() {
         return mJSPrincipals;
     }
 
@@ -108,52 +96,37 @@ public:
 
     void SetShouldCompoleOnly(JSBool aCompileOnly) {
         mCompileOnly = aCompileOnly;
     }
     JSBool ShouldCompileOnly() {
         return mCompileOnly;
     }
 
-    int EventLoopDepth() {
-        return mEventLoopDepth;
-    }
-    void IncrementEventLoopDepth() {
-        ++mEventLoopDepth;
-    }
-    void DecrementEventLoopDepth() {
-        --mEventLoopDepth;
-    }
-
     class AutoContextPusher
     {
     public:
         AutoContextPusher(XPCShellEnvironment* aEnv);
         ~AutoContextPusher();
     private:
         XPCShellEnvironment* mEnv;
     };
 
 protected:
     XPCShellEnvironment();
-    ~XPCShellEnvironment();
-
     bool Init();
 
 private:
     JSContext* mCx;
     nsAutoJSValHolder mGlobalHolder;
     nsCOMPtr<nsIJSContextStack> mCxStack;
     JSPrincipals* mJSPrincipals;
 
     int mExitCode;
-    int mEventLoopDepth;
     JSBool mQuitting;
     JSBool mReportWarnings;
     JSBool mCompileOnly;
-
-    TestShellParent* mParent;
 };
 
 } /* namespace ipc */
 } /* namespace mozilla */
 
 #endif /* _IPC_TESTSHELL_XPCSHELLENVIRONMENT_H_ */
\ No newline at end of file
deleted file mode 100644
--- a/ipc/testshell/app/Makefile.in
+++ /dev/null
@@ -1,74 +0,0 @@
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is Mozilla IPCShell.
-#
-# The Initial Developer of the Original Code is
-#   Ben Turner <bent.mozilla@gmail.com>.
-# Portions created by the Initial Developer are Copyright (C) 2009
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-DEPTH = ../../..
-topsrcdir = @top_srcdir@
-srcdir = @srcdir@
-VPATH = @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE = ipcshell
-PROGRAM = $(MODULE)$(BIN_SUFFIX)
-ENABLE_CXX_EXCEPTIONS = 1
-
-LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
-
-CPPSRCS = \
-  TestShellApp.cpp \
-  $(NULL)
-
-LIBS = \
-  $(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
-  $(LIBXUL_LIBS) \
-  $(MOZ_JS_LIBS) \
-  $(NSPR_LIBS) \
-  $(NULL)
-
-NSDISTMODE = copy
-
-include $(topsrcdir)/config/config.mk
-
-ifdef _MSC_VER
-ifdef WINCE
-WIN32_EXE_LDFLAGS += -ENTRY:mainWCRTStartup
-else
-WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
-endif
-endif
-
-include $(topsrcdir)/ipc/chromium/chromium-config.mk
-include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/ipc/testshell/app/TestShellApp.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla IPCShell.
- *
- * The Initial Developer of the Original Code is
- *   Ben Turner <bent.mozilla@gmail.com>.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsXULAppAPI.h"
-
-#if defined(XP_WIN)
-#include <windows.h>
-#include "nsWindowsWMain.cpp"
-#endif
-
-int
-main(int argc, char* argv[])
-{
-    return XRE_RunTestShell(argc, argv);
-}
--- a/js/src/xpconnect/public/nsAutoJSValHolder.h
+++ b/js/src/xpconnect/public/nsAutoJSValHolder.h
@@ -37,16 +37,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __NSAUTOJSVALHOLDER_H__
 #define __NSAUTOJSVALHOLDER_H__
 
 #include "jsapi.h"
 
+#include "nsDebug.h"
+
 /**
  * Simple class that looks and acts like a jsval except that it unroots
  * itself automatically if Root() is ever called. Designed to be rooted on the
  * context or runtime (but not both!).
  */
 class nsAutoJSValHolder
 {
 public:
--- a/js/src/xpconnect/shell/Makefile.in
+++ b/js/src/xpconnect/shell/Makefile.in
@@ -63,16 +63,18 @@ LIBS		= \
 NSDISTMODE = copy
 
 ifdef _MSC_VER
 ifdef WINCE
 WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup
 endif
 endif
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES		+= -DJS_THREADSAFE
 
 ifdef MOZ_SHARK
 DEFINES += -DMOZ_SHARK
 CFLAGS += -F/System/Library/PrivateFrameworks
 LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -40,16 +40,21 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* XPConnect JavaScript interactive shell. */
 
+#ifdef MOZ_IPC
+#include "mozilla/dom/ContentProcessParent.h"
+#include "mozilla/ipc/TestShellParent.h"
+#endif
+
 #include <stdio.h>
 #include "nsXULAppAPI.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsStringAPI.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCScriptable.h"
 #include "nsIInterfaceInfo.h"
@@ -104,16 +109,19 @@
 #endif
 
 #include "nsIJSContextStack.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsICrashReporter.h"
 #endif
 
+using mozilla::dom::ContentProcessParent;
+using mozilla::ipc::TestShellParent;
+
 class XPCShellDirProvider : public nsIDirectoryServiceProvider2
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIDIRECTORYSERVICEPROVIDER
     NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
 
     XPCShellDirProvider() { }
@@ -645,30 +653,68 @@ Clear(JSContext *cx, JSObject *obj, uint
         JS_ClearScope(cx, JSVAL_TO_OBJECT(argv[0]));
     } else {
         JS_ReportError(cx, "'clear' requires an object");
         return JS_FALSE;
     }
     return JS_TRUE;
 }
 
+#ifdef MOZ_IPC
+
+static JSBool
+SendCommand(JSContext* cx,
+            JSObject* obj,
+            uintN argc,
+            jsval* argv,
+            jsval* rval)
+{
+    if (argc == 0) {
+        JS_ReportError(cx, "Function takes at least one argument!");
+        return JS_FALSE;
+    }
+
+    JSString* str = JS_ValueToString(cx, argv[0]);
+    if (!str) {
+        JS_ReportError(cx, "Could not convert argument 1 to string!");
+        return JS_FALSE;
+    }
+
+    if (argc > 1 && JS_TypeOfValue(cx, argv[1]) != JSTYPE_FUNCTION) {
+        JS_ReportError(cx, "Could not convert argument 2 to function!");
+        return JS_FALSE;
+    }
+
+    if (!XRE_SendTestShellCommand(cx, str, argc > 1 ? &argv[1] : nsnull)) {
+        JS_ReportError(cx, "Couldn't send command!");
+        return JS_FALSE;
+    }
+
+    return JS_TRUE;
+}
+
+#endif // MOZ_IPC
+
 static JSFunctionSpec glob_functions[] = {
     {"print",           Print,          0,0,0},
     {"readline",        ReadLine,       1,0,0},
     {"load",            Load,           1,0,0},
     {"quit",            Quit,           0,0,0},
     {"version",         Version,        1,0,0},
     {"build",           BuildDate,      0,0,0},
     {"dumpXPC",         DumpXPC,        1,0,0},
     {"dump",            Dump,           1,0,0},
     {"gc",              GC,             0,0,0},
     {"clear",           Clear,          1,0,0},
 #ifdef DEBUG
     {"dumpHeap",        DumpHeap,       5,0,0},
 #endif
+#ifdef MOZ_IPC
+    {"sendCommand",     SendCommand,    1,0,0},
+#endif
 #ifdef MOZ_SHARK
     {"startShark",      js_StartShark,      0,0,0},
     {"stopShark",       js_StopShark,       0,0,0},
     {"connectShark",    js_ConnectShark,    0,0,0},
     {"disconnectShark", js_DisconnectShark, 0,0,0},
 #endif
 #ifdef MOZ_CALLGRIND
     {"startCallgrind",  js_StartCallgrind,  0,0,0},
--- a/toolkit/library/dlldeps-xul.cpp
+++ b/toolkit/library/dlldeps-xul.cpp
@@ -48,16 +48,13 @@ void xxxNeverCalledXUL()
   XRE_TermEmbedding();
   XRE_CreateAppData(nsnull, nsnull);
   XRE_ParseAppData(nsnull, nsnull);
   XRE_FreeAppData(nsnull);
   XRE_ChildProcessTypeToString(GeckoProcessType_Default);
   XRE_StringToChildProcessType("");
   XRE_InitChildProcess(0, nsnull, GeckoProcessType_Default);
   XRE_InitParentProcess(0, nsnull, nsnull, nsnull);
-  XRE_RunTestShell(0, nsnull);
   XRE_GetProcessType();
-  XRE_ShutdownChildProcess();
   XRE_RunAppShell();
-  XRE_ShutdownChildProcess();
-  XRE_GetContentProcessParent();
-  XRE_GetContentProcessChild();
+  XRE_ShutdownChildProcess(nsnull);
+  XRE_SendTestShellCommand(nsnull, nsnull, nsnull);
 }
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -30,16 +30,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "base/basictypes.h"
+
 #include "nsXULAppAPI.h"
 
 #include <stdlib.h>
 
 #include "prenv.h"
 
 #include "nsIAppShell.h"
 #include "nsIAppStartupNotifier.h"
@@ -85,16 +87,17 @@ using mozilla::ipc::GeckoChildProcessHos
 using mozilla::ipc::GeckoThread;
 using mozilla::ipc::ScopedXREEmbed;
 
 using mozilla::plugins::PluginThreadChild;
 using mozilla::dom::ContentProcessThread;
 using mozilla::dom::ContentProcessParent;
 using mozilla::dom::ContentProcessChild;
 using mozilla::ipc::TestShellParent;
+using mozilla::ipc::TestShellCommandParent;
 using mozilla::ipc::XPCShellEnvironment;
 
 using mozilla::test::TestParent;
 using mozilla::test::TestProcessParent;
 using mozilla::test::TestThreadChild;
 
 using mozilla::Monitor;
 using mozilla::MonitorAutoEnter;
@@ -360,103 +363,16 @@ XRE_InitParentProcess(int aArgc,
       NS_WARNING("Failed to run appshell");
       return NS_ERROR_FAILURE;
     }
   }
 
   return NS_OK;
 }
 
-NS_SPECIALIZE_TEMPLATE
-class nsAutoRefTraits<XPCShellEnvironment> :
-  public nsPointerRefTraits<XPCShellEnvironment>
-{
-public:
-  void Release(XPCShellEnvironment* aEnv) {
-    XPCShellEnvironment::DestroyEnvironment(aEnv);
-  }
-};
-
-namespace {
-
-class QuitRunnable : public nsRunnable
-{
-public:
-  NS_IMETHOD Run() {
-    nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
-    NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
-
-    return appShell->Exit();
-  }
-};
-
-int
-TestShellMain(int argc, char** argv)
-{
-  // Make sure we quit when we exit this function.
-  nsIRunnable* quitRunnable = new QuitRunnable();
-  NS_ENSURE_TRUE(quitRunnable, 1);
-
-  nsresult rv = NS_DispatchToCurrentThread(quitRunnable);
-  NS_ENSURE_SUCCESS(rv, 1);
-
-  nsAutoRef<XPCShellEnvironment> env(XPCShellEnvironment::CreateEnvironment());
-  NS_ENSURE_TRUE(env, 1);
-
-  ContentProcessParent* childProcess = ContentProcessParent::GetSingleton();
-  NS_ENSURE_TRUE(childProcess, 1);
-
-  TestShellParent* testShellParent = childProcess->CreateTestShell();
-  NS_ENSURE_TRUE(testShellParent, 1);
-
-  testShellParent->SetXPCShell(env);
-
-  bool ok = env->DefineIPCCommands(testShellParent);
-  NS_ENSURE_TRUE(ok, 1);
-
-  const char* filename = argc > 1 ? argv[1] : nsnull;
-  env->Process(filename);
-
-  testShellParent->SetXPCShell(nsnull);
-
-  return env->ExitCode();
-}
-
-struct TestShellData {
-  int* result;
-  int argc;
-  char** argv;
-};
-
-void
-TestShellMainWrapper(void* aData)
-{
-  NS_ASSERTION(aData, "Don't give me a null pointer!");
-  TestShellData& testShellData = *static_cast<TestShellData*>(aData);
-
-  *testShellData.result =
-    TestShellMain(testShellData.argc, testShellData.argv);
-}
-
-} /* anonymous namespace */
-
-int
-XRE_RunTestShell(int aArgc, char* aArgv[])
-{
-    int result;
-
-    TestShellData data = { &result, aArgc, aArgv };
-
-    nsresult rv =
-      XRE_InitParentProcess(aArgc, aArgv, TestShellMainWrapper, &data);
-    NS_ENSURE_SUCCESS(rv, 1);
-
-    return result;
-}
-
 //-----------------------------------------------------------------------------
 // TestHarness
 
 static void
 IPCTestHarnessMain(void* data)
 {
     TestProcessParent* subprocess = new TestProcessParent(); // leaks
     bool launched = subprocess->SyncLaunch();
@@ -491,45 +407,54 @@ struct RunnableMethodTraits<ContentProce
 {
     static void RetainCallee(ContentProcessChild* obj) { }
     static void ReleaseCallee(ContentProcessChild* obj) { }
 };
 
 void
 XRE_ShutdownChildProcess(MessageLoop* aUILoop)
 {
+    NS_ASSERTION(aUILoop, "Shouldn't be null!");
     if (aUILoop) {
         NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
         aUILoop->PostTask(FROM_HERE,
             NewRunnableMethod(ContentProcessChild::GetSingleton(),
                               &ContentProcessChild::Quit));
-        return;
-    }
-
-    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-    nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
-    if (appShell) {
-        appShell->Exit();
     }
 }
 
-ContentProcessParent*
-XRE_GetContentProcessParent()
-{
-    if (XRE_GetProcessType() == GeckoProcessType_Default) {
-        return ContentProcessParent::GetSingleton();
-    }
-    NS_WARNING("Called XRE_GetContentProcessParent in child process!");
-    return nsnull;
+namespace {
+TestShellParent* gTestShellParent = nsnull;
 }
 
-ContentProcessChild*
-XRE_GetContentProcessChild()
+bool
+XRE_SendTestShellCommand(JSContext* aCx,
+                         JSString* aCommand,
+                         void* aCallback)
 {
-    if (XRE_GetProcessType() != GeckoProcessType_Default) {
-        return ContentProcessChild::GetSingleton();
+    if (!gTestShellParent) {
+        ContentProcessParent* parent = ContentProcessParent::GetSingleton();
+        NS_ENSURE_TRUE(parent, false);
+
+        gTestShellParent = parent->CreateTestShell();
+        NS_ENSURE_TRUE(gTestShellParent, false);
     }
-    NS_WARNING("Called XRE_GetContentProcessChild in parent process!");
-    return nsnull;
+
+    nsDependentString command((PRUnichar*)JS_GetStringChars(aCommand),
+                              JS_GetStringLength(aCommand));
+    if (!aCallback) {
+        if (NS_FAILED(gTestShellParent->SendExecuteCommand(command))) {
+            return false;
+        }
+        return true;
+    }
+
+    TestShellCommandParent* callback = static_cast<TestShellCommandParent*>(
+        gTestShellParent->SendTestShellCommandConstructor(command));
+    NS_ENSURE_TRUE(callback, false);
+
+    jsval callbackVal = *reinterpret_cast<jsval*>(aCallback);
+    NS_ENSURE_TRUE(callback->SetCallback(aCx, callbackVal), false);
+
+    return true;
 }
 
 #endif
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -33,16 +33,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/XPCOM.h"
+#include "nsXULAppAPI.h"
 
 #include "nsXPCOMPrivate.h"
 #include "nsXPCOMCIDInternal.h"
 
 #include "nsStaticComponents.h"
 #include "prlink.h"
 
 #include "nsObserverList.h"
@@ -587,17 +588,18 @@ NS_InitXPCOM3(nsIServiceManager* *result
 #endif
     }
 
     if (!MessageLoop::current()) {
         sMessageLoop = new MessageLoopForUI();
         NS_ENSURE_STATE(sMessageLoop);
     }
 
-    if (!BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO)) {
+    if (XRE_GetProcessType() == GeckoProcessType_Default &&
+        !BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO)) {
         scoped_ptr<BrowserProcessSubThread> ioThread(
             new BrowserProcessSubThread(BrowserProcessSubThread::IO));
         NS_ENSURE_TRUE(ioThread.get(), NS_ERROR_OUT_OF_MEMORY);
 
         base::Thread::Options options;
         options.message_loop_type = MessageLoop::TYPE_IO;
         NS_ENSURE_TRUE(ioThread->StartWithOptions(options), NS_ERROR_FAILURE);
 
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -461,36 +461,28 @@ typedef void (*MainFunction)(void* aData
 
 XRE_API(nsresult,
         XRE_InitParentProcess, (int aArgc,
                                 char* aArgv[],
                                 MainFunction aMainFunction,
                                 void* aMainFunctionExtraData))
 
 XRE_API(int,
-        XRE_RunTestShell, (int aArgc,
-                           char* aArgv[]))
-
-XRE_API(int,
         XRE_RunIPCTestHarness, (int aArgc,
                                 char* aArgv[]))
 
 XRE_API(nsresult,
         XRE_RunAppShell, ())
 
 class MessageLoop;
 
 XRE_API(void,
-        XRE_ShutdownChildProcess, (MessageLoop* aUILoop = 0))
+        XRE_ShutdownChildProcess, (MessageLoop* aUILoop))
+
+struct JSContext;
+struct JSString;
 
-namespace mozilla {
-namespace dom {
-class ContentProcessParent;
-class ContentProcessChild;
-}
-}
-
-XRE_API(mozilla::dom::ContentProcessParent*,
-        XRE_GetContentProcessParent, ())
-XRE_API(mozilla::dom::ContentProcessChild*,
-        XRE_GetContentProcessChild, ())
+XRE_API(bool,
+        XRE_SendTestShellCommand, (JSContext* aCx,
+                                   JSString* aCommand,
+                                   void* aCallback))
 
 #endif // _nsXULAppAPI_h__