• 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 runtime {
8extern transitioning runtime
9DebugPromiseThen(implicit context: Context)(JSAny): JSAny;
10}
11
12namespace promise {
13
14extern macro
15CodeStubAssembler::HasAsyncEventDelegate(): bool;
16
17macro
18IsPromiseSpeciesLookupChainIntact(
19    nativeContext: NativeContext, promiseMap: Map): bool {
20  const promisePrototype =
21      *NativeContextSlot(nativeContext, ContextSlot::PROMISE_PROTOTYPE_INDEX);
22  if (IsForceSlowPath()) return false;
23  if (promiseMap.prototype != promisePrototype) return false;
24  return !IsPromiseSpeciesProtectorCellInvalid();
25}
26
27// https://tc39.es/ecma262/#sec-promise.prototype.then
28transitioning javascript builtin
29PromisePrototypeThen(js-implicit context: NativeContext, receiver: JSAny)(
30    onFulfilled: JSAny, onRejected: JSAny): JSAny {
31  // 1. Let promise be the this value.
32  // 2. If IsPromise(promise) is false, throw a TypeError exception.
33  const promise = Cast<JSPromise>(receiver) otherwise ThrowTypeError(
34      MessageTemplate::kIncompatibleMethodReceiver, 'Promise.prototype.then',
35      receiver);
36
37  // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
38  const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX);
39
40  // 4. Let resultCapability be ? NewPromiseCapability(C).
41  let resultPromiseOrCapability: JSPromise|PromiseCapability;
42  let resultPromise: JSAny;
43  try {
44    if (IsPromiseSpeciesLookupChainIntact(context, promise.map)) {
45      goto AllocateAndInit;
46    }
47
48    const constructor = SpeciesConstructor(promise, promiseFun);
49    if (TaggedEqual(constructor, promiseFun)) {
50      goto AllocateAndInit;
51    } else {
52      const promiseCapability = NewPromiseCapability(constructor, True);
53      resultPromiseOrCapability = promiseCapability;
54      resultPromise = promiseCapability.promise;
55    }
56  } label AllocateAndInit {
57    const resultJSPromise = NewJSPromise(promise);
58    resultPromiseOrCapability = resultJSPromise;
59    resultPromise = resultJSPromise;
60  }
61
62  // We do some work of the PerformPromiseThen operation here, in that
63  // we check the handlers and turn non-callable handlers into undefined.
64  // This is because this is the one and only callsite of PerformPromiseThen
65  // that has to do this.
66
67  // 3. If IsCallable(onFulfilled) is false, then
68  //    a. Set onFulfilled to undefined.
69  const onFulfilled = CastOrDefault<Callable>(onFulfilled, Undefined);
70
71  // 4. If IsCallable(onRejected) is false, then
72  //    a. Set onRejected to undefined.
73  const onRejected = CastOrDefault<Callable>(onRejected, Undefined);
74
75  // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
76  //    resultCapability).
77  PerformPromiseThenImpl(
78      promise, onFulfilled, onRejected, resultPromiseOrCapability);
79
80  // Async instrumentation for Promise#then(), Promise#catch() and
81  // Promise#finally(), where the latter two both call eventually
82  // call into Promise#then().
83  if (HasAsyncEventDelegate()) {
84    return runtime::DebugPromiseThen(resultPromise);
85  }
86
87  return resultPromise;
88}
89}
90