Bug 988122 - Expose Promise on non-window non-worker globals. r=bholley sr=bz
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Sat, 29 Mar 2014 15:55:53 +0900
changeset 176035 fc8a8379714c8f6751d24893d7e4561cc8248bf0
parent 176034 e45db0a68b4f805d3beefbd3d1c1a0b1f501f4a3
child 176036 b93c9a7e21a574532eab52045a71292ab845ac9b
push id26505
push userphilringnalda@gmail.com
push dateSat, 29 Mar 2014 16:01:43 +0000
treeherdermozilla-central@8da3aabb044f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley, bz
bugs988122
milestone31.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 988122 - Expose Promise on non-window non-worker globals. r=bholley sr=bz
dom/contacts/tests/test_migration_chrome.js
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/tests/unit/test_promise.js
js/xpconnect/tests/unit/xpcshell.ini
toolkit/devtools/tests/unit/test_async-utils.js
--- a/dom/contacts/tests/test_migration_chrome.js
+++ b/dom/contacts/tests/test_migration_chrome.js
@@ -9,24 +9,28 @@ const {classes: Cc, interfaces: Ci, util
 
 let imports = {};
 
 Cu.import("resource://gre/modules/ContactDB.jsm", imports);
 Cu.import("resource://gre/modules/ContactService.jsm", imports);
 Cu.import("resource://gre/modules/Promise.jsm", imports);
 Cu.importGlobalProperties(["indexedDB"]);
 
-const {
+// |const| will not work because
+// it will make the Promise object immutable before assigning.
+// Using |let| and Object.freeze() instead.
+let {
   STORE_NAME,
   SAVED_GETALL_STORE_NAME,
   REVISION_STORE,
   DB_NAME,
   ContactService,
   Promise
 } = imports;
+Object.freeze(imports);
 
 let DEBUG = false;
 function debug(str) {
   if (DEBUG){
     dump("-*- TestMigrationChromeScript: " + str + "\n");
   }
 }
 
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -26,16 +26,17 @@
 #include "nsXMLHttpRequest.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 #include "XPCWrapper.h"
 #include "XrayWrapper.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
+#include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/URLBinding.h"
 
 using namespace mozilla;
 using namespace JS;
 using namespace js;
 using namespace xpc;
@@ -969,27 +970,30 @@ xpc::SandboxProxyHandler::iterate(JSCont
 bool
 xpc::GlobalProperties::Parse(JSContext *cx, JS::HandleObject obj)
 {
     MOZ_ASSERT(JS_IsArrayObject(cx, obj));
 
     uint32_t length;
     bool ok = JS_GetArrayLength(cx, obj, &length);
     NS_ENSURE_TRUE(ok, false);
+    bool promise = Promise;
     for (uint32_t i = 0; i < length; i++) {
         RootedValue nameValue(cx);
         ok = JS_GetElement(cx, obj, i, &nameValue);
         NS_ENSURE_TRUE(ok, false);
         if (!nameValue.isString()) {
             JS_ReportError(cx, "Property names must be strings");
             return false;
         }
         JSAutoByteString name(cx, nameValue.toString());
         NS_ENSURE_TRUE(name, false);
-        if (!strcmp(name.ptr(), "indexedDB")) {
+        if (promise && !strcmp(name.ptr(), "-Promise")) {
+            Promise = false;
+        } else if (!strcmp(name.ptr(), "indexedDB")) {
             indexedDB = true;
         } else if (!strcmp(name.ptr(), "XMLHttpRequest")) {
             XMLHttpRequest = true;
         } else if (!strcmp(name.ptr(), "TextEncoder")) {
             TextEncoder = true;
         } else if (!strcmp(name.ptr(), "TextDecoder")) {
             TextDecoder = true;
         } else if (!strcmp(name.ptr(), "URL")) {
@@ -1004,16 +1008,19 @@ xpc::GlobalProperties::Parse(JSContext *
         }
     }
     return true;
 }
 
 bool
 xpc::GlobalProperties::Define(JSContext *cx, JS::HandleObject obj)
 {
+    if (Promise && !dom::PromiseBinding::GetConstructorObject(cx, obj))
+        return false;
+
     if (indexedDB && AccessCheck::isChrome(obj) &&
         !IndexedDatabaseManager::DefineIndexedDB(cx, obj))
         return false;
 
     if (XMLHttpRequest &&
         !JS_DefineFunction(cx, obj, "XMLHttpRequest", CreateXMLHttpRequest, 0, JSFUN_CONSTRUCTOR))
         return false;
 
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2751,17 +2751,17 @@ nsXPCComponents_Utils::Unload(const nsAC
  * JSObject importGlobalProperties (in jsval aPropertyList);
  */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ImportGlobalProperties(HandleValue aPropertyList,
                                               JSContext* cx)
 {
     RootedObject global(cx, CurrentGlobalOrNull(cx));
     MOZ_ASSERT(global);
-    GlobalProperties options;
+    GlobalProperties options(false);
     NS_ENSURE_TRUE(aPropertyList.isObject(), NS_ERROR_INVALID_ARG);
     RootedObject propertyList(cx, &aPropertyList.toObject());
     NS_ENSURE_TRUE(JS_IsArrayObject(cx, propertyList), NS_ERROR_INVALID_ARG);
     if (!options.Parse(cx, propertyList) ||
         !options.Define(cx, global))
     {
         return NS_ERROR_FAILURE;
     }
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -25,35 +25,33 @@
 #ifdef MOZ_JSDEBUGGER
 #include "jsdIDebuggerService.h"
 #endif
 
 #include "XPCQuickStubs.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Exceptions.h"
-#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
+#include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/DOMErrorBinding.h"
 
 #include "nsDOMMutationObserver.h"
 #include "nsICycleCollectorListener.h"
 #include "nsThread.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace xpc;
 using namespace JS;
 
-using mozilla::dom::indexedDB::IndexedDatabaseManager;
-
 NS_IMPL_ISUPPORTS4(nsXPConnect,
                    nsIXPConnect,
                    nsISupportsWeakReference,
                    nsIThreadObserver,
                    nsIJSRuntimeService)
 
 nsXPConnect* nsXPConnect::gSelf = nullptr;
 bool         nsXPConnect::gOnceAliveNowDead = false;
@@ -448,17 +446,18 @@ nsXPConnect::InitClassesWithNewWrappedGl
     // XXX Someone who knows why we can assert this should re-check
     //     (after bug 720580).
     MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL);
 
     // Init WebIDL binding constructors wanted on all XPConnect globals.
     //
     // XXX Please do not add any additional classes here without the approval of
     //     the XPConnect module owner.
-    if (!TextDecoderBinding::GetConstructorObject(aJSContext, global) ||
+    if (!PromiseBinding::GetConstructorObject(aJSContext, global) ||
+        !TextDecoderBinding::GetConstructorObject(aJSContext, global) ||
         !TextEncoderBinding::GetConstructorObject(aJSContext, global) ||
         !DOMErrorBinding::GetConstructorObject(aJSContext, global)) {
         return UnexpectedFailure(NS_ERROR_FAILURE);
     }
 
     wrappedGlobal.forget(_retval);
     return NS_OK;
 }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3284,19 +3284,23 @@ bool
 NewFunctionForwarder(JSContext *cx, JS::HandleObject callable,
                      bool doclone, JS::MutableHandleValue vp);
 
 // Old fashioned xpc error reporter. Try to use JS_ReportError instead.
 nsresult
 ThrowAndFail(nsresult errNum, JSContext *cx, bool *retval);
 
 struct GlobalProperties {
-    GlobalProperties() { mozilla::PodZero(this); }
+    GlobalProperties(bool aPromise) {
+      mozilla::PodZero(this);
+      Promise = true;
+    }
     bool Parse(JSContext *cx, JS::HandleObject obj);
     bool Define(JSContext *cx, JS::HandleObject obj);
+    bool Promise : 1;
     bool indexedDB : 1;
     bool XMLHttpRequest : 1;
     bool TextDecoder : 1;
     bool TextEncoder : 1;
     bool URL : 1;
     bool atob : 1;
     bool btoa : 1;
 };
@@ -3337,16 +3341,17 @@ public:
                    JSObject *options = nullptr)
         : OptionsBase(cx, options)
         , wantXrays(true)
         , wantComponents(true)
         , wantExportHelpers(false)
         , proto(cx)
         , sameZoneAs(cx)
         , invisibleToDebugger(false)
+        , globalProperties(true)
         , metadata(cx)
     { }
 
     virtual bool Parse();
 
     bool wantXrays;
     bool wantComponents;
     bool wantExportHelpers;
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_promise.js
@@ -0,0 +1,12 @@
+function run_test() {
+  var Cu = Components.utils;
+  sb = new Cu.Sandbox('http://www.example.com');
+  sb.do_check_eq = do_check_eq;
+  Cu.evalInSandbox('do_check_eq(typeof new Promise(function(resolve){resolve();}), "object");',
+                   sb);
+  sb = new Cu.Sandbox('http://www.example.com',
+                      { wantGlobalProperties: ["-Promise"] });
+  sb.do_check_eq = do_check_eq;
+  Cu.evalInSandbox('do_check_eq(typeof Promise, "undefined");', sb);
+  do_check_eq(typeof new Promise(function(resolve){resolve();}), "object");
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -65,16 +65,17 @@ fail-if = os == "android"
 [test_tearoffs.js]
 [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_textDecoder.js]
 [test_url.js]
 [test_sandbox_atob.js]
 [test_isProxy.js]
 [test_getObjectPrincipal.js]
 [test_watchdog_enable.js]
 head = head_watchdog.js
 [test_watchdog_disable.js]
--- a/toolkit/devtools/tests/unit/test_async-utils.js
+++ b/toolkit/devtools/tests/unit/test_async-utils.js
@@ -1,16 +1,20 @@
 /* -*- Mode: js; js-indent-level: 2; -*- */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test async-utils.js
 
 const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
-const {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
+// |const| will not work because
+// it will make the Promise object immutable before assigning.
+// Using |let| and Object.freeze() instead.
+let {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
+Object.freeze(Promise);
 const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 const {async, asyncOnce, promiseInvoke, promiseCall} = require("devtools/async-utils");
 
 function run_test() {
   do_test_pending();
   Task.spawn(function*() {
     for (let helper of [async, asyncOnce]) {
       yield test_async_args(helper);