Wrap promise implementation in a function.
authoryangguo <yangguo@chromium.org>
Tue, 21 Apr 2015 14:39:09 +0000 (07:39 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 21 Apr 2015 14:38:53 +0000 (14:38 +0000)
R=mvstanton@chromium.org

Review URL: https://codereview.chromium.org/1054763003

Cr-Commit-Position: refs/heads/master@{#27969}

src/bootstrapper.cc
src/debug.cc
src/mirror-debugger.js
src/promise.js

index e11aff6..cb9bdfa 100644 (file)
@@ -1559,13 +1559,13 @@ void Genesis::InstallNativeFunctions() {
   INSTALL_NATIVE(JSFunction, "ToCompletePropertyDescriptor",
                  to_complete_property_descriptor);
 
-  INSTALL_NATIVE(Symbol, "promiseStatus", promise_status);
-  INSTALL_NATIVE(JSFunction, "PromiseCreate", promise_create);
-  INSTALL_NATIVE(JSFunction, "PromiseResolve", promise_resolve);
-  INSTALL_NATIVE(JSFunction, "PromiseReject", promise_reject);
-  INSTALL_NATIVE(JSFunction, "PromiseChain", promise_chain);
-  INSTALL_NATIVE(JSFunction, "PromiseCatch", promise_catch);
-  INSTALL_NATIVE(JSFunction, "PromiseThen", promise_then);
+  INSTALL_NATIVE(Symbol, "$promiseStatus", promise_status);
+  INSTALL_NATIVE(JSFunction, "$promiseCreate", promise_create);
+  INSTALL_NATIVE(JSFunction, "$promiseResolve", promise_resolve);
+  INSTALL_NATIVE(JSFunction, "$promiseReject", promise_reject);
+  INSTALL_NATIVE(JSFunction, "$promiseChain", promise_chain);
+  INSTALL_NATIVE(JSFunction, "$promiseCatch", promise_catch);
+  INSTALL_NATIVE(JSFunction, "$promiseThen", promise_then);
 
   INSTALL_NATIVE(JSFunction, "$observeNotifyChange", observers_notify_change);
   INSTALL_NATIVE(JSFunction, "$observeEnqueueSpliceRecord",
index 49700ee..7b64f2f 100644 (file)
@@ -2518,7 +2518,7 @@ MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler(
   Handle<JSFunction> fun = Handle<JSFunction>::cast(
       JSObject::GetDataProperty(isolate_->js_builtins_object(),
                                 isolate_->factory()->NewStringFromStaticChars(
-                                    "PromiseHasUserDefinedRejectHandler")));
+                                    "$promiseHasUserDefinedRejectHandler")));
   return Execution::Call(isolate_, fun, promise, 0, NULL);
 }
 
index b329f81..0fffd61 100644 (file)
@@ -25,7 +25,7 @@ function ToggleMirrorCache(value) {
 function ObjectIsPromise(value) {
   try {
     return IS_SPEC_OBJECT(value) &&
-           !IS_UNDEFINED(%DebugGetProperty(value, builtins.promiseStatus));
+           !IS_UNDEFINED(%DebugGetProperty(value, builtins.$promiseStatus));
   } catch (e) {
     return false;
   }
@@ -1335,7 +1335,7 @@ inherits(PromiseMirror, ObjectMirror);
 
 
 function PromiseGetStatus_(value) {
-  var status = %DebugGetProperty(value, builtins.promiseStatus);
+  var status = %DebugGetProperty(value, builtins.$promiseStatus);
   if (status == 0) return "pending";
   if (status == 1) return "resolved";
   return "rejected";
@@ -1343,7 +1343,7 @@ function PromiseGetStatus_(value) {
 
 
 function PromiseGetValue_(value) {
-  return %DebugGetProperty(value, builtins.promiseValue);
+  return %DebugGetProperty(value, builtins.$promiseValue);
 }
 
 
index ba0dfe0..6fc7c73 100644 (file)
@@ -2,27 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-"use strict";
+var $promiseCreate;
+var $promiseResolve;
+var $promiseReject;
+var $promiseChain;
+var $promiseCatch;
+var $promiseThen;
+var $promiseHasUserDefinedRejectHandler;
+var $promiseStatus;
+var $promiseValue;
 
-// This file relies on the fact that the following declaration has been made
-// in runtime.js:
-// var $Object = global.Object
+(function() {
 
-// For bootstrapper.
+"use strict";
 
-var IsPromise;
-var PromiseCreate;
-var PromiseResolve;
-var PromiseReject;
-var PromiseChain;
-var PromiseCatch;
-var PromiseThen;
-var PromiseHasRejectHandler;
-var PromiseHasUserDefinedRejectHandler;
+%CheckIsBootstrapping();
 
-// mirror-debugger.js currently uses builtins.promiseStatus. It would be nice
-// if we could move these property names into the closure below.
-// TODO(jkummerow/rossberg/yangguo): Find a better solution.
+// -------------------------------------------------------------------
 
 // Status values: 0 = pending, +1 = resolved, -1 = rejected
 var promiseStatus = GLOBAL_PRIVATE("Promise#status");
@@ -33,360 +29,366 @@ var promiseRaw = GLOBAL_PRIVATE("Promise#raw");
 var promiseHasHandler = %PromiseHasHandlerSymbol();
 var lastMicrotaskId = 0;
 
-
-(function() {
-
-  var $Promise = function Promise(resolver) {
-    if (resolver === promiseRaw) return;
-    if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]);
-    if (!IS_SPEC_FUNCTION(resolver))
-      throw MakeTypeError('resolver_not_a_function', [resolver]);
-    var promise = PromiseInit(this);
-    try {
-      %DebugPushPromise(promise, Promise);
-      resolver(function(x) { PromiseResolve(promise, x) },
-               function(r) { PromiseReject(promise, r) });
-    } catch (e) {
-      PromiseReject(promise, e);
-    } finally {
-      %DebugPopPromise();
-    }
+var GlobalPromise = function Promise(resolver) {
+  if (resolver === promiseRaw) return;
+  if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]);
+  if (!IS_SPEC_FUNCTION(resolver))
+    throw MakeTypeError('resolver_not_a_function', [resolver]);
+  var promise = PromiseInit(this);
+  try {
+    %DebugPushPromise(promise, Promise);
+    resolver(function(x) { PromiseResolve(promise, x) },
+             function(r) { PromiseReject(promise, r) });
+  } catch (e) {
+    PromiseReject(promise, e);
+  } finally {
+    %DebugPopPromise();
   }
+}
 
-  // Core functionality.
-
-  function PromiseSet(promise, status, value, onResolve, onReject) {
-    SET_PRIVATE(promise, promiseStatus, status);
-    SET_PRIVATE(promise, promiseValue, value);
-    SET_PRIVATE(promise, promiseOnResolve, onResolve);
-    SET_PRIVATE(promise, promiseOnReject, onReject);
-    if (DEBUG_IS_ACTIVE) {
-      %DebugPromiseEvent({ promise: promise, status: status, value: value });
-    }
-    return promise;
-  }
+// Core functionality.
 
-  function PromiseCreateAndSet(status, value) {
-    var promise = new $Promise(promiseRaw);
-    // If debug is active, notify about the newly created promise first.
-    if (DEBUG_IS_ACTIVE) PromiseSet(promise, 0, UNDEFINED);
-    return PromiseSet(promise, status, value);
+function PromiseSet(promise, status, value, onResolve, onReject) {
+  SET_PRIVATE(promise, promiseStatus, status);
+  SET_PRIVATE(promise, promiseValue, value);
+  SET_PRIVATE(promise, promiseOnResolve, onResolve);
+  SET_PRIVATE(promise, promiseOnReject, onReject);
+  if (DEBUG_IS_ACTIVE) {
+    %DebugPromiseEvent({ promise: promise, status: status, value: value });
   }
-
-  function PromiseInit(promise) {
-    return PromiseSet(
-        promise, 0, UNDEFINED, new InternalArray, new InternalArray)
+  return promise;
+}
+
+function PromiseCreateAndSet(status, value) {
+  var promise = new GlobalPromise(promiseRaw);
+  // If debug is active, notify about the newly created promise first.
+  if (DEBUG_IS_ACTIVE) PromiseSet(promise, 0, UNDEFINED);
+  return PromiseSet(promise, status, value);
+}
+
+function PromiseInit(promise) {
+  return PromiseSet(
+      promise, 0, UNDEFINED, new InternalArray, new InternalArray)
+}
+
+function PromiseDone(promise, status, value, promiseQueue) {
+  if (GET_PRIVATE(promise, promiseStatus) === 0) {
+    var tasks = GET_PRIVATE(promise, promiseQueue);
+    if (tasks.length) PromiseEnqueue(value, tasks, status);
+    PromiseSet(promise, status, value);
   }
+}
 
-  function PromiseDone(promise, status, value, promiseQueue) {
-    if (GET_PRIVATE(promise, promiseStatus) === 0) {
-      var tasks = GET_PRIVATE(promise, promiseQueue);
-      if (tasks.length) PromiseEnqueue(value, tasks, status);
-      PromiseSet(promise, status, value);
+function PromiseCoerce(constructor, x) {
+  if (!IsPromise(x) && IS_SPEC_OBJECT(x)) {
+    var then;
+    try {
+      then = x.then;
+    } catch(r) {
+      return %_CallFunction(constructor, r, PromiseRejected);
     }
-  }
-
-  function PromiseCoerce(constructor, x) {
-    if (!IsPromise(x) && IS_SPEC_OBJECT(x)) {
-      var then;
+    if (IS_SPEC_FUNCTION(then)) {
+      var deferred = %_CallFunction(constructor, PromiseDeferred);
       try {
-        then = x.then;
+        %_CallFunction(x, deferred.resolve, deferred.reject, then);
       } catch(r) {
-        return %_CallFunction(constructor, r, PromiseRejected);
-      }
-      if (IS_SPEC_FUNCTION(then)) {
-        var deferred = %_CallFunction(constructor, PromiseDeferred);
-        try {
-          %_CallFunction(x, deferred.resolve, deferred.reject, then);
-        } catch(r) {
-          deferred.reject(r);
-        }
-        return deferred.promise;
+        deferred.reject(r);
       }
+      return deferred.promise;
     }
-    return x;
   }
-
-  function PromiseHandle(value, handler, deferred) {
-    try {
-      %DebugPushPromise(deferred.promise, PromiseHandle);
-      DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler);
-      var result = handler(value);
-      if (result === deferred.promise)
-        throw MakeTypeError('promise_cyclic', [result]);
-      else if (IsPromise(result))
-        %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
-      else
-        deferred.resolve(result);
-    } catch (exception) {
-      try { deferred.reject(exception); } catch (e) { }
-    } finally {
-      %DebugPopPromise();
-    }
+  return x;
+}
+
+function PromiseHandle(value, handler, deferred) {
+  try {
+    %DebugPushPromise(deferred.promise, PromiseHandle);
+    DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler);
+    var result = handler(value);
+    if (result === deferred.promise)
+      throw MakeTypeError('promise_cyclic', [result]);
+    else if (IsPromise(result))
+      %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
+    else
+      deferred.resolve(result);
+  } catch (exception) {
+    try { deferred.reject(exception); } catch (e) { }
+  } finally {
+    %DebugPopPromise();
   }
+}
 
-  function PromiseEnqueue(value, tasks, status) {
-    var id, name, instrumenting = DEBUG_IS_ACTIVE;
-    %EnqueueMicrotask(function() {
-      if (instrumenting) {
-        %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
-      }
-      for (var i = 0; i < tasks.length; i += 2) {
-        PromiseHandle(value, tasks[i], tasks[i + 1])
-      }
-      if (instrumenting) {
-        %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
-      }
-    });
+function PromiseEnqueue(value, tasks, status) {
+  var id, name, instrumenting = DEBUG_IS_ACTIVE;
+  %EnqueueMicrotask(function() {
     if (instrumenting) {
-      id = ++lastMicrotaskId;
-      name = status > 0 ? "Promise.resolve" : "Promise.reject";
-      %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
+      %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
     }
+    for (var i = 0; i < tasks.length; i += 2) {
+      PromiseHandle(value, tasks[i], tasks[i + 1])
+    }
+    if (instrumenting) {
+      %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
+    }
+  });
+  if (instrumenting) {
+    id = ++lastMicrotaskId;
+    name = status > 0 ? "Promise.resolve" : "Promise.reject";
+    %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
   }
+}
 
-  function PromiseIdResolveHandler(x) { return x }
-  function PromiseIdRejectHandler(r) { throw r }
-
-  function PromiseNopResolver() {}
-
-  // -------------------------------------------------------------------
-  // Define exported functions.
-
-  // For bootstrapper.
-
-  IsPromise = function IsPromise(x) {
-    return IS_SPEC_OBJECT(x) && HAS_DEFINED_PRIVATE(x, promiseStatus);
-  }
-
-  PromiseCreate = function PromiseCreate() {
-    return new $Promise(PromiseNopResolver)
-  }
+function PromiseIdResolveHandler(x) { return x }
+function PromiseIdRejectHandler(r) { throw r }
 
-  PromiseResolve = function PromiseResolve(promise, x) {
-    PromiseDone(promise, +1, x, promiseOnResolve)
-  }
+function PromiseNopResolver() {}
 
-  PromiseReject = function PromiseReject(promise, r) {
-    // Check promise status to confirm that this reject has an effect.
-    // Call runtime for callbacks to the debugger or for unhandled reject.
-    if (GET_PRIVATE(promise, promiseStatus) == 0) {
-      var debug_is_active = DEBUG_IS_ACTIVE;
-      if (debug_is_active || !HAS_DEFINED_PRIVATE(promise, promiseHasHandler)) {
-        %PromiseRejectEvent(promise, r, debug_is_active);
-      }
-    }
-    PromiseDone(promise, -1, r, promiseOnReject)
-  }
+// -------------------------------------------------------------------
+// Define exported functions.
 
-  // Convenience.
-
-  function PromiseDeferred() {
-    if (this === $Promise) {
-      // Optimized case, avoid extra closure.
-      var promise = PromiseInit(new $Promise(promiseRaw));
-      return {
-        promise: promise,
-        resolve: function(x) { PromiseResolve(promise, x) },
-        reject: function(r) { PromiseReject(promise, r) }
-      };
-    } else {
-      var result = {};
-      result.promise = new this(function(resolve, reject) {
-        result.resolve = resolve;
-        result.reject = reject;
-      })
-      return result;
-    }
-  }
+// For bootstrapper.
 
-  function PromiseResolved(x) {
-    if (this === $Promise) {
-      // Optimized case, avoid extra closure.
-      return PromiseCreateAndSet(+1, x);
-    } else {
-      return new this(function(resolve, reject) { resolve(x) });
+function IsPromise(x) {
+  return IS_SPEC_OBJECT(x) && HAS_DEFINED_PRIVATE(x, promiseStatus);
+}
+
+function PromiseCreate() {
+  return new GlobalPromise(PromiseNopResolver)
+}
+
+function PromiseResolve(promise, x) {
+  PromiseDone(promise, +1, x, promiseOnResolve)
+}
+
+function PromiseReject(promise, r) {
+  // Check promise status to confirm that this reject has an effect.
+  // Call runtime for callbacks to the debugger or for unhandled reject.
+  if (GET_PRIVATE(promise, promiseStatus) == 0) {
+    var debug_is_active = DEBUG_IS_ACTIVE;
+    if (debug_is_active || !HAS_DEFINED_PRIVATE(promise, promiseHasHandler)) {
+      %PromiseRejectEvent(promise, r, debug_is_active);
     }
   }
-
-  function PromiseRejected(r) {
-    var promise;
-    if (this === $Promise) {
-      // Optimized case, avoid extra closure.
-      promise = PromiseCreateAndSet(-1, r);
-      // The debug event for this would always be an uncaught promise reject,
-      // which is usually simply noise. Do not trigger that debug event.
-      %PromiseRejectEvent(promise, r, false);
-    } else {
-      promise = new this(function(resolve, reject) { reject(r) });
-    }
-    return promise;
+  PromiseDone(promise, -1, r, promiseOnReject)
+}
+
+// Convenience.
+
+function PromiseDeferred() {
+  if (this === GlobalPromise) {
+    // Optimized case, avoid extra closure.
+    var promise = PromiseInit(new GlobalPromise(promiseRaw));
+    return {
+      promise: promise,
+      resolve: function(x) { PromiseResolve(promise, x) },
+      reject: function(r) { PromiseReject(promise, r) }
+    };
+  } else {
+    var result = {};
+    result.promise = new this(function(resolve, reject) {
+      result.resolve = resolve;
+      result.reject = reject;
+    })
+    return result;
   }
-
-  // Simple chaining.
-
-  PromiseChain = function PromiseChain(onResolve, onReject) {  // a.k.a.
-                                                               // flatMap
-    onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
-    onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
-    var deferred = %_CallFunction(this.constructor, PromiseDeferred);
-    switch (GET_PRIVATE(this, promiseStatus)) {
-      case UNDEFINED:
-        throw MakeTypeError('not_a_promise', [this]);
-      case 0:  // Pending
-        GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
-        GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
-        break;
-      case +1:  // Resolved
-        PromiseEnqueue(GET_PRIVATE(this, promiseValue),
-                       [onResolve, deferred],
-                       +1);
-        break;
-      case -1:  // Rejected
-        if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
-          // Promise has already been rejected, but had no handler.
-          // Revoke previously triggered reject event.
-          %PromiseRevokeReject(this);
-        }
-        PromiseEnqueue(GET_PRIVATE(this, promiseValue),
-                       [onReject, deferred],
-                       -1);
-        break;
-    }
-    // Mark this promise as having handler.
-    SET_PRIVATE(this, promiseHasHandler, true);
-    if (DEBUG_IS_ACTIVE) {
-      %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
-    }
-    return deferred.promise;
+}
+
+function PromiseResolved(x) {
+  if (this === GlobalPromise) {
+    // Optimized case, avoid extra closure.
+    return PromiseCreateAndSet(+1, x);
+  } else {
+    return new this(function(resolve, reject) { resolve(x) });
   }
-
-  PromiseCatch = function PromiseCatch(onReject) {
-    return this.then(UNDEFINED, onReject);
+}
+
+function PromiseRejected(r) {
+  var promise;
+  if (this === GlobalPromise) {
+    // Optimized case, avoid extra closure.
+    promise = PromiseCreateAndSet(-1, r);
+    // The debug event for this would always be an uncaught promise reject,
+    // which is usually simply noise. Do not trigger that debug event.
+    %PromiseRejectEvent(promise, r, false);
+  } else {
+    promise = new this(function(resolve, reject) { reject(r) });
   }
-
-  // Multi-unwrapped chaining with thenable coercion.
-
-  PromiseThen = function PromiseThen(onResolve, onReject) {
-    onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve
-                                            : PromiseIdResolveHandler;
-    onReject = IS_SPEC_FUNCTION(onReject) ? onReject
-                                          : PromiseIdRejectHandler;
-    var that = this;
-    var constructor = this.constructor;
-    return %_CallFunction(
-      this,
-      function(x) {
-        x = PromiseCoerce(constructor, x);
-        if (x === that) {
-          DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject);
-          return onReject(MakeTypeError('promise_cyclic', [x]));
-        } else if (IsPromise(x)) {
-          return x.then(onResolve, onReject);
-        } else {
-          DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve);
-          return onResolve(x);
-        }
-      },
-      onReject,
-      PromiseChain
-    );
+  return promise;
+}
+
+// Simple chaining.
+
+function PromiseChain(onResolve, onReject) {  // a.k.a. flatMap
+  onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
+  onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
+  var deferred = %_CallFunction(this.constructor, PromiseDeferred);
+  switch (GET_PRIVATE(this, promiseStatus)) {
+    case UNDEFINED:
+      throw MakeTypeError('not_a_promise', [this]);
+    case 0:  // Pending
+      GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
+      GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
+      break;
+    case +1:  // Resolved
+      PromiseEnqueue(GET_PRIVATE(this, promiseValue),
+                     [onResolve, deferred],
+                     +1);
+      break;
+    case -1:  // Rejected
+      if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
+        // Promise has already been rejected, but had no handler.
+        // Revoke previously triggered reject event.
+        %PromiseRevokeReject(this);
+      }
+      PromiseEnqueue(GET_PRIVATE(this, promiseValue),
+                     [onReject, deferred],
+                     -1);
+      break;
   }
-
-  // Combinators.
-
-  function PromiseCast(x) {
-    // TODO(rossberg): cannot do better until we support @@create.
-    return IsPromise(x) ? x : new this(function(resolve) { resolve(x) });
+  // Mark this promise as having handler.
+  SET_PRIVATE(this, promiseHasHandler, true);
+  if (DEBUG_IS_ACTIVE) {
+    %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
   }
-
-  function PromiseAll(iterable) {
-    var deferred = %_CallFunction(this, PromiseDeferred);
-    var resolutions = [];
-    try {
-      var count = 0;
-      var i = 0;
-      for (var value of iterable) {
-        this.resolve(value).then(
-            // Nested scope to get closure over current i.
-            // TODO(arv): Use an inner let binding once available.
-            (function(i) {
-              return function(x) {
-                resolutions[i] = x;
-                if (--count === 0) deferred.resolve(resolutions);
-              }
-            })(i),
-            function(r) { deferred.reject(r); });
-        ++i;
-        ++count;
-      }
-
-      if (count === 0) {
-        deferred.resolve(resolutions);
+  return deferred.promise;
+}
+
+function PromiseCatch(onReject) {
+  return this.then(UNDEFINED, onReject);
+}
+
+// Multi-unwrapped chaining with thenable coercion.
+
+function PromiseThen(onResolve, onReject) {
+  onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve
+                                          : PromiseIdResolveHandler;
+  onReject = IS_SPEC_FUNCTION(onReject) ? onReject
+                                        : PromiseIdRejectHandler;
+  var that = this;
+  var constructor = this.constructor;
+  return %_CallFunction(
+    this,
+    function(x) {
+      x = PromiseCoerce(constructor, x);
+      if (x === that) {
+        DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject);
+        return onReject(MakeTypeError('promise_cyclic', [x]));
+      } else if (IsPromise(x)) {
+        return x.then(onResolve, onReject);
+      } else {
+        DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve);
+        return onResolve(x);
       }
+    },
+    onReject,
+    PromiseChain
+  );
+}
+
+// Combinators.
+
+function PromiseCast(x) {
+  // TODO(rossberg): cannot do better until we support @@create.
+  return IsPromise(x) ? x : new this(function(resolve) { resolve(x) });
+}
+
+function PromiseAll(iterable) {
+  var deferred = %_CallFunction(this, PromiseDeferred);
+  var resolutions = [];
+  try {
+    var count = 0;
+    var i = 0;
+    for (var value of iterable) {
+      this.resolve(value).then(
+          // Nested scope to get closure over current i.
+          // TODO(arv): Use an inner let binding once available.
+          (function(i) {
+            return function(x) {
+              resolutions[i] = x;
+              if (--count === 0) deferred.resolve(resolutions);
+            }
+          })(i),
+          function(r) { deferred.reject(r); });
+      ++i;
+      ++count;
+    }
 
-    } catch (e) {
-      deferred.reject(e)
+    if (count === 0) {
+      deferred.resolve(resolutions);
     }
-    return deferred.promise;
-  }
 
-  function PromiseRace(iterable) {
-    var deferred = %_CallFunction(this, PromiseDeferred);
-    try {
-      for (var value of iterable) {
-        this.resolve(value).then(
-            function(x) { deferred.resolve(x) },
-            function(r) { deferred.reject(r) });
-      }
-    } catch (e) {
-      deferred.reject(e)
+  } catch (e) {
+    deferred.reject(e)
+  }
+  return deferred.promise;
+}
+
+function PromiseRace(iterable) {
+  var deferred = %_CallFunction(this, PromiseDeferred);
+  try {
+    for (var value of iterable) {
+      this.resolve(value).then(
+          function(x) { deferred.resolve(x) },
+          function(r) { deferred.reject(r) });
     }
-    return deferred.promise;
+  } catch (e) {
+    deferred.reject(e)
   }
+  return deferred.promise;
+}
 
 
-  // Utility for debugger
+// Utility for debugger
 
-  function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
-    var queue = GET_PRIVATE(promise, promiseOnReject);
-    if (IS_UNDEFINED(queue)) return false;
-    for (var i = 0; i < queue.length; i += 2) {
-      if (queue[i] != PromiseIdRejectHandler) return true;
-      if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
-        return true;
-      }
+function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
+  var queue = GET_PRIVATE(promise, promiseOnReject);
+  if (IS_UNDEFINED(queue)) return false;
+  for (var i = 0; i < queue.length; i += 2) {
+    if (queue[i] != PromiseIdRejectHandler) return true;
+    if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
+      return true;
     }
-    return false;
   }
-
-  // Return whether the promise will be handled by a user-defined reject
-  // handler somewhere down the promise chain. For this, we do a depth-first
-  // search for a reject handler that's not the default PromiseIdRejectHandler.
-  PromiseHasUserDefinedRejectHandler =
-      function PromiseHasUserDefinedRejectHandler() {
-    return PromiseHasUserDefinedRejectHandlerRecursive(this);
-  };
-
-  // -------------------------------------------------------------------
-  // Install exported functions.
-
-  %CheckIsBootstrapping();
-  %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM);
-  %AddNamedProperty(
-      $Promise.prototype, symbolToStringTag, "Promise", DONT_ENUM | READ_ONLY);
-  InstallFunctions($Promise, DONT_ENUM, [
-    "defer", PromiseDeferred,
-    "accept", PromiseResolved,
-    "reject", PromiseRejected,
-    "all", PromiseAll,
-    "race", PromiseRace,
-    "resolve", PromiseCast
-  ]);
-  InstallFunctions($Promise.prototype, DONT_ENUM, [
-    "chain", PromiseChain,
-    "then", PromiseThen,
-    "catch", PromiseCatch
-  ]);
+  return false;
+}
+
+// Return whether the promise will be handled by a user-defined reject
+// handler somewhere down the promise chain. For this, we do a depth-first
+// search for a reject handler that's not the default PromiseIdRejectHandler.
+function PromiseHasUserDefinedRejectHandler() {
+  return PromiseHasUserDefinedRejectHandlerRecursive(this);
+};
+
+// -------------------------------------------------------------------
+// Install exported functions.
+
+%AddNamedProperty(global, 'Promise', GlobalPromise, DONT_ENUM);
+%AddNamedProperty(GlobalPromise.prototype, symbolToStringTag, "Promise",
+                  DONT_ENUM | READ_ONLY);
+
+InstallFunctions(GlobalPromise, DONT_ENUM, [
+  "defer", PromiseDeferred,
+  "accept", PromiseResolved,
+  "reject", PromiseRejected,
+  "all", PromiseAll,
+  "race", PromiseRace,
+  "resolve", PromiseCast
+]);
+
+InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
+  "chain", PromiseChain,
+  "then", PromiseThen,
+  "catch", PromiseCatch
+]);
+
+$promiseCreate = PromiseCreate;
+$promiseResolve = PromiseResolve;
+$promiseReject = PromiseReject;
+$promiseChain = PromiseChain;
+$promiseCatch = PromiseCatch;
+$promiseThen = PromiseThen;
+$promiseHasUserDefinedRejectHandler = PromiseHasUserDefinedRejectHandler;
+$promiseStatus = promiseStatus;
+$promiseValue = promiseValue;
 
 })();