// 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-constructor-gen.h' #include 'src/builtins/builtins-promise-gen.h' namespace runtime { extern transitioning runtime DebugPushPromise(implicit context: Context)(JSAny): JSAny; extern transitioning runtime DebugPopPromise(implicit context: Context)(): JSAny; extern transitioning runtime PromiseHookInit(implicit context: Context)(Object, Object): JSAny; } // https://tc39.es/ecma262/#sec-promise-constructor namespace promise { extern runtime IncrementUseCounter(Context, Smi): void; type UseCounterFeature extends int31 constexpr 'v8::Isolate::UseCounterFeature'; const kPromiseConstructorReturnedUndefined: constexpr UseCounterFeature generates 'v8::Isolate::kPromiseConstructorReturnedUndefined'; extern macro IsDebugActive(): bool; transitioning macro HasAccessCheckFailed(implicit context: Context)( nativeContext: NativeContext, promiseFun: JSAny, executor: JSAny): bool { BranchIfAccessCheckFailed(nativeContext, promiseFun, executor) otherwise return true; return false; } extern macro ConstructorBuiltinsAssembler::FastNewObject( Context, JSFunction, JSReceiver): JSObject; extern macro PromiseBuiltinsAssembler::IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate( uint32): bool; // https://tc39.es/ecma262/#sec-promise-executor transitioning javascript builtin PromiseConstructor( js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny)(executor: JSAny): JSAny { // 1. If NewTarget is undefined, throw a TypeError exception. if (newTarget == Undefined) { ThrowTypeError(MessageTemplate::kPromiseNewTargetUndefined); } // 2. If IsCallable(executor) is false, throw a TypeError exception. if (!Is(executor)) { ThrowTypeError(MessageTemplate::kResolverNotAFunction, executor); } const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX); // Throw no access type error if the stack looks fishy. if (HasAccessCheckFailed(context, promiseFun, executor)) { IncrementUseCounter( context, SmiConstant(kPromiseConstructorReturnedUndefined)); runtime::ThrowNoAccess(); } let result: JSPromise; if (promiseFun == newTarget) { result = NewJSPromise(); } else { result = UnsafeCast( FastNewObject(context, promiseFun, UnsafeCast(newTarget))); PromiseInit(result); RunAnyPromiseHookInit(result, Undefined); } const isDebugActive = IsDebugActive(); if (isDebugActive) runtime::DebugPushPromise(result); const funcs = CreatePromiseResolvingFunctions(result, True, context); const resolve = funcs.resolve; const reject = funcs.reject; try { Call(context, UnsafeCast(executor), Undefined, resolve, reject); } catch (e, _message) { Call(context, reject, Undefined, e); } if (isDebugActive) runtime::DebugPopPromise(); return result; } // Promise.prototype.catch ( onRejected ) // https://tc39.es/ecma262/#sec-promise.prototype.catch transitioning javascript builtin PromisePrototypeCatch( js-implicit context: Context, receiver: JSAny)(onRejected: JSAny): JSAny { // 1. Let promise be the this value. // 2. Return ? Invoke(promise, "then", « undefined, onRejected »). // This builtin is attached to JSFunction created by the bootstrapper so // `context` is the native context. check(Is(context)); const nativeContext = UnsafeCast(context); return UnsafeCast( InvokeThen(nativeContext, receiver, Undefined, onRejected)); } }