| // 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 { |
| |
| macro |
| IsPromiseSpeciesLookupChainIntact( |
| nativeContext: NativeContext, promiseMap: Map): bool { |
| const promisePrototype = |
| *NativeContextSlot(nativeContext, ContextSlot::PROMISE_PROTOTYPE_INDEX); |
| if (IsForceSlowPath()) return false; |
| if (promiseMap.prototype != promisePrototype) return false; |
| return !IsPromiseSpeciesProtectorCellInvalid(); |
| } |
| |
| // 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); |
| |
| // 3. Let C be ? SpeciesConstructor(promise, %Promise%). |
| const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX); |
| |
| // 4. Let resultCapability be ? NewPromiseCapability(C). |
| let resultPromiseOrCapability: JSPromise|PromiseCapability; |
| let resultPromise: JSAny; |
| try { |
| if (IsPromiseSpeciesLookupChainIntact(context, promise.map)) { |
| goto AllocateAndInit; |
| } |
| |
| const constructor = SpeciesConstructor(promise, promiseFun); |
| if (TaggedEqual(constructor, promiseFun)) { |
| goto AllocateAndInit; |
| } else { |
| const promiseCapability = NewPromiseCapability(constructor, True); |
| resultPromiseOrCapability = promiseCapability; |
| resultPromise = promiseCapability.promise; |
| } |
| } label AllocateAndInit { |
| const resultJSPromise = NewJSPromise(promise); |
| resultPromiseOrCapability = resultJSPromise; |
| resultPromise = resultJSPromise; |
| } |
| |
| // 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. |
| |
| // 3. If IsCallable(onFulfilled) is false, then |
| // a. Set onFulfilled to undefined. |
| const onFulfilled = CastOrDefault<Callable>(onFulfilled, Undefined); |
| |
| // 4. If IsCallable(onRejected) is false, then |
| // a. Set onRejected to undefined. |
| const onRejected = CastOrDefault<Callable>(onRejected, Undefined); |
| |
| // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
| // resultCapability). |
| PerformPromiseThenImpl( |
| promise, onFulfilled, onRejected, resultPromiseOrCapability); |
| return resultPromise; |
| } |
| } |