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-constructor-gen.h' 6#include 'src/builtins/builtins-promise-gen.h' 7 8namespace runtime { 9extern transitioning runtime 10DebugPushPromise(implicit context: Context)(JSAny): JSAny; 11 12extern transitioning runtime 13DebugPopPromise(implicit context: Context)(): JSAny; 14 15extern transitioning runtime 16PromiseHookInit(implicit context: Context)(Object, Object): JSAny; 17} 18 19// https://tc39.es/ecma262/#sec-promise-constructor 20namespace promise { 21 22extern runtime IncrementUseCounter(Context, Smi): void; 23type UseCounterFeature extends int31 24constexpr 'v8::Isolate::UseCounterFeature'; 25const kPromiseConstructorReturnedUndefined: constexpr UseCounterFeature 26 generates 'v8::Isolate::kPromiseConstructorReturnedUndefined'; 27 28extern macro 29IsDebugActive(): bool; 30 31transitioning macro 32HasAccessCheckFailed(implicit context: Context)( 33 nativeContext: NativeContext, promiseFun: JSAny, executor: JSAny): bool { 34 BranchIfAccessCheckFailed(nativeContext, promiseFun, executor) 35 otherwise return true; 36 return false; 37} 38 39extern macro ConstructorBuiltinsAssembler::FastNewObject( 40 Context, JSFunction, JSReceiver): JSObject; 41 42extern macro 43PromiseBuiltinsAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate(): bool; 44 45// https://tc39.es/ecma262/#sec-promise-executor 46transitioning javascript builtin 47PromiseConstructor( 48 js-implicit context: NativeContext, receiver: JSAny, 49 newTarget: JSAny)(executor: JSAny): JSAny { 50 // 1. If NewTarget is undefined, throw a TypeError exception. 51 if (newTarget == Undefined) { 52 ThrowTypeError(MessageTemplate::kNotAPromise, newTarget); 53 } 54 55 // 2. If IsCallable(executor) is false, throw a TypeError exception. 56 if (!Is<Callable>(executor)) { 57 ThrowTypeError(MessageTemplate::kResolverNotAFunction, executor); 58 } 59 60 const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX); 61 62 // Silently fail if the stack looks fishy. 63 if (HasAccessCheckFailed(context, promiseFun, executor)) { 64 IncrementUseCounter( 65 context, SmiConstant(kPromiseConstructorReturnedUndefined)); 66 return Undefined; 67 } 68 69 let result: JSPromise; 70 if (promiseFun == newTarget) { 71 result = NewJSPromise(); 72 } else { 73 result = UnsafeCast<JSPromise>( 74 FastNewObject(context, promiseFun, UnsafeCast<JSReceiver>(newTarget))); 75 PromiseInit(result); 76 if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) { 77 runtime::PromiseHookInit(result, Undefined); 78 } 79 } 80 81 const isDebugActive = IsDebugActive(); 82 if (isDebugActive) runtime::DebugPushPromise(result); 83 84 const funcs = CreatePromiseResolvingFunctions(result, True, context); 85 const resolve = funcs.resolve; 86 const reject = funcs.reject; 87 try { 88 Call(context, UnsafeCast<Callable>(executor), Undefined, resolve, reject); 89 } catch (e) { 90 Call(context, reject, Undefined, e); 91 } 92 93 if (isDebugActive) runtime::DebugPopPromise(); 94 return result; 95} 96 97// Promise.prototype.catch ( onRejected ) 98// https://tc39.es/ecma262/#sec-promise.prototype.catch 99transitioning javascript builtin 100PromisePrototypeCatch( 101 js-implicit context: Context, receiver: JSAny)(onRejected: JSAny): JSAny { 102 // 1. Let promise be the this value. 103 // 2. Return ? Invoke(promise, "then", « undefined, onRejected »). 104 const nativeContext = LoadNativeContext(context); 105 return UnsafeCast<JSAny>( 106 InvokeThen(nativeContext, receiver, Undefined, onRejected)); 107} 108} 109