• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 promiseAsyncStackIDSymbol =
16     utils.ImportNow("promise_async_stack_id_symbol");
17 var promiseHandledBySymbol =
18     utils.ImportNow("promise_handled_by_symbol");
19 var promiseForwardingHandlerSymbol =
20     utils.ImportNow("promise_forwarding_handler_symbol");
21 var promiseHasHandlerSymbol =
22     utils.ImportNow("promise_has_handler_symbol");
23 var promiseRejectReactionsSymbol =
24     utils.ImportNow("promise_reject_reactions_symbol");
25 var promiseFulfillReactionsSymbol =
26     utils.ImportNow("promise_fulfill_reactions_symbol");
27 var promiseDeferredReactionSymbol =
28     utils.ImportNow("promise_deferred_reaction_symbol");
29 var promiseHandledHintSymbol =
30     utils.ImportNow("promise_handled_hint_symbol");
31 var promiseRawSymbol = utils.ImportNow("promise_raw_symbol");
32 var promiseStateSymbol = utils.ImportNow("promise_state_symbol");
33 var promiseResultSymbol = utils.ImportNow("promise_result_symbol");
34 var SpeciesConstructor;
35 var speciesSymbol = utils.ImportNow("species_symbol");
36 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
37 var ObjectHasOwnProperty;
38 
39 utils.Import(function(from) {
40   ObjectHasOwnProperty = from.ObjectHasOwnProperty;
41   SpeciesConstructor = from.SpeciesConstructor;
42 });
43 
44 // -------------------------------------------------------------------
45 
46 // [[PromiseState]] values:
47 // These values should be kept in sync with PromiseStatus in globals.h
48 const kPending = 0;
49 const kFulfilled = +1;
50 const kRejected = +2;
51 
52 const kResolveCallback = 0;
53 const kRejectCallback = 1;
54 
55 // ES#sec-promise-executor
56 // Promise ( executor )
57 var GlobalPromise = function Promise(executor) {
58   if (executor === promiseRawSymbol) {
59     return %_NewObject(GlobalPromise, new.target);
60   }
61   if (IS_UNDEFINED(new.target)) throw %make_type_error(kNotAPromise, this);
62   if (!IS_CALLABLE(executor)) {
63     throw %make_type_error(kResolverNotAFunction, executor);
64   }
65 
66   var promise = PromiseInit(%_NewObject(GlobalPromise, new.target));
67   // Calling the reject function would be a new exception, so debugEvent = true
68   // TODO(gsathya): Remove container for callbacks when this is moved
69   // to CPP/TF.
70   var callbacks = %create_resolving_functions(promise, true);
71   var debug_is_active = DEBUG_IS_ACTIVE;
72   try {
73     if (debug_is_active) %DebugPushPromise(promise);
74     executor(callbacks[kResolveCallback], callbacks[kRejectCallback]);
75   } %catch (e) {  // Natives syntax to mark this catch block.
76     %_Call(callbacks[kRejectCallback], UNDEFINED, e);
77   } finally {
78     if (debug_is_active) %DebugPopPromise();
79   }
80 
81   return promise;
82 }
83 
84 // Core functionality.
85 
86 function PromiseSet(promise, status, value) {
87   SET_PRIVATE(promise, promiseStateSymbol, status);
88   SET_PRIVATE(promise, promiseResultSymbol, value);
89 
90   // There are 3 possible states for the resolve, reject symbols when we add
91   // a new callback --
92   // 1) UNDEFINED -- This is the zero state where there is no callback
93   // registered. When we see this state, we directly attach the callbacks to
94   // the symbol.
95   // 2) !IS_ARRAY -- There is a single callback directly attached to the
96   // symbols. We need to create a new array to store additional callbacks.
97   // 3) IS_ARRAY -- There are multiple callbacks already registered,
98   // therefore we can just push the new callback to the existing array.
99   SET_PRIVATE(promise, promiseFulfillReactionsSymbol, UNDEFINED);
100   SET_PRIVATE(promise, promiseRejectReactionsSymbol, UNDEFINED);
101 
102   // This symbol is used only when one deferred needs to be attached. When more
103   // than one deferred need to be attached the promise, we attach them directly
104   // to the promiseFulfillReactionsSymbol and promiseRejectReactionsSymbol and
105   // reset this back to UNDEFINED.
106   SET_PRIVATE(promise, promiseDeferredReactionSymbol, UNDEFINED);
107 
108   return promise;
109 }
110 
111 function PromiseCreateAndSet(status, value) {
112   var promise = new GlobalPromise(promiseRawSymbol);
113   // If debug is active, notify about the newly created promise first.
114   if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED);
115   return PromiseSet(promise, status, value);
116 }
117 
118 function PromiseInit(promise) {
119   return PromiseSet(promise, kPending, UNDEFINED);
120 }
121 
122 function PromiseHandle(value, handler, deferred) {
123   var debug_is_active = DEBUG_IS_ACTIVE;
124   try {
125     if (debug_is_active) %DebugPushPromise(deferred.promise);
126     var result = handler(value);
127     if (IS_UNDEFINED(deferred.resolve)) {
128       ResolvePromise(deferred.promise, result);
129     } else {
130       %_Call(deferred.resolve, UNDEFINED, result);
131     }
132   } %catch (exception) {  // Natives syntax to mark this catch block.
133     try {
134       if (IS_UNDEFINED(deferred.reject)) {
135         // Pass false for debugEvent so .then chaining does not trigger
136         // redundant ExceptionEvents.
137         %PromiseReject(deferred.promise, exception, false);
138         PromiseSet(deferred.promise, kRejected, exception);
139       } else {
140         %_Call(deferred.reject, UNDEFINED, exception);
141       }
142     } catch (e) { }
143   } finally {
144     if (debug_is_active) %DebugPopPromise();
145   }
146 }
147 
148 function PromiseDebugGetInfo(deferreds, status) {
149   var id, name, instrumenting = DEBUG_IS_ACTIVE;
150 
151   if (instrumenting) {
152     // In an async function, reuse the existing stack related to the outer
153     // Promise. Otherwise, e.g. in a direct call to then, save a new stack.
154     // Promises with multiple reactions with one or more of them being async
155     // functions will not get a good stack trace, as async functions require
156     // different stacks from direct Promise use, but we save and restore a
157     // stack once for all reactions. TODO(littledan): Improve this case.
158     if (!IS_UNDEFINED(deferreds) &&
159         HAS_PRIVATE(deferreds.promise, promiseHandledBySymbol) &&
160         HAS_PRIVATE(GET_PRIVATE(deferreds.promise, promiseHandledBySymbol),
161                     promiseAsyncStackIDSymbol)) {
162       id = GET_PRIVATE(GET_PRIVATE(deferreds.promise, promiseHandledBySymbol),
163                        promiseAsyncStackIDSymbol);
164       name = "async function";
165     } else {
166       id = %DebugNextMicrotaskId();
167       name = status === kFulfilled ? "Promise.resolve" : "Promise.reject";
168       %DebugAsyncTaskEvent("enqueue", id, name);
169     }
170   }
171   return [id, name];
172 }
173 
174 function PromiseAttachCallbacks(promise, deferred, onResolve, onReject) {
175   var maybeResolveCallbacks =
176       GET_PRIVATE(promise, promiseFulfillReactionsSymbol);
177   if (IS_UNDEFINED(maybeResolveCallbacks)) {
178     SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve);
179     SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject);
180     SET_PRIVATE(promise, promiseDeferredReactionSymbol, deferred);
181   } else if (!IS_ARRAY(maybeResolveCallbacks)) {
182     var resolveCallbacks = new InternalArray();
183     var rejectCallbacks = new InternalArray();
184     var existingDeferred = GET_PRIVATE(promise, promiseDeferredReactionSymbol);
185 
186     resolveCallbacks.push(
187         maybeResolveCallbacks, existingDeferred, onResolve, deferred);
188     rejectCallbacks.push(GET_PRIVATE(promise, promiseRejectReactionsSymbol),
189                          existingDeferred,
190                          onReject,
191                          deferred);
192 
193     SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks);
194     SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks);
195     SET_PRIVATE(promise, promiseDeferredReactionSymbol, UNDEFINED);
196   } else {
197     maybeResolveCallbacks.push(onResolve, deferred);
198     GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred);
199   }
200 }
201 
202 function PromiseIdResolveHandler(x) { return x; }
203 function PromiseIdRejectHandler(r) { %_ReThrow(r); }
204 SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true);
205 
206 // -------------------------------------------------------------------
207 // Define exported functions.
208 
209 // For bootstrapper.
210 
211 // ES#sec-ispromise IsPromise ( x )
212 function IsPromise(x) {
213   return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol);
214 }
215 
216 function PromiseCreate() {
217   return PromiseInit(new GlobalPromise(promiseRawSymbol));
218 }
219 
220 // ES#sec-promise-resolve-functions
221 // Promise Resolve Functions, steps 6-13
222 function ResolvePromise(promise, resolution) {
223   if (resolution === promise) {
224     var exception = %make_type_error(kPromiseCyclic, resolution);
225     %PromiseReject(promise, exception, true);
226     PromiseSet(promise, kRejected, exception);
227     return;
228   }
229   if (IS_RECEIVER(resolution)) {
230     // 25.4.1.3.2 steps 8-12
231     try {
232       var then = resolution.then;
233     } catch (e) {
234       %PromiseReject(promise, e, true);
235       PromiseSet(promise, kRejected, e);
236       return;
237     }
238 
239     // Resolution is a native promise and if it's already resolved or
240     // rejected, shortcircuit the resolution procedure by directly
241     // reusing the value from the promise.
242     if (IsPromise(resolution) && then === PromiseThen) {
243       var thenableState = GET_PRIVATE(resolution, promiseStateSymbol);
244       if (thenableState === kFulfilled) {
245         // This goes inside the if-else to save one symbol lookup in
246         // the slow path.
247         var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol);
248         %PromiseFulfill(promise, kFulfilled, thenableValue,
249                        promiseFulfillReactionsSymbol);
250         PromiseSet(promise, kFulfilled, thenableValue);
251         SET_PRIVATE(promise, promiseHasHandlerSymbol, true);
252         return;
253       } else if (thenableState === kRejected) {
254         var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol);
255         if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) {
256           // Promise has already been rejected, but had no handler.
257           // Revoke previously triggered reject event.
258           %PromiseRevokeReject(resolution);
259         }
260         // Don't cause a debug event as this case is forwarding a rejection
261         %PromiseReject(promise, thenableValue, false);
262         PromiseSet(promise, kRejected, thenableValue);
263         SET_PRIVATE(resolution, promiseHasHandlerSymbol, true);
264         return;
265       }
266     }
267 
268     if (IS_CALLABLE(then)) {
269       if (DEBUG_IS_ACTIVE && IsPromise(resolution)) {
270           // Mark the dependency of the new promise on the resolution
271         SET_PRIVATE(resolution, promiseHandledBySymbol, promise);
272       }
273       %EnqueuePromiseResolveThenableJob(promise, resolution, then);
274       return;
275     }
276   }
277   %PromiseFulfill(promise, kFulfilled, resolution,
278                   promiseFulfillReactionsSymbol);
279   PromiseSet(promise, kFulfilled, resolution);
280 }
281 
282 // Only used by async-await.js
283 function RejectPromise(promise, reason, debugEvent) {
284   %PromiseReject(promise, reason, debugEvent);
285   PromiseSet(promise, kRejected, reason);
286 }
287 
288 // Export to bindings
289 function DoRejectPromise(promise, reason) {
290   %PromiseReject(promise, reason, true);
291   PromiseSet(promise, kRejected, reason);
292 }
293 
294 // ES#sec-newpromisecapability
295 // NewPromiseCapability ( C )
296 function NewPromiseCapability(C, debugEvent) {
297   if (C === GlobalPromise) {
298     // Optimized case, avoid extra closure.
299     var promise = PromiseCreate();
300     // TODO(gsathya): Remove container for callbacks when this is
301     // moved to CPP/TF.
302     var callbacks = %create_resolving_functions(promise, debugEvent);
303     return {
304       promise: promise,
305       resolve: callbacks[kResolveCallback],
306       reject: callbacks[kRejectCallback]
307     };
308   }
309 
310   var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED };
311   result.promise = new C((resolve, reject) => {
312     if (!IS_UNDEFINED(result.resolve) || !IS_UNDEFINED(result.reject))
313         throw %make_type_error(kPromiseExecutorAlreadyInvoked);
314     result.resolve = resolve;
315     result.reject = reject;
316   });
317 
318   if (!IS_CALLABLE(result.resolve) || !IS_CALLABLE(result.reject))
319       throw %make_type_error(kPromiseNonCallable);
320 
321   return result;
322 }
323 
324 // ES#sec-promise.reject
325 // Promise.reject ( x )
326 function PromiseReject(r) {
327   if (!IS_RECEIVER(this)) {
328     throw %make_type_error(kCalledOnNonObject, PromiseResolve);
329   }
330   if (this === GlobalPromise) {
331     // Optimized case, avoid extra closure.
332     var promise = PromiseCreateAndSet(kRejected, r);
333     // Trigger debug events if the debugger is on, as Promise.reject is
334     // equivalent to throwing an exception directly.
335     %PromiseRejectEventFromStack(promise, r);
336     return promise;
337   } else {
338     var promiseCapability = NewPromiseCapability(this, true);
339     %_Call(promiseCapability.reject, UNDEFINED, r);
340     return promiseCapability.promise;
341   }
342 }
343 
344 function PerformPromiseThen(promise, onResolve, onReject, resultCapability) {
345   if (!IS_CALLABLE(onResolve)) onResolve = PromiseIdResolveHandler;
346   if (!IS_CALLABLE(onReject)) onReject = PromiseIdRejectHandler;
347 
348   var status = GET_PRIVATE(promise, promiseStateSymbol);
349   switch (status) {
350     case kPending:
351       PromiseAttachCallbacks(promise, resultCapability, onResolve, onReject);
352       break;
353     case kFulfilled:
354       %EnqueuePromiseReactionJob(GET_PRIVATE(promise, promiseResultSymbol),
355                                  onResolve, resultCapability, kFulfilled);
356       break;
357     case kRejected:
358       if (!HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) {
359         // Promise has already been rejected, but had no handler.
360         // Revoke previously triggered reject event.
361         %PromiseRevokeReject(promise);
362       }
363       %EnqueuePromiseReactionJob(GET_PRIVATE(promise, promiseResultSymbol),
364                                  onReject, resultCapability, kRejected);
365       break;
366   }
367 
368   // Mark this promise as having handler.
369   SET_PRIVATE(promise, promiseHasHandlerSymbol, true);
370   return resultCapability.promise;
371 }
372 
373 // ES#sec-promise.prototype.then
374 // Promise.prototype.then ( onFulfilled, onRejected )
375 // Multi-unwrapped chaining with thenable coercion.
376 function PromiseThen(onResolve, onReject) {
377   var status = GET_PRIVATE(this, promiseStateSymbol);
378   if (IS_UNDEFINED(status)) {
379     throw %make_type_error(kNotAPromise, this);
380   }
381 
382   var constructor = SpeciesConstructor(this, GlobalPromise);
383   var resultCapability;
384 
385   // The resultCapability.promise is only ever fulfilled internally,
386   // so we don't need the closures to protect against accidentally
387   // calling them multiple times.
388   if (constructor === GlobalPromise) {
389     // TODO(gsathya): Combine this into NewPromiseCapability.
390     resultCapability = {
391       promise: PromiseCreate(),
392       resolve: UNDEFINED,
393       reject: UNDEFINED
394     };
395   } else {
396     // Pass false for debugEvent so .then chaining does not trigger
397     // redundant ExceptionEvents.
398     resultCapability = NewPromiseCapability(constructor, false);
399   }
400   return PerformPromiseThen(this, onResolve, onReject, resultCapability);
401 }
402 
403 // ES#sec-promise.prototype.catch
404 // Promise.prototype.catch ( onRejected )
405 function PromiseCatch(onReject) {
406   return this.then(UNDEFINED, onReject);
407 }
408 
409 // Combinators.
410 
411 // ES#sec-promise.resolve
412 // Promise.resolve ( x )
413 function PromiseResolve(x) {
414   if (!IS_RECEIVER(this)) {
415     throw %make_type_error(kCalledOnNonObject, PromiseResolve);
416   }
417   if (IsPromise(x) && x.constructor === this) return x;
418 
419   // Avoid creating resolving functions.
420   if (this === GlobalPromise) {
421     var promise = PromiseCreate();
422     ResolvePromise(promise, x);
423     return promise;
424   }
425 
426   // debugEvent is not so meaningful here as it will be resolved
427   var promiseCapability = NewPromiseCapability(this, true);
428   %_Call(promiseCapability.resolve, UNDEFINED, x);
429   return promiseCapability.promise;
430 }
431 
432 // ES#sec-promise.all
433 // Promise.all ( iterable )
434 function PromiseAll(iterable) {
435   if (!IS_RECEIVER(this)) {
436     throw %make_type_error(kCalledOnNonObject, "Promise.all");
437   }
438 
439   // false debugEvent so that forwarding the rejection through all does not
440   // trigger redundant ExceptionEvents
441   var deferred = NewPromiseCapability(this, false);
442   var resolutions = new InternalArray();
443   var count;
444 
445   // For catch prediction, don't treat the .then calls as handling it;
446   // instead, recurse outwards.
447   var instrumenting = DEBUG_IS_ACTIVE;
448   if (instrumenting) {
449     SET_PRIVATE(deferred.reject, promiseForwardingHandlerSymbol, true);
450   }
451 
452   function CreateResolveElementFunction(index, values, promiseCapability) {
453     var alreadyCalled = false;
454     return (x) => {
455       if (alreadyCalled === true) return;
456       alreadyCalled = true;
457       values[index] = x;
458       if (--count === 0) {
459         var valuesArray = [];
460         %MoveArrayContents(values, valuesArray);
461         %_Call(promiseCapability.resolve, UNDEFINED, valuesArray);
462       }
463     };
464   }
465 
466   try {
467     var i = 0;
468     count = 1;
469     for (var value of iterable) {
470       var nextPromise = this.resolve(value);
471       ++count;
472       var throwawayPromise = nextPromise.then(
473           CreateResolveElementFunction(i, resolutions, deferred),
474           deferred.reject);
475       // For catch prediction, mark that rejections here are semantically
476       // handled by the combined Promise.
477       if (instrumenting && IsPromise(throwawayPromise)) {
478         SET_PRIVATE(throwawayPromise, promiseHandledBySymbol, deferred.promise);
479       }
480       ++i;
481     }
482 
483     // 6.d
484     if (--count === 0) {
485       var valuesArray = [];
486       %MoveArrayContents(resolutions, valuesArray);
487       %_Call(deferred.resolve, UNDEFINED, valuesArray);
488     }
489 
490   } catch (e) {
491     %_Call(deferred.reject, UNDEFINED, e);
492   }
493   return deferred.promise;
494 }
495 
496 // ES#sec-promise.race
497 // Promise.race ( iterable )
498 function PromiseRace(iterable) {
499   if (!IS_RECEIVER(this)) {
500     throw %make_type_error(kCalledOnNonObject, PromiseRace);
501   }
502 
503   // false debugEvent so that forwarding the rejection through race does not
504   // trigger redundant ExceptionEvents
505   var deferred = NewPromiseCapability(this, false);
506 
507   // For catch prediction, don't treat the .then calls as handling it;
508   // instead, recurse outwards.
509   var instrumenting = DEBUG_IS_ACTIVE;
510   if (instrumenting) {
511     SET_PRIVATE(deferred.reject, promiseForwardingHandlerSymbol, true);
512   }
513 
514   try {
515     for (var value of iterable) {
516       var throwawayPromise = this.resolve(value).then(deferred.resolve,
517                                                       deferred.reject);
518       // For catch prediction, mark that rejections here are semantically
519       // handled by the combined Promise.
520       if (instrumenting && IsPromise(throwawayPromise)) {
521         SET_PRIVATE(throwawayPromise, promiseHandledBySymbol, deferred.promise);
522       }
523     }
524   } catch (e) {
525     %_Call(deferred.reject, UNDEFINED, e);
526   }
527   return deferred.promise;
528 }
529 
530 
531 // Utility for debugger
532 
533 function PromiseHasUserDefinedRejectHandlerCheck(handler, deferred) {
534   // Recurse to the forwarding Promise, if any. This may be due to
535   //  - await reaction forwarding to the throwaway Promise, which has
536   //    a dependency edge to the outer Promise.
537   //  - PromiseIdResolveHandler forwarding to the output of .then
538   //  - Promise.all/Promise.race forwarding to a throwaway Promise, which
539   //    has a dependency edge to the generated outer Promise.
540   if (GET_PRIVATE(handler, promiseForwardingHandlerSymbol)) {
541     return PromiseHasUserDefinedRejectHandlerRecursive(deferred.promise);
542   }
543 
544   // Otherwise, this is a real reject handler for the Promise
545   return true;
546 }
547 
548 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
549   // If this promise was marked as being handled by a catch block
550   // in an async function, then it has a user-defined reject handler.
551   if (GET_PRIVATE(promise, promiseHandledHintSymbol)) return true;
552 
553   // If this Promise is subsumed by another Promise (a Promise resolved
554   // with another Promise, or an intermediate, hidden, throwaway Promise
555   // within async/await), then recurse on the outer Promise.
556   // In this case, the dependency is one possible way that the Promise
557   // could be resolved, so it does not subsume the other following cases.
558   var outerPromise = GET_PRIVATE(promise, promiseHandledBySymbol);
559   if (outerPromise &&
560       PromiseHasUserDefinedRejectHandlerRecursive(outerPromise)) {
561     return true;
562   }
563 
564   var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol);
565   var deferred = GET_PRIVATE(promise, promiseDeferredReactionSymbol);
566 
567   if (IS_UNDEFINED(queue)) return false;
568 
569   if (!IS_ARRAY(queue)) {
570     return PromiseHasUserDefinedRejectHandlerCheck(queue, deferred);
571   }
572 
573   for (var i = 0; i < queue.length; i += 2) {
574     if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], queue[i + 1])) {
575       return true;
576     }
577   }
578   return false;
579 }
580 
581 // Return whether the promise will be handled by a user-defined reject
582 // handler somewhere down the promise chain. For this, we do a depth-first
583 // search for a reject handler that's not the default PromiseIdRejectHandler.
584 // This function also traverses dependencies of one Promise on another,
585 // set up through async/await and Promises resolved with Promises.
586 function PromiseHasUserDefinedRejectHandler() {
587   return PromiseHasUserDefinedRejectHandlerRecursive(this);
588 };
589 
590 function MarkPromiseAsHandled(promise) {
591   SET_PRIVATE(promise, promiseHasHandlerSymbol, true);
592 }
593 
594 
595 function PromiseSpecies() {
596   return this;
597 }
598 
599 // -------------------------------------------------------------------
600 // Install exported functions.
601 
602 %AddNamedProperty(global, 'Promise', GlobalPromise, DONT_ENUM);
603 %AddNamedProperty(GlobalPromise.prototype, toStringTagSymbol, "Promise",
604                   DONT_ENUM | READ_ONLY);
605 
606 utils.InstallFunctions(GlobalPromise, DONT_ENUM, [
607   "reject", PromiseReject,
608   "all", PromiseAll,
609   "race", PromiseRace,
610   "resolve", PromiseResolve
611 ]);
612 
613 utils.InstallGetter(GlobalPromise, speciesSymbol, PromiseSpecies);
614 
615 utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
616   "then", PromiseThen,
617   "catch", PromiseCatch
618 ]);
619 
620 %InstallToContext([
621   "promise_catch", PromiseCatch,
622   "promise_create", PromiseCreate,
623   "promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler,
624   "promise_reject", DoRejectPromise,
625   // TODO(gsathya): Remove this once we update the promise builtin.
626   "promise_internal_reject", RejectPromise,
627   "promise_resolve", ResolvePromise,
628   "promise_then", PromiseThen,
629   "promise_handle", PromiseHandle,
630   "promise_debug_get_info", PromiseDebugGetInfo
631 ]);
632 
633 // This allows extras to create promises quickly without building extra
634 // resolve/reject closures, and allows them to later resolve and reject any
635 // promise without having to hold on to those closures forever.
636 utils.InstallFunctions(extrasUtils, 0, [
637   "createPromise", PromiseCreate,
638   "resolvePromise", ResolvePromise,
639   "rejectPromise", DoRejectPromise,
640   "markPromiseAsHandled", MarkPromiseAsHandled
641 ]);
642 
643 utils.Export(function(to) {
644   to.IsPromise = IsPromise;
645   to.PromiseCreate = PromiseCreate;
646   to.PromiseThen = PromiseThen;
647 
648   to.GlobalPromise = GlobalPromise;
649   to.NewPromiseCapability = NewPromiseCapability;
650   to.PerformPromiseThen = PerformPromiseThen;
651   to.ResolvePromise = ResolvePromise;
652   to.RejectPromise = RejectPromise;
653 });
654 
655 })
656