Welcome to mirror list, hosted at ThFree Co, Russian Federation.

promise-race.tq « builtins « src « v8 « deps - github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 27d2038398ab4bded27ed78b1a0dad6f97f786b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include 'src/builtins/builtins-promise-gen.h'

namespace promise {

extern macro PromiseForwardingHandlerSymbolConstant(): Symbol;
const kPromiseForwardingHandlerSymbol: Symbol =
    PromiseForwardingHandlerSymbolConstant();
extern macro PromiseHandledBySymbolConstant(): Symbol;
const kPromiseHandledBySymbol: Symbol = PromiseHandledBySymbolConstant();
extern macro ResolveStringConstant(): String;
const kResolveString: String = ResolveStringConstant();
extern macro SetPropertyStrict(Context, Object, Object, Object): Object;
extern macro IsPromiseResolveProtectorCellInvalid(): bool;

macro IsPromiseResolveLookupChainIntact(implicit context: Context)(
    nativeContext: NativeContext, constructor: JSReceiver): bool {
  if (IsForceSlowPath()) return false;
  const promiseFun = UnsafeCast<JSFunction>(
      nativeContext[NativeContextSlot::PROMISE_FUNCTION_INDEX]);
  return promiseFun == constructor && !IsPromiseResolveProtectorCellInvalid();
}

// https://tc39.es/ecma262/#sec-promise.race
transitioning javascript builtin
PromiseRace(
    js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny {
  const receiver = Cast<JSReceiver>(receiver)
      otherwise ThrowTypeError(MessageTemplate::kCalledOnNonObject, 'Promise.race');

  // Let promiseCapability be ? NewPromiseCapability(C).
  // Don't fire debugEvent so that forwarding the rejection through all does
  // not trigger redundant ExceptionEvents
  const capability = NewPromiseCapability(receiver, False);
  const resolve = capability.resolve;
  const reject = capability.reject;
  const promise = capability.promise;

  // For catch prediction, don't treat the .then calls as handling it;
  // instead, recurse outwards.
  if (IsDebugActive()) deferred {
      SetPropertyStrict(context, reject, kPromiseForwardingHandlerSymbol, True);
    }

  try {
    // Let iterator be GetIterator(iterable).
    // IfAbruptRejectPromise(iterator, promiseCapability).
    let i: iterator::IteratorRecord;
    try {
      i = iterator::GetIterator(iterable);
    } catch (e) deferred {
      goto Reject(e);
    }

    // Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability).
    try {
      // We can skip the "resolve" lookup on {constructor} if it's the
      // Promise constructor and the Promise.resolve protector is intact,
      // as that guards the lookup path for the "resolve" property on the
      // Promise constructor.
      const nativeContext = LoadNativeContext(context);
      let promiseResolveFunction: JSAny = Undefined;
      if (!IsPromiseResolveLookupChainIntact(nativeContext, receiver))
        deferred {
          // 3. Let _promiseResolve_ be ? Get(_constructor_, `"resolve"`).
          const resolve = GetProperty(receiver, kResolveString);

          // 4. If IsCallable(_promiseResolve_) is *false*, throw a
          // *TypeError* exception.
          promiseResolveFunction = Cast<Callable>(resolve)
              otherwise ThrowTypeError(
              MessageTemplate::kCalledNonCallable, 'resolve');
        }

      const fastIteratorResultMap = UnsafeCast<Map>(
          nativeContext[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]);
      while (true) {
        let nextValue: JSAny;
        try {
          // Let next be IteratorStep(iteratorRecord.[[Iterator]]).
          // If next is an abrupt completion, set iteratorRecord.[[Done]] to
          // true. ReturnIfAbrupt(next).
          const next: JSReceiver = iterator::IteratorStep(
              i, fastIteratorResultMap) otherwise return promise;

          // Let nextValue be IteratorValue(next).
          // If nextValue is an abrupt completion, set iteratorRecord.[[Done]]
          // to true.
          // ReturnIfAbrupt(nextValue).
          nextValue = iterator::IteratorValue(next, fastIteratorResultMap);
        } catch (e) {
          goto Reject(e);
        }
        // Let nextPromise be ? Call(constructor, _promiseResolve_, «
        // nextValue »).
        const nextPromise = CallResolve(
            UnsafeCast<Constructor>(receiver), promiseResolveFunction,
            nextValue);

        // Perform ? Invoke(nextPromise, "then", « resolveElement,
        //                  resultCapability.[[Reject]] »).
        const then = GetProperty(nextPromise, kThenString);
        const thenResult = Call(
            context, then, nextPromise, UnsafeCast<JSAny>(resolve),
            UnsafeCast<JSAny>(reject));

        // For catch prediction, mark that rejections here are semantically
        // handled by the combined Promise.
        if (IsDebugActive() && !Is<JSPromise>(promise)) deferred {
            SetPropertyStrict(
                context, thenResult, kPromiseHandledBySymbol, promise);
          }
      }
    } catch (e) deferred {
      iterator::IteratorCloseOnException(i);
      goto Reject(e);
    }
  } label Reject(exception: Object) deferred {
    Call(
        context, UnsafeCast<JSAny>(reject), Undefined,
        UnsafeCast<JSAny>(exception));
    return promise;
  }
  unreachable;
}
}