Bug 287107 - make Components.returnCode be the xpcom nsresult if set by js components. r=bholley
authorMark Hammond <mhammond@skippinet.com.au>
Tue, 09 Dec 2014 13:52:08 +1100
changeset 218795 6d97109e0c306f9194d236eac82a6d7e8f572416
parent 218794 2147895c5dc47c9a416991711c82c41ea7ca888b
child 218796 62bd0993a4553a941287594df99cd6bc24c969d1
push id27944
push usercbook@mozilla.com
push dateTue, 09 Dec 2014 11:54:28 +0000
treeherdermozilla-central@acf5660d2048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs287107
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 287107 - make Components.returnCode be the xpcom nsresult if set by js components. r=bholley
js/xpconnect/idl/xpccomponents.idl
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/tests/components/js/Makefile.in
js/xpconnect/tests/components/js/xpctest.manifest
js/xpconnect/tests/components/js/xpctest_returncode_child.js
js/xpconnect/tests/components/native/moz.build
js/xpconnect/tests/components/native/xpctest_module.cpp
js/xpconnect/tests/components/native/xpctest_private.h
js/xpconnect/tests/components/native/xpctest_returncode.cpp
js/xpconnect/tests/idl/moz.build
js/xpconnect/tests/idl/xpctest_returncode.idl
js/xpconnect/tests/unit/test_returncode.js
js/xpconnect/tests/unit/xpcshell.ini
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -711,13 +711,15 @@ interface nsIXPCComponents : nsIXPCCompo
 
     readonly attribute nsIXPCComponents_ID              ID;
     readonly attribute nsIXPCComponents_Exception       Exception;
     readonly attribute nsIXPCComponents_Constructor     Constructor;
 
     [implicit_jscontext]
     readonly attribute jsval                            lastResult;
     [implicit_jscontext]
+    // A javascript component can set |returnCode| to specify an nsresult to
+    // be returned without throwing an exception.
     attribute jsval                                     returnCode;
 
     /* @deprecated Use Components.utils.reportError instead. */
     [deprecated, implicit_jscontext] void reportError(in jsval error);
 };
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -77,16 +77,35 @@ bool xpc_IsReportableErrorCode(nsresult 
         case NS_ERROR_FACTORY_REGISTER_AGAIN:
         case NS_BASE_STREAM_WOULD_BLOCK:
             return false;
         default:
             return true;
     }
 }
 
+// A little stack-based RAII class to help management of the XPCContext
+// PendingResult.
+class MOZ_STACK_CLASS AutoSavePendingResult {
+public:
+    AutoSavePendingResult(XPCContext *xpcc) :
+        mXPCContext(xpcc)
+    {
+        // Save any existing pending result and reset to NS_OK for this invocation.
+        mSavedResult = xpcc->GetPendingResult();
+        xpcc->SetPendingResult(NS_OK);
+    }
+    ~AutoSavePendingResult() {
+        mXPCContext->SetPendingResult(mSavedResult);
+    }
+private:
+    XPCContext *mXPCContext;
+    nsresult mSavedResult;
+};
+
 // static
 already_AddRefed<nsXPCWrappedJSClass>
 nsXPCWrappedJSClass::GetNewOrUsed(JSContext* cx, REFNSIID aIID, bool allowNonScriptable)
 {
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
     nsRefPtr<nsXPCWrappedJSClass> clasp = map->Find(aIID);
 
@@ -868,17 +887,16 @@ NS_IMETHODIMP
 nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
                                 const XPTMethodDescriptor* info_,
                                 nsXPTCMiniVariant* nativeParams)
 {
     jsval* sp = nullptr;
     jsval* argv = nullptr;
     uint8_t i;
     nsresult retval = NS_ERROR_FAILURE;
-    nsresult pending_result = NS_OK;
     bool success;
     bool readyToDoTheCall = false;
     nsID  param_iid;
     const nsXPTMethodInfo* info = static_cast<const nsXPTMethodInfo*>(info_);
     const char* name = info->name;
     bool foundDependentParam;
 
     // Make sure not to set the callee on ccx until after we've gone through
@@ -917,25 +935,26 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
     RootedObject obj(cx, wrapper->GetJSObject());
     RootedObject thisObj(cx, obj);
 
     JSAutoCompartment ac(cx, obj);
 
     AutoValueVector args(cx);
     AutoScriptEvaluate scriptEval(cx);
 
+    AutoSavePendingResult apr(xpcc);
+
     // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
     uint8_t paramCount = info->num_args;
     uint8_t argc = paramCount -
         (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0);
 
     if (!scriptEval.StartEvaluating(obj))
         goto pre_call_clean_up;
 
-    xpcc->SetPendingResult(pending_result);
     xpcc->SetException(nullptr);
     XPCJSRuntime::Get()->SetPendingException(nullptr);
 
     // We use js_Invoke so that the gcthings we use as args will be rooted by
     // the engine as we do conversions and prepare to do the function call.
 
     // setup stack
 
@@ -1398,17 +1417,17 @@ pre_call_clean_up:
                     nsMemory::Free(pp);
                 }
             } else
                 CleanupPointerTypeObject(type, (void**)p);
             *((void**)p) = nullptr;
         }
     } else {
         // set to whatever the JS code might have set as the result
-        retval = pending_result;
+        retval = xpcc->GetPendingResult();
     }
 
     return retval;
 }
 
 const char*
 nsXPCWrappedJSClass::GetInterfaceName()
 {
--- a/js/xpconnect/tests/components/js/Makefile.in
+++ b/js/xpconnect/tests/components/js/Makefile.in
@@ -5,14 +5,15 @@
 
 componentdir = js/xpconnect/tests/components/js
 
 JS_FILES := \
   xpctest_attributes.js \
   xpctest_bug809674.js \
   xpctest_interfaces.js \
   xpctest_params.js \
+  xpctest_returncode_child.js \
   xpctest.manifest \
   $(NULL)
 JS_DEST = $(testxpcobjdir)/$(componentdir)
 INSTALL_TARGETS += JS
 
 include $(topsrcdir)/config/rules.mk
--- a/js/xpconnect/tests/components/js/xpctest.manifest
+++ b/js/xpconnect/tests/components/js/xpctest.manifest
@@ -14,9 +14,12 @@ component {3c8fd2f5-970c-42c6-b5dd-cda1c
 contract @mozilla.org/js/xpc/test/js/InterfaceA;1 {3c8fd2f5-970c-42c6-b5dd-cda1c16dcfd8}
 
 component {ff528c3a-2410-46de-acaa-449aa6403a33} xpctest_interfaces.js
 contract @mozilla.org/js/xpc/test/js/InterfaceB;1 {ff528c3a-2410-46de-acaa-449aa6403a33}
 
 component {90ec5c9e-f6da-406b-9a38-14d00f59db76} xpctest_interfaces.js
 contract @mozilla.org/js/xpc/test/js/TestInterfaceAll;1 {90ec5c9e-f6da-406b-9a38-14d00f59db76}
 
+component {38dd78aa-467f-4fad-8dcf-4383a743e235} xpctest_returncode_child.js
+contract @mozilla.org/js/xpc/test/js/ReturnCodeChild;1 {38dd78aa-467f-4fad-8dcf-4383a743e235}
+
 interfaces xpctest.xpt
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/components/js/xpctest_returncode_child.js
@@ -0,0 +1,49 @@
+/* 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/. */
+const {interfaces: Ci, classes: Cc, utils: Cu, results: Cr} = Components;
+Cu.import("resource:///modules/XPCOMUtils.jsm");
+
+function TestReturnCodeChild() {}
+TestReturnCodeChild.prototype = {
+
+  /* Boilerplate */
+  QueryInterface: XPCOMUtils.generateQI([Ci["nsIXPCTestReturnCodeChild"]]),
+  contractID: "@mozilla.org/js/xpc/test/js/ReturnCodeChild;1",
+  classID: Components.ID("{38dd78aa-467f-4fad-8dcf-4383a743e235}"),
+
+  doIt(behaviour) {
+    switch (behaviour) {
+      case Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_THROW:
+        throw(new Error("a requested error"));
+      case Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_RETURN_SUCCESS:
+        return;
+      case Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_RETURN_RESULTCODE:
+        Components.returnCode = Cr.NS_ERROR_FAILURE;
+        return;
+      case Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_NEST_RESULTCODES:
+        // Use xpconnect to create another instance of *this* component and
+        // call that.  This way we have crossed the xpconnect bridge twice.
+
+        // We set *our* return code early - this should be what is returned
+        // to our caller, even though our "inner" component will set it to
+        // a different value that we will see (but our caller should not)
+        Components.returnCode = Cr.NS_ERROR_UNEXPECTED;
+        // call the child asking it to do the .returnCode set.
+        let sub = Cc[this.contractID].createInstance(Ci.nsIXPCTestReturnCodeChild);
+        let childResult = Cr.NS_OK;
+        try {
+          sub.doIt(Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_RETURN_RESULTCODE);
+        } catch (ex) {
+          childResult = ex.result;
+        }
+        // write it to the console so the test can check it.
+        let consoleService = Cc["@mozilla.org/consoleservice;1"]
+                             .getService(Ci.nsIConsoleService);
+        consoleService.logStringMessage("nested child returned " + childResult);
+        return;
+    }
+  }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestReturnCodeChild]);
--- a/js/xpconnect/tests/components/native/moz.build
+++ b/js/xpconnect/tests/components/native/moz.build
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 NO_DIST_INSTALL = True
 
 UNIFIED_SOURCES += [
     'xpctest_attributes.cpp',
     'xpctest_module.cpp',
     'xpctest_params.cpp',
+    'xpctest_returncode.cpp',
 ]
 
 XPCOMBinaryComponent('xpctest')
 
 DEFINES['LIBRARY_FILENAME'] = '%s%s%s' % (
     CONFIG['DLL_PREFIX'],
     LIBRARY_NAME,
     CONFIG['DLL_SUFFIX']
--- a/js/xpconnect/tests/components/native/xpctest_module.cpp
+++ b/js/xpconnect/tests/components/native/xpctest_module.cpp
@@ -16,34 +16,42 @@
 #define NS_XPCTESTOBJECTREADWRITE_CID                                         \
 { 0x8f37f760, 0x3686, 0x4dbb,                                                 \
    { 0xb1, 0x21, 0x96, 0x93, 0xba, 0x81, 0x3f, 0x8f } }
 
 #define NS_XPCTESTPARAMS_CID                                                  \
 { 0x1f11076a, 0x0fa2, 0x4f07,                                                 \
     { 0xb4, 0x7a, 0xa1, 0x54, 0x31, 0xf2, 0xce, 0xf7 } }
 
+#define NS_XPCTESTRETURNCODEPARENT_CID                                        \
+{ 0x3818f744, 0x5445, 0x4e9c,                                                 \
+    { 0x9b, 0xb8, 0x64, 0x62, 0xfe, 0x81, 0xb6, 0x19 } }
+
 NS_GENERIC_FACTORY_CONSTRUCTOR(xpcTestObjectReadOnly)
 NS_GENERIC_FACTORY_CONSTRUCTOR(xpcTestObjectReadWrite)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPCTestParams)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPCTestReturnCodeParent)
 NS_DEFINE_NAMED_CID(NS_XPCTESTOBJECTREADONLY_CID);
 NS_DEFINE_NAMED_CID(NS_XPCTESTOBJECTREADWRITE_CID);
 NS_DEFINE_NAMED_CID(NS_XPCTESTPARAMS_CID);
+NS_DEFINE_NAMED_CID(NS_XPCTESTRETURNCODEPARENT_CID);
 
 static const mozilla::Module::CIDEntry kXPCTestCIDs[] = {
     { &kNS_XPCTESTOBJECTREADONLY_CID, false, nullptr, xpcTestObjectReadOnlyConstructor },
     { &kNS_XPCTESTOBJECTREADWRITE_CID, false, nullptr, xpcTestObjectReadWriteConstructor },
     { &kNS_XPCTESTPARAMS_CID, false, nullptr, nsXPCTestParamsConstructor },
+    { &kNS_XPCTESTRETURNCODEPARENT_CID, false, nullptr, nsXPCTestReturnCodeParentConstructor },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kXPCTestContracts[] = {
     { "@mozilla.org/js/xpc/test/native/ObjectReadOnly;1", &kNS_XPCTESTOBJECTREADONLY_CID },
     { "@mozilla.org/js/xpc/test/native/ObjectReadWrite;1", &kNS_XPCTESTOBJECTREADWRITE_CID },
     { "@mozilla.org/js/xpc/test/native/Params;1", &kNS_XPCTESTPARAMS_CID },
+    { "@mozilla.org/js/xpc/test/native/ReturnCodeParent;1", &kNS_XPCTESTRETURNCODEPARENT_CID },
     { nullptr }
 };
 
 static const mozilla::Module kXPCTestModule = {
     mozilla::Module::kVersion,
     kXPCTestCIDs,
     kXPCTestContracts
 };
--- a/js/xpconnect/tests/components/native/xpctest_private.h
+++ b/js/xpconnect/tests/components/native/xpctest_private.h
@@ -9,16 +9,17 @@
 #ifndef xpctest_private_h___
 #define xpctest_private_h___
 
 #include "nsISupports.h"
 #include "nsMemory.h"
 #include "nsStringGlue.h"
 #include "xpctest_attributes.h"
 #include "xpctest_params.h"
+#include "xpctest_returncode.h"
 #include "mozilla/Attributes.h"
 
 class xpcTestObjectReadOnly MOZ_FINAL : public nsIXPCTestObjectReadOnly {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIXPCTESTOBJECTREADONLY
   xpcTestObjectReadOnly();
 
@@ -59,9 +60,21 @@ public:
     NS_DECL_NSIXPCTESTPARAMS
 
     nsXPCTestParams();
 
 private:
     ~nsXPCTestParams();
 };
 
+class nsXPCTestReturnCodeParent MOZ_FINAL : public nsIXPCTestReturnCodeParent
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIXPCTESTRETURNCODEPARENT
+
+    nsXPCTestReturnCodeParent();
+
+private:
+    ~nsXPCTestReturnCodeParent();
+};
+
 #endif /* xpctest_private_h___ */
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/components/native/xpctest_returncode.cpp
@@ -0,0 +1,28 @@
+/* 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 "xpctest_private.h"
+#include "xpctest_interfaces.h"
+#include "nsComponentManagerUtils.h"
+
+NS_IMPL_ISUPPORTS(nsXPCTestReturnCodeParent, nsIXPCTestReturnCodeParent)
+
+nsXPCTestReturnCodeParent::nsXPCTestReturnCodeParent()
+{
+}
+
+nsXPCTestReturnCodeParent::~nsXPCTestReturnCodeParent()
+{
+}
+
+/* unsigned long callChild (in long childBehavior); */
+NS_IMETHODIMP nsXPCTestReturnCodeParent::CallChild(int32_t childBehavior, nsresult *_retval)
+{
+    nsresult rv;
+    nsCOMPtr<nsIXPCTestReturnCodeChild> child(do_CreateInstance("@mozilla.org/js/xpc/test/js/ReturnCodeChild;1", &rv));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = child->DoIt(childBehavior);
+    *_retval = rv;
+    return NS_OK;
+}
--- a/js/xpconnect/tests/idl/moz.build
+++ b/js/xpconnect/tests/idl/moz.build
@@ -4,12 +4,13 @@
 # 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/.
 
 XPIDL_SOURCES += [
     'xpctest_attributes.idl',
     'xpctest_bug809674.idl',
     'xpctest_interfaces.idl',
     'xpctest_params.idl',
+    'xpctest_returncode.idl',
 ]
 
 XPIDL_MODULE = 'xpctest'
 
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/idl/xpctest_returncode.idl
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * 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/. */
+
+/**
+ * Test the use of Components.returnCode
+ *
+ * This ("parent") interface defines a method that in-turn calls another
+ * ("child") interface implemented in JS, and returns the nsresult from that
+ * child interface.  The child interface manages the return code by way of
+ * Components.returnCode.
+ */
+
+#include "nsISupports.idl"
+
+
+[scriptable, uuid(479e4532-95cf-48b8-a99b-8a5881e47138)]
+interface nsIXPCTestReturnCodeParent : nsISupports {
+  // Calls the "child" interface with the specified behavior flag.  Returns
+  // the NSRESULT from the child interface.
+  nsresult        callChild(in long childBehavior);
+};
+
+[scriptable, uuid(672cfd34-1fd1-455d-9901-d879fa6fdb95)]
+interface nsIXPCTestReturnCodeChild : nsISupports {
+  void doIt(in long behavior);
+
+  // Flags to control that the child does.
+  // child will throw a JS exception
+  const long CHILD_SHOULD_THROW = 0;
+
+  // child will just return normally
+  const long CHILD_SHOULD_RETURN_SUCCESS = 1;
+
+  // child will return after setting Components.returnCode to NS_ERROR_FAILURE
+  const long CHILD_SHOULD_RETURN_RESULTCODE = 2;
+
+  // child will set Components.returnCode to NS_ERROR_UNEXPECTED, then create
+  // a new component that sets Components.returnCode to NS_ERROR_FAILURE.
+  // Our caller should see the NS_ERROR_UNEXPECTED we set rather than the
+  // value set later by the "inner" child.
+  const long CHILD_SHOULD_NEST_RESULTCODES = 3;
+};
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_returncode.js
@@ -0,0 +1,78 @@
+/* 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/. */
+
+const {interfaces: Ci, classes: Cc, utils: Cu, manager: Cm, results: Cr} = Components;
+
+Cu.import("resource:///modules/XPCOMUtils.jsm");
+
+function getConsoleMessages() {
+  let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
+  let messages = [m.toString() for (m of consoleService.getMessageArray())];
+  // reset ready for the next call.
+  consoleService.reset();
+  return messages;
+}
+
+function run_test() {
+  // Load the component manifests.
+  Cm.autoRegister(do_get_file('../components/native/xpctest.manifest'));
+  Cm.autoRegister(do_get_file('../components/js/xpctest.manifest'));
+
+  // and the tests.
+  test_simple();
+  test_nested();
+}
+
+function test_simple() {
+  let parent = Cc["@mozilla.org/js/xpc/test/native/ReturnCodeParent;1"]
+               .createInstance(Ci.nsIXPCTestReturnCodeParent);
+  let result;
+
+  // flush existing messages before we start testing.
+  getConsoleMessages();
+
+  // Ask the C++ to call the JS object which will throw.
+  result = parent.callChild(Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_THROW);
+  Assert.equal(result, Cr.NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS,
+               "exception caused NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS");
+
+  let messages = getConsoleMessages();
+  Assert.equal(messages.length, 1, "got a console message from the exception");
+  Assert.ok(messages[0].indexOf("a requested error") != -1, "got the message text");
+
+  // Ask the C++ to call the JS object which will return success.
+  result = parent.callChild(Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_RETURN_SUCCESS);
+  Assert.equal(result, Cr.NS_OK, "success is success");
+
+  Assert.deepEqual(getConsoleMessages(), [], "no messages reported on success.");
+
+  // And finally the point of this test!
+  // Ask the C++ to call the JS object which will use .returnCode
+  result = parent.callChild(Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_RETURN_RESULTCODE);
+  Assert.equal(result, Cr.NS_ERROR_FAILURE,
+               "NS_ERROR_FAILURE was seen as the error code.");
+
+  Assert.deepEqual(getConsoleMessages(), [], "no messages reported with .returnCode");
+}
+
+function test_nested() {
+  let parent = Cc["@mozilla.org/js/xpc/test/native/ReturnCodeParent;1"]
+               .createInstance(Ci.nsIXPCTestReturnCodeParent);
+  let result;
+
+  // flush existing messages before we start testing.
+  getConsoleMessages();
+
+  // Ask the C++ to call the "outer" JS object, which will set .returnCode, but
+  // then create and call *another* component which itself sets the .returnCode
+  // to a different value.  This checks the returnCode is correctly saved
+  // across call contexts.
+  result = parent.callChild(Ci.nsIXPCTestReturnCodeChild.CHILD_SHOULD_NEST_RESULTCODES);
+  Assert.equal(result, Cr.NS_ERROR_UNEXPECTED,
+               "NS_ERROR_UNEXPECTED was seen as the error code.");
+  // We expect one message, which is the child reporting what it got as the
+  // return code - which should be NS_ERROR_FAILURE
+  let expected = ["nested child returned " + Cr.NS_ERROR_FAILURE];
+  Assert.deepEqual(getConsoleMessages(), expected, "got the correct sub-error");
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -80,16 +80,17 @@ fail-if = os == "android"
 [test_want_components.js]
 [test_components.js]
 [test_allowedDomains.js]
 [test_allowedDomainsXHR.js]
 [test_nuke_sandbox.js]
 [test_sandbox_metadata.js]
 [test_exportFunction.js]
 [test_promise.js]
+[test_returncode.js]
 [test_textDecoder.js]
 [test_url.js]
 [test_URLSearchParams.js]
 [test_css.js]
 [test_sandbox_atob.js]
 [test_isProxy.js]
 [test_getObjectPrincipal.js]
 [test_watchdog_enable.js]