promise-then.tq 3.13 KB
Newer Older
1 2 3 4 5 6
// 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'

7 8 9 10 11
namespace runtime {
extern transitioning runtime
DebugPromiseThen(implicit context: Context)(JSAny): JSAny;
}

12 13
namespace promise {

14 15 16
extern macro
CodeStubAssembler::HasAsyncEventDelegate(): bool;

17 18 19 20
macro
IsPromiseSpeciesLookupChainIntact(
    nativeContext: NativeContext, promiseMap: Map): bool {
  const promisePrototype =
21
      *NativeContextSlot(nativeContext, ContextSlot::PROMISE_PROTOTYPE_INDEX);
22 23 24 25
  if (IsForceSlowPath()) return false;
  if (promiseMap.prototype != promisePrototype) return false;
  return !IsPromiseSpeciesProtectorCellInvalid();
}
26

27 28 29 30 31 32 33 34 35
// https://tc39.es/ecma262/#sec-promise.prototype.then
transitioning javascript builtin
PromisePrototypeThen(js-implicit context: NativeContext, receiver: JSAny)(
    onFulfilled: JSAny, onRejected: JSAny): JSAny {
  // 1. Let promise be the this value.
  // 2. If IsPromise(promise) is false, throw a TypeError exception.
  const promise = Cast<JSPromise>(receiver) otherwise ThrowTypeError(
      MessageTemplate::kIncompatibleMethodReceiver, 'Promise.prototype.then',
      receiver);
36

37
  // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
38
  const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX);
39

40 41 42 43 44 45 46
  // 4. Let resultCapability be ? NewPromiseCapability(C).
  let resultPromiseOrCapability: JSPromise|PromiseCapability;
  let resultPromise: JSAny;
  try {
    if (IsPromiseSpeciesLookupChainIntact(context, promise.map)) {
      goto AllocateAndInit;
    }
47

48 49 50 51 52 53 54
    const constructor = SpeciesConstructor(promise, promiseFun);
    if (TaggedEqual(constructor, promiseFun)) {
      goto AllocateAndInit;
    } else {
      const promiseCapability = NewPromiseCapability(constructor, True);
      resultPromiseOrCapability = promiseCapability;
      resultPromise = promiseCapability.promise;
55
    }
56 57 58 59 60
  } label AllocateAndInit {
    const resultJSPromise = NewJSPromise(promise);
    resultPromiseOrCapability = resultJSPromise;
    resultPromise = resultJSPromise;
  }
61

62 63 64 65
  // We do some work of the PerformPromiseThen operation here, in that
  // we check the handlers and turn non-callable handlers into undefined.
  // This is because this is the one and only callsite of PerformPromiseThen
  // that has to do this.
66

67 68 69
  // 3. If IsCallable(onFulfilled) is false, then
  //    a. Set onFulfilled to undefined.
  const onFulfilled = CastOrDefault<Callable>(onFulfilled, Undefined);
70

71 72 73
  // 4. If IsCallable(onRejected) is false, then
  //    a. Set onRejected to undefined.
  const onRejected = CastOrDefault<Callable>(onRejected, Undefined);
74

75 76 77 78
  // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
  //    resultCapability).
  PerformPromiseThenImpl(
      promise, onFulfilled, onRejected, resultPromiseOrCapability);
79 80 81 82 83 84 85 86

  // Async instrumentation for Promise#then(), Promise#catch() and
  // Promise#finally(), where the latter two both call eventually
  // call into Promise#then().
  if (HasAsyncEventDelegate()) {
    return runtime::DebugPromiseThen(resultPromise);
  }

87 88
  return resultPromise;
}
89
}