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