• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 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#include 'src/builtins/builtins-promise-gen.h'
6
7namespace promise {
8
9// https://tc39.es/ecma262/#sec-promise.race
10transitioning javascript builtin
11PromiseRace(
12    js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny {
13  const receiver = Cast<JSReceiver>(receiver)
14      otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.race');
15
16  // This builtin is attached to JSFunction created by the bootstrapper so
17  // `context` is the native context.
18  check(Is<NativeContext>(context));
19  const nativeContext = UnsafeCast<NativeContext>(context);
20
21  // Let promiseCapability be ? NewPromiseCapability(C).
22  // Don't fire debugEvent so that forwarding the rejection through all does
23  // not trigger redundant ExceptionEvents
24  const capability = NewPromiseCapability(receiver, False);
25  const resolve = capability.resolve;
26  const reject = capability.reject;
27  const promise = capability.promise;
28
29  // NewPromiseCapability guarantees that receiver is Constructor.
30  dcheck(Is<Constructor>(receiver));
31  const constructor = UnsafeCast<Constructor>(receiver);
32
33  // For catch prediction, don't treat the .then calls as handling it;
34  // instead, recurse outwards.
35  if (IsDebugActive()) deferred {
36      SetPropertyStrict(context, reject, kPromiseForwardingHandlerSymbol, True);
37    }
38
39  try {
40    let promiseResolveFunction: JSAny;
41    let i: iterator::IteratorRecord;
42    try {
43      // Let promiseResolve be GetPromiseResolve(C).
44      // IfAbruptRejectPromise(promiseResolve, promiseCapability).
45      promiseResolveFunction = GetPromiseResolve(nativeContext, constructor);
46
47      // Let iterator be GetIterator(iterable).
48      // IfAbruptRejectPromise(iterator, promiseCapability).
49      i = iterator::GetIterator(iterable);
50    } catch (e, _message) deferred {
51      goto Reject(e);
52    }
53
54    // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability).
55    try {
56      const fastIteratorResultMap = *NativeContextSlot(
57          nativeContext, ContextSlot::ITERATOR_RESULT_MAP_INDEX);
58      while (true) {
59        let nextValue: JSAny;
60        try {
61          // Let next be IteratorStep(iteratorRecord.[[Iterator]]).
62          // If next is an abrupt completion, set iteratorRecord.[[Done]] to
63          // true. ReturnIfAbrupt(next).
64          const next: JSReceiver = iterator::IteratorStep(
65              i, fastIteratorResultMap) otherwise return promise;
66
67          // Let nextValue be IteratorValue(next).
68          // If nextValue is an abrupt completion, set iteratorRecord.[[Done]]
69          // to true.
70          // ReturnIfAbrupt(nextValue).
71          nextValue = iterator::IteratorValue(next, fastIteratorResultMap);
72        } catch (e, _message) {
73          goto Reject(e);
74        }
75        // Let nextPromise be ? Call(constructor, _promiseResolve_, «
76        // nextValue »).
77        const nextPromise =
78            CallResolve(constructor, promiseResolveFunction, nextValue);
79
80        // Perform ? Invoke(nextPromise, "then", « resolveElement,
81        //                  resultCapability.[[Reject]] »).
82        const then = GetProperty(nextPromise, kThenString);
83        const thenResult = Call(
84            context, then, nextPromise, UnsafeCast<JSAny>(resolve),
85            UnsafeCast<JSAny>(reject));
86
87        // For catch prediction, mark that rejections here are semantically
88        // handled by the combined Promise.
89        if (IsDebugActive() && !Is<JSPromise>(promise)) deferred {
90            SetPropertyStrict(
91                context, thenResult, kPromiseHandledBySymbol, promise);
92          }
93      }
94    } catch (e, _message) deferred {
95      iterator::IteratorCloseOnException(i);
96      goto Reject(e);
97    }
98  } label Reject(exception: JSAny) deferred {
99    Call(context, UnsafeCast<JSAny>(reject), Undefined, exception);
100    return promise;
101  }
102  unreachable;
103}
104}
105