Home | History | Annotate | Download | only in js
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 (function(global, utils, extrasUtils) {
      6 
      7 "use strict";
      8 
      9 %CheckIsBootstrapping();
     10 
     11 // -------------------------------------------------------------------
     12 // Imports
     13 
     14 var InternalArray = utils.InternalArray;
     15 var MakeTypeError;
     16 var promiseCombinedDeferredSymbol =
     17     utils.ImportNow("promise_combined_deferred_symbol");
     18 var promiseHasHandlerSymbol =
     19     utils.ImportNow("promise_has_handler_symbol");
     20 var promiseRejectReactionsSymbol =
     21     utils.ImportNow("promise_reject_reactions_symbol");
     22 var promiseFulfillReactionsSymbol =
     23     utils.ImportNow("promise_fulfill_reactions_symbol");
     24 var promiseDeferredReactionsSymbol =
     25     utils.ImportNow("promise_deferred_reactions_symbol");
     26 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol");
     27 var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
     28 var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
     29 var SpeciesConstructor;
     30 var speciesSymbol = utils.ImportNow("species_symbol");
     31 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
     32 
     33 utils.Import(function(from) {
     34   MakeTypeError = from.MakeTypeError;
     35   SpeciesConstructor = from.SpeciesConstructor;
     36 });
     37 
     38 // -------------------------------------------------------------------
     39 
     40 // [[PromiseState]] values:
     41 const kPending = 0;
     42 const kFulfilled = +1;
     43 const kRejected = -1;
     44 
     45 var lastMicrotaskId = 0;
     46 
     47 // ES#sec-createresolvingfunctions
     48 // CreateResolvingFunctions ( promise )
     49 function CreateResolvingFunctions(promise) {
     50   var alreadyResolved = false;
     51 
     52   // ES#sec-promise-resolve-functions
     53   // Promise Resolve Functions
     54   var resolve = value => {
     55     if (alreadyResolved === true) return;
     56     alreadyResolved = true;
     57     ResolvePromise(promise, value);
     58   };
     59 
     60   // ES#sec-promise-reject-functions
     61   // Promise Reject Functions
     62   var reject = reason => {
     63     if (alreadyResolved === true) return;
     64     alreadyResolved = true;
     65     RejectPromise(promise, reason);
     66   };
     67 
     68   return {
     69     __proto__: null,
     70     resolve: resolve,
     71     reject: reject
     72   };
     73 }
     74 
     75 
     76 // ES#sec-promise-executor
     77 // Promise ( executor )
     78 var GlobalPromise = function Promise(executor) {
     79   if (executor === promiseRawSymbol) {
     80     return %_NewObject(GlobalPromise, new.target);
     81   }
     82   if (IS_UNDEFINED(new.target)) throw MakeTypeError(kNotAPromise, this);
     83   if (!IS_CALLABLE(executor)) {
     84     throw MakeTypeError(kResolverNotAFunction, executor);
     85   }
     86 
     87   var promise = PromiseInit(%_NewObject(GlobalPromise, new.target));
     88   var callbacks = CreateResolvingFunctions(promise);
     89   var debug_is_active = DEBUG_IS_ACTIVE;
     90   try {
     91     if (debug_is_active) %DebugPushPromise(promise, Promise);
     92     executor(callbacks.resolve, callbacks.reject);
     93   } catch (e) {
     94     %_Call(callbacks.reject, UNDEFINED, e);
     95   } finally {
     96     if (debug_is_active) %DebugPopPromise();
     97   }
     98 
     99   return promise;
    100 }
    101 
    102 // Core functionality.
    103 
    104 function PromiseSet(promise, status, value) {
    105   SET_PRIVATE(promise, promiseStateSymbol, status);
    106   SET_PRIVATE(promise, promiseResultSymbol, value);
    107 
    108   // There are 3 possible states for the resolve, reject symbols when we add
    109   // a new callback --
    110   // 1) UNDEFINED -- This is the zero state where there is no callback
    111   // registered. When we see this state, we directly attach the callbacks to
    112   // the symbol.
    113   // 2) !IS_ARRAY -- There is a single callback directly attached to the
    114   // symbols. We need to create a new array to store additional callbacks.
    115   // 3) IS_ARRAY -- There are multiple callbacks already registered,
    116   // therefore we can just push the new callback to the existing array.
    117   SET_PRIVATE(promise, promiseFulfillReactionsSymbol, UNDEFINED);
    118   SET_PRIVATE(promise, promiseRejectReactionsSymbol, UNDEFINED);
    119 
    120   // There are 2 possible states for this symbol --
    121   // 1) UNDEFINED -- This is the zero state, no deferred object is
    122   // attached to this symbol. When we want to add a new deferred we
    123   // directly attach it to this symbol.
    124   // 2) symbol with attached deferred object -- New deferred objects
    125   // are not attached to this symbol, but instead they are directly
    126   // attached to the resolve, reject callback arrays. At this point,
    127   // the deferred symbol's state is stale, and the deferreds should be
    128   // read from the reject, resolve callbacks.
    129   SET_PRIVATE(promise, promiseDeferredReactionsSymbol, UNDEFINED);
    130 
    131   return promise;
    132 }
    133 
    134 function PromiseCreateAndSet(status, value) {
    135   var promise = new GlobalPromise(promiseRawSymbol);
    136   // If debug is active, notify about the newly created promise first.
    137   if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED);
    138   return PromiseSet(promise, status, value);
    139 }
    140 
    141 function PromiseInit(promise) {
    142   return PromiseSet(promise, kPending, UNDEFINED);
    143 }
    144 
    145 function FulfillPromise(promise, status, value, promiseQueue) {
    146   if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) {
    147     var tasks = GET_PRIVATE(promise, promiseQueue);
    148     if (!IS_UNDEFINED(tasks)) {
    149       var tasks = GET_PRIVATE(promise, promiseQueue);
    150       var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol);
    151       PromiseEnqueue(value, tasks, deferreds, status);
    152     }
    153     PromiseSet(promise, status, value);
    154   }
    155 }
    156 
    157 function PromiseHandle(value, handler, deferred) {
    158   var debug_is_active = DEBUG_IS_ACTIVE;
    159   try {
    160     if (debug_is_active) %DebugPushPromise(deferred.promise, PromiseHandle);
    161     var result = handler(value);
    162     deferred.resolve(result);
    163   } catch (exception) {
    164     try { deferred.reject(exception); } catch (e) { }
    165   } finally {
    166     if (debug_is_active) %DebugPopPromise();
    167   }
    168 }
    169 
    170 function PromiseEnqueue(value, tasks, deferreds, status) {
    171   var id, name, instrumenting = DEBUG_IS_ACTIVE;
    172   %EnqueueMicrotask(function() {
    173     if (instrumenting) {
    174       %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
    175     }
    176     if (IS_ARRAY(tasks)) {
    177       for (var i = 0; i < tasks.length; i += 2) {
    178         PromiseHandle(value, tasks[i], tasks[i + 1]);
    179       }
    180     } else {
    181       PromiseHandle(value, tasks, deferreds);
    182     }
    183     if (instrumenting) {
    184       %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
    185     }
    186   });
    187   if (instrumenting) {
    188     id = ++lastMicrotaskId;
    189     name = status === kFulfilled ? "Promise.resolve" : "Promise.reject";
    190     %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
    191   }
    192 }
    193 
    194 function PromiseAttachCallbacks(promise, deferred, onResolve, onReject) {
    195   var maybeResolveCallbacks =
    196       GET_PRIVATE(promise, promiseFulfillReactionsSymbol);
    197   if (IS_UNDEFINED(maybeResolveCallbacks)) {
    198     SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve);
    199     SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject);
    200     SET_PRIVATE(promise, promiseDeferredReactionsSymbol, deferred);
    201   } else if (!IS_ARRAY(maybeResolveCallbacks)) {
    202     var resolveCallbacks = new InternalArray();
    203     var rejectCallbacks = new InternalArray();
    204     var existingDeferred = GET_PRIVATE(promise, promiseDeferredReactionsSymbol);
    205 
    206     resolveCallbacks.push(
    207         maybeResolveCallbacks, existingDeferred, onResolve, deferred);
    208     rejectCallbacks.push(GET_PRIVATE(promise, promiseRejectReactionsSymbol),
    209                          existingDeferred,
    210                          onReject,
    211                          deferred);
    212 
    213     SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks);
    214     SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks);
    215   } else {
    216     maybeResolveCallbacks.push(onResolve, deferred);
    217     GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred);
    218   }
    219 }
    220 
    221 function PromiseIdResolveHandler(x) { return x }
    222 function PromiseIdRejectHandler(r) { throw r }
    223 
    224 function PromiseNopResolver() {}
    225 
    226 // -------------------------------------------------------------------
    227 // Define exported functions.
    228 
    229 // For bootstrapper.
    230 
    231 // ES#sec-ispromise IsPromise ( x )
    232 function IsPromise(x) {
    233   return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol);
    234 }
    235 
    236 function PromiseCreate() {
    237   return new GlobalPromise(PromiseNopResolver)
    238 }
    239 
    240 // ES#sec-promise-resolve-functions
    241 // Promise Resolve Functions, steps 6-13
    242 function ResolvePromise(promise, resolution) {
    243   if (resolution === promise) {
    244     return RejectPromise(promise, MakeTypeError(kPromiseCyclic, resolution));
    245   }
    246   if (IS_RECEIVER(resolution)) {
    247     // 25.4.1.3.2 steps 8-12
    248     try {
    249       var then = resolution.then;
    250     } catch (e) {
    251       return RejectPromise(promise, e);
    252     }
    253 
    254     // Resolution is a native promise and if it's already resolved or
    255     // rejected, shortcircuit the resolution procedure by directly
    256     // reusing the value from the promise.
    257     if (IsPromise(resolution) && then === PromiseThen) {
    258       var thenableState = GET_PRIVATE(resolution, promiseStateSymbol);
    259       if (thenableState === kFulfilled) {
    260         // This goes inside the if-else to save one symbol lookup in
    261         // the slow path.
    262         var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol);
    263         FulfillPromise(promise, kFulfilled, thenableValue,
    264                        promiseFulfillReactionsSymbol);
    265         SET_PRIVATE(promise, promiseHasHandlerSymbol, true);
    266         return;
    267       } else if (thenableState === kRejected) {
    268         var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol);
    269         if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) {
    270           // Promise has already been rejected, but had no handler.
    271           // Revoke previously triggered reject event.
    272           %PromiseRevokeReject(resolution);
    273         }
    274         RejectPromise(promise, thenableValue);
    275         SET_PRIVATE(resolution, promiseHasHandlerSymbol, true);
    276         return;
    277       }
    278     }
    279 
    280     if (IS_CALLABLE(then)) {
    281       // PromiseResolveThenableJob
    282       var id;
    283       var name = "PromiseResolveThenableJob";
    284       var instrumenting = DEBUG_IS_ACTIVE;
    285       %EnqueueMicrotask(function() {
    286         if (instrumenting) {
    287           %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
    288         }
    289         var callbacks = CreateResolvingFunctions(promise);
    290         try {
    291           %_Call(then, resolution, callbacks.resolve, callbacks.reject);
    292         } catch (e) {
    293           %_Call(callbacks.reject, UNDEFINED, e);
    294         }
    295         if (instrumenting) {
    296           %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
    297         }
    298       });
    299       if (instrumenting) {
    300         id = ++lastMicrotaskId;
    301         %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
    302       }
    303       return;
    304     }
    305   }
    306   FulfillPromise(promise, kFulfilled, resolution, promiseFulfillReactionsSymbol);
    307 }
    308 
    309 // ES#sec-rejectpromise
    310 // RejectPromise ( promise, reason )
    311 function RejectPromise(promise, reason) {
    312   // Check promise status to confirm that this reject has an effect.
    313   // Call runtime for callbacks to the debugger or for unhandled reject.
    314   if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) {
    315     var debug_is_active = DEBUG_IS_ACTIVE;
    316     if (debug_is_active ||
    317         !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) {
    318       %PromiseRejectEvent(promise, reason, debug_is_active);
    319     }
    320   }
    321   FulfillPromise(promise, kRejected, reason, promiseRejectReactionsSymbol)
    322 }
    323 
    324 // ES#sec-newpromisecapability
    325 // NewPromiseCapability ( C )
    326 function NewPromiseCapability(C) {
    327   if (C === GlobalPromise) {
    328     // Optimized case, avoid extra closure.
    329     var promise = PromiseInit(new GlobalPromise(promiseRawSymbol));
    330     var callbacks = CreateResolvingFunctions(promise);
    331     return {
    332       promise: promise,
    333       resolve: callbacks.resolve,
    334       reject: callbacks.reject
    335     };
    336   }
    337 
    338   var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED };
    339   result.promise = new C((resolve, reject) => {
    340     if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject))
    341         throw MakeTypeError(kPromiseExecutorAlreadyInvoked);
    342     result.resolve = resolve;
    343     result.reject = reject;
    344   });
    345 
    346   if (!IS_CALLABLE(result.resolve) || !IS_CALLABLE(result.reject))
    347       throw MakeTypeError(kPromiseNonCallable);
    348 
    349   return result;
    350 }
    351 
    352 // Unspecified V8-specific legacy function
    353 function PromiseDefer() {
    354   %IncrementUseCounter(kPromiseDefer);
    355   return NewPromiseCapability(this);
    356 }
    357 
    358 // Unspecified V8-specific legacy function
    359 function PromiseAccept(x) {
    360   %IncrementUseCounter(kPromiseAccept);
    361   return %_Call(PromiseResolve, this, x);
    362 }
    363 
    364 // ES#sec-promise.reject
    365 // Promise.reject ( x )
    366 function PromiseReject(r) {
    367   if (!IS_RECEIVER(this)) {
    368     throw MakeTypeError(kCalledOnNonObject, PromiseResolve);
    369   }
    370   if (this === GlobalPromise) {
    371     // Optimized case, avoid extra closure.
    372     var promise = PromiseCreateAndSet(kRejected, r);
    373     // The debug event for this would always be an uncaught promise reject,
    374     // which is usually simply noise. Do not trigger that debug event.
    375     %PromiseRejectEvent(promise, r, false);
    376     return promise;
    377   } else {
    378     var promiseCapability = NewPromiseCapability(this);
    379     %_Call(promiseCapability.reject, UNDEFINED, r);
    380     return promiseCapability.promise;
    381   }
    382 }
    383 
    384 // Shortcut Promise.reject and Promise.resolve() implementations, used by
    385 // Async Functions implementation.
    386 function PromiseCreateRejected(r) {
    387   return %_Call(PromiseReject, GlobalPromise, r);
    388 }
    389 
    390 function PromiseCreateResolved(x) {
    391   return %_Call(PromiseResolve, GlobalPromise, x);
    392 }
    393 
    394 // ES#sec-promise.prototype.then
    395 // Promise.prototype.then ( onFulfilled, onRejected )
    396 // Multi-unwrapped chaining with thenable coercion.
    397 function PromiseThen(onResolve, onReject) {
    398   var status = GET_PRIVATE(this, promiseStateSymbol);
    399   if (IS_UNDEFINED(status)) {
    400     throw MakeTypeError(kNotAPromise, this);
    401   }
    402 
    403   var constructor = SpeciesConstructor(this, GlobalPromise);
    404   onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler;
    405   onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler;
    406   var deferred = NewPromiseCapability(constructor);
    407   switch (status) {
    408     case kPending:
    409       PromiseAttachCallbacks(this, deferred, onResolve, onReject);
    410       break;
    411     case kFulfilled:
    412       PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol),
    413                      onResolve, deferred, kFulfilled);
    414       break;
    415     case kRejected:
    416       if (!HAS_DEFINED_PRIVATE(this, promiseHasHandlerSymbol)) {
    417         // Promise has already been rejected, but had no handler.
    418         // Revoke previously triggered reject event.
    419         %PromiseRevokeReject(this);
    420       }
    421       PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol),
    422                      onReject, deferred, kRejected);
    423       break;
    424   }
    425   // Mark this promise as having handler.
    426   SET_PRIVATE(this, promiseHasHandlerSymbol, true);
    427   return deferred.promise;
    428 }
    429 
    430 // Unspecified V8-specific legacy function
    431 // Chain is left around for now as an alias for then
    432 function PromiseChain(onResolve, onReject) {
    433   %IncrementUseCounter(kPromiseChain);
    434   return %_Call(PromiseThen, this, onResolve, onReject);
    435 }
    436 
    437 // ES#sec-promise.prototype.catch
    438 // Promise.prototype.catch ( onRejected )
    439 function PromiseCatch(onReject) {
    440   return this.then(UNDEFINED, onReject);
    441 }
    442 
    443 // Combinators.
    444 
    445 // ES#sec-promise.resolve
    446 // Promise.resolve ( x )
    447 function PromiseResolve(x) {
    448   if (!IS_RECEIVER(this)) {
    449     throw MakeTypeError(kCalledOnNonObject, PromiseResolve);
    450   }
    451   if (IsPromise(x) && x.constructor === this) return x;
    452 
    453   var promiseCapability = NewPromiseCapability(this);
    454   var resolveResult = %_Call(promiseCapability.resolve, UNDEFINED, x);
    455   return promiseCapability.promise;
    456 }
    457 
    458 // ES#sec-promise.all
    459 // Promise.all ( iterable )
    460 function PromiseAll(iterable) {
    461   if (!IS_RECEIVER(this)) {
    462     throw MakeTypeError(kCalledOnNonObject, "Promise.all");
    463   }
    464 
    465   var deferred = NewPromiseCapability(this);
    466   var resolutions = new InternalArray();
    467   var count;
    468 
    469   function CreateResolveElementFunction(index, values, promiseCapability) {
    470     var alreadyCalled = false;
    471     return (x) => {
    472       if (alreadyCalled === true) return;
    473       alreadyCalled = true;
    474       values[index] = x;
    475       if (--count === 0) {
    476         var valuesArray = [];
    477         %MoveArrayContents(values, valuesArray);
    478         %_Call(promiseCapability.resolve, UNDEFINED, valuesArray);
    479       }
    480     };
    481   }
    482 
    483   try {
    484     var i = 0;
    485     count = 1;
    486     for (var value of iterable) {
    487       var nextPromise = this.resolve(value);
    488       ++count;
    489       nextPromise.then(
    490           CreateResolveElementFunction(i, resolutions, deferred),
    491           deferred.reject);
    492       SET_PRIVATE(deferred.reject, promiseCombinedDeferredSymbol, deferred);
    493       ++i;
    494     }
    495 
    496     // 6.d
    497     if (--count === 0) {
    498       var valuesArray = [];
    499       %MoveArrayContents(resolutions, valuesArray);
    500       %_Call(deferred.resolve, UNDEFINED, valuesArray);
    501     }
    502 
    503   } catch (e) {
    504     %_Call(deferred.reject, UNDEFINED, e);
    505   }
    506   return deferred.promise;
    507 }
    508 
    509 // ES#sec-promise.race
    510 // Promise.race ( iterable )
    511 function PromiseRace(iterable) {
    512   if (!IS_RECEIVER(this)) {
    513     throw MakeTypeError(kCalledOnNonObject, PromiseRace);
    514   }
    515 
    516   var deferred = NewPromiseCapability(this);
    517   try {
    518     for (var value of iterable) {
    519       this.resolve(value).then(deferred.resolve, deferred.reject);
    520       SET_PRIVATE(deferred.reject, promiseCombinedDeferredSymbol, deferred);
    521     }
    522   } catch (e) {
    523     deferred.reject(e)
    524   }
    525   return deferred.promise;
    526 }
    527 
    528 
    529 // Utility for debugger
    530 
    531 function PromiseHasUserDefinedRejectHandlerCheck(handler, deferred) {
    532   if (handler !== PromiseIdRejectHandler) {
    533     var combinedDeferred = GET_PRIVATE(handler, promiseCombinedDeferredSymbol);
    534     if (IS_UNDEFINED(combinedDeferred)) return true;
    535     if (PromiseHasUserDefinedRejectHandlerRecursive(combinedDeferred.promise)) {
    536       return true;
    537     }
    538   } else if (PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise)) {
    539     return true;
    540   }
    541   return false;
    542 }
    543 
    544 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
    545   var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol);
    546   var deferreds = GET_PRIVATE(promise, promiseDeferredReactionsSymbol);
    547   if (IS_UNDEFINED(queue)) return false;
    548   if (!IS_ARRAY(queue)) {
    549     return PromiseHasUserDefinedRejectHandlerCheck(queue, deferreds);
    550   } else {
    551     for (var i = 0; i < queue.length; i += 2) {
    552       if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], queue[i + 1])) {
    553         return true;
    554       }
    555     }
    556   }
    557   return false;
    558 }
    559 
    560 // Return whether the promise will be handled by a user-defined reject
    561 // handler somewhere down the promise chain. For this, we do a depth-first
    562 // search for a reject handler that's not the default PromiseIdRejectHandler.
    563 function PromiseHasUserDefinedRejectHandler() {
    564   return PromiseHasUserDefinedRejectHandlerRecursive(this);
    565 };
    566 
    567 
    568 function PromiseSpecies() {
    569   return this;
    570 }
    571 
    572 // -------------------------------------------------------------------
    573 // Install exported functions.
    574 
    575 %AddNamedProperty(global, 'Promise', GlobalPromise, DONT_ENUM);
    576 %AddNamedProperty(GlobalPromise.prototype, toStringTagSymbol, "Promise",
    577                   DONT_ENUM | READ_ONLY);
    578 
    579 utils.InstallFunctions(GlobalPromise, DONT_ENUM, [
    580   "reject", PromiseReject,
    581   "all", PromiseAll,
    582   "race", PromiseRace,
    583   "resolve", PromiseResolve
    584 ]);
    585 
    586 utils.InstallGetter(GlobalPromise, speciesSymbol, PromiseSpecies);
    587 
    588 utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
    589   "then", PromiseThen,
    590   "catch", PromiseCatch
    591 ]);
    592 
    593 %InstallToContext([
    594   "promise_catch", PromiseCatch,
    595   "promise_chain", PromiseChain,
    596   "promise_create", PromiseCreate,
    597   "promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler,
    598   "promise_reject", RejectPromise,
    599   "promise_resolve", ResolvePromise,
    600   "promise_then", PromiseThen,
    601   "promise_create_rejected", PromiseCreateRejected,
    602   "promise_create_resolved", PromiseCreateResolved
    603 ]);
    604 
    605 // This allows extras to create promises quickly without building extra
    606 // resolve/reject closures, and allows them to later resolve and reject any
    607 // promise without having to hold on to those closures forever.
    608 utils.InstallFunctions(extrasUtils, 0, [
    609   "createPromise", PromiseCreate,
    610   "resolvePromise", ResolvePromise,
    611   "rejectPromise", RejectPromise
    612 ]);
    613 
    614 // TODO(v8:4567): Allow experimental natives to remove function prototype
    615 [PromiseChain, PromiseDefer, PromiseAccept].forEach(
    616     fn => %FunctionRemovePrototype(fn));
    617 
    618 utils.Export(function(to) {
    619   to.PromiseChain = PromiseChain;
    620   to.PromiseDefer = PromiseDefer;
    621   to.PromiseAccept = PromiseAccept;
    622 
    623   to.PromiseCreateRejected = PromiseCreateRejected;
    624   to.PromiseCreateResolved = PromiseCreateResolved;
    625   to.PromiseThen = PromiseThen;
    626 });
    627 
    628 })
    629