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::IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate( 44 uint32): bool; 45 46// https://tc39.es/ecma262/#sec-promise-executor 47transitioning javascript builtin 48PromiseConstructor( 49 js-implicit context: NativeContext, receiver: JSAny, 50 newTarget: JSAny)(executor: JSAny): JSAny { 51 // 1. If NewTarget is undefined, throw a TypeError exception. 52 if (newTarget == Undefined) { 53 ThrowTypeError(MessageTemplate::kPromiseNewTargetUndefined); 54 } 55 56 // 2. If IsCallable(executor) is false, throw a TypeError exception. 57 if (!Is<Callable>(executor)) { 58 ThrowTypeError(MessageTemplate::kResolverNotAFunction, executor); 59 } 60 61 const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX); 62 63 // Throw no access type error if the stack looks fishy. 64 if (HasAccessCheckFailed(context, promiseFun, executor)) { 65 IncrementUseCounter( 66 context, SmiConstant(kPromiseConstructorReturnedUndefined)); 67 runtime::ThrowNoAccess(); 68 } 69 70 let result: JSPromise; 71 if (promiseFun == newTarget) { 72 result = NewJSPromise(); 73 } else { 74 result = UnsafeCast<JSPromise>( 75 FastNewObject(context, promiseFun, UnsafeCast<JSReceiver>(newTarget))); 76 PromiseInit(result); 77 RunAnyPromiseHookInit(result, Undefined); 78 } 79 80 const isDebugActive = IsDebugActive(); 81 if (isDebugActive) runtime::DebugPushPromise(result); 82 83 const funcs = CreatePromiseResolvingFunctions(result, True, context); 84 const resolve = funcs.resolve; 85 const reject = funcs.reject; 86 try { 87 Call(context, UnsafeCast<Callable>(executor), Undefined, resolve, reject); 88 } catch (e, _message) { 89 Call(context, reject, Undefined, e); 90 } 91 92 if (isDebugActive) runtime::DebugPopPromise(); 93 return result; 94} 95 96// Promise.prototype.catch ( onRejected ) 97// https://tc39.es/ecma262/#sec-promise.prototype.catch 98transitioning javascript builtin 99PromisePrototypeCatch( 100 js-implicit context: Context, receiver: JSAny)(onRejected: JSAny): JSAny { 101 // 1. Let promise be the this value. 102 // 2. Return ? Invoke(promise, "then", « undefined, onRejected »). 103 // This builtin is attached to JSFunction created by the bootstrapper so 104 // `context` is the native context. 105 check(Is<NativeContext>(context)); 106 const nativeContext = UnsafeCast<NativeContext>(context); 107 return UnsafeCast<JSAny>( 108 InvokeThen(nativeContext, receiver, Undefined, onRejected)); 109} 110} 111