blob: 90a60678dd07367fe14048027529a0e7cc688a07 [file] [log] [blame]
// 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.h'
#include 'src/builtins/builtins-promise-gen.h'
namespace promise {
type PromiseValueThunkOrReasonContext extends FunctionContext;
extern enum PromiseValueThunkOrReasonContextSlot extends intptr
constexpr 'PromiseBuiltins::PromiseValueThunkOrReasonContextSlot' {
kValueSlot: Slot<PromiseValueThunkOrReasonContext, JSAny>,
kPromiseValueThunkOrReasonContextLength
}
type PromiseFinallyContext extends FunctionContext;
extern enum PromiseFinallyContextSlot extends intptr
constexpr 'PromiseBuiltins::PromiseFinallyContextSlot' {
kOnFinallySlot: Slot<PromiseFinallyContext, Callable>,
kConstructorSlot: Slot<PromiseFinallyContext, Constructor>,
kPromiseFinallyContextLength
}
transitioning javascript builtin
PromiseValueThunkFinally(
js-implicit context: Context, receiver: JSAny)(): JSAny {
const context = %RawDownCast<PromiseValueThunkOrReasonContext>(context);
return *ContextSlot(
context, PromiseValueThunkOrReasonContextSlot::kValueSlot);
}
transitioning javascript builtin
PromiseThrowerFinally(js-implicit context: Context, receiver: JSAny)(): never {
const context = %RawDownCast<PromiseValueThunkOrReasonContext>(context);
const reason =
*ContextSlot(context, PromiseValueThunkOrReasonContextSlot::kValueSlot);
Throw(reason);
}
macro CreateThrowerFunction(implicit context: Context)(
nativeContext: NativeContext, reason: JSAny): JSFunction {
const throwerContext = %RawDownCast<PromiseValueThunkOrReasonContext>(
AllocateSyntheticFunctionContext(
nativeContext,
PromiseValueThunkOrReasonContextSlot::
kPromiseValueThunkOrReasonContextLength));
InitContextSlot(
throwerContext, PromiseValueThunkOrReasonContextSlot::kValueSlot, reason);
const map = *ContextSlot(
nativeContext, ContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
const throwerInfo = PromiseThrowerFinallySharedFunConstant();
return AllocateFunctionWithMapAndContext(map, throwerInfo, throwerContext);
}
transitioning javascript builtin
PromiseCatchFinally(
js-implicit context: Context, receiver: JSAny)(reason: JSAny): JSAny {
const context = %RawDownCast<PromiseFinallyContext>(context);
// 1. Let onFinally be F.[[OnFinally]].
// 2. Assert: IsCallable(onFinally) is true.
const onFinally: Callable =
*ContextSlot(context, PromiseFinallyContextSlot::kOnFinallySlot);
// 3. Let result be ? Call(onFinally).
const result = Call(context, onFinally, Undefined);
// 4. Let C be F.[[Constructor]].
const constructor: Constructor =
*ContextSlot(context, PromiseFinallyContextSlot::kConstructorSlot);
// 5. Assert: IsConstructor(C) is true.
assert(IsConstructor(constructor));
// 6. Let promise be ? PromiseResolve(C, result).
const promise = PromiseResolve(constructor, result);
// 7. Let thrower be equivalent to a function that throws reason.
const nativeContext = LoadNativeContext(context);
const thrower = CreateThrowerFunction(nativeContext, reason);
// 8. Return ? Invoke(promise, "then", « thrower »).
return UnsafeCast<JSAny>(InvokeThen(nativeContext, promise, thrower));
}
macro CreateValueThunkFunction(implicit context: Context)(
nativeContext: NativeContext, value: JSAny): JSFunction {
const valueThunkContext = %RawDownCast<PromiseValueThunkOrReasonContext>(
AllocateSyntheticFunctionContext(
nativeContext,
PromiseValueThunkOrReasonContextSlot::
kPromiseValueThunkOrReasonContextLength));
InitContextSlot(
valueThunkContext, PromiseValueThunkOrReasonContextSlot::kValueSlot,
value);
const map = *ContextSlot(
nativeContext, ContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
const valueThunkInfo = PromiseValueThunkFinallySharedFunConstant();
return AllocateFunctionWithMapAndContext(
map, valueThunkInfo, valueThunkContext);
}
transitioning javascript builtin
PromiseThenFinally(
js-implicit context: Context, receiver: JSAny)(value: JSAny): JSAny {
const context = %RawDownCast<PromiseFinallyContext>(context);
// 1. Let onFinally be F.[[OnFinally]].
// 2. Assert: IsCallable(onFinally) is true.
const onFinally =
*ContextSlot(context, PromiseFinallyContextSlot::kOnFinallySlot);
// 3. Let result be ? Call(onFinally).
const result = Call(context, onFinally, Undefined);
// 4. Let C be F.[[Constructor]].
const constructor =
*ContextSlot(context, PromiseFinallyContextSlot::kConstructorSlot);
// 5. Assert: IsConstructor(C) is true.
assert(IsConstructor(constructor));
// 6. Let promise be ? PromiseResolve(C, result).
const promise = PromiseResolve(constructor, result);
// 7. Let valueThunk be equivalent to a function that returns value.
const nativeContext = LoadNativeContext(context);
const valueThunk = CreateValueThunkFunction(nativeContext, value);
// 8. Return ? Invoke(promise, "then", « valueThunk »).
return UnsafeCast<JSAny>(InvokeThen(nativeContext, promise, valueThunk));
}
struct PromiseFinallyFunctions {
then_finally: JSFunction;
catch_finally: JSFunction;
}
macro CreatePromiseFinallyFunctions(implicit context: Context)(
nativeContext: NativeContext, onFinally: Callable,
constructor: Constructor): PromiseFinallyFunctions {
const promiseContext =
%RawDownCast<PromiseFinallyContext>(AllocateSyntheticFunctionContext(
nativeContext,
PromiseFinallyContextSlot::kPromiseFinallyContextLength));
InitContextSlot(
promiseContext, PromiseFinallyContextSlot::kOnFinallySlot, onFinally);
InitContextSlot(
promiseContext, PromiseFinallyContextSlot::kConstructorSlot, constructor);
const map = *ContextSlot(
nativeContext, ContextSlot::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
const thenFinallyInfo = PromiseThenFinallySharedFunConstant();
const thenFinally =
AllocateFunctionWithMapAndContext(map, thenFinallyInfo, promiseContext);
const catchFinallyInfo = PromiseCatchFinallySharedFunConstant();
const catchFinally =
AllocateFunctionWithMapAndContext(map, catchFinallyInfo, promiseContext);
return PromiseFinallyFunctions{
then_finally: thenFinally,
catch_finally: catchFinally
};
}
transitioning javascript builtin
PromisePrototypeFinally(
js-implicit context: Context, receiver: JSAny)(onFinally: JSAny): JSAny {
// 1. Let promise be the this value.
// 2. If Type(promise) is not Object, throw a TypeError exception.
const jsReceiver = Cast<JSReceiver>(receiver) otherwise ThrowTypeError(
MessageTemplate::kCalledOnNonObject, 'Promise.prototype.finally');
// 3. Let C be ? SpeciesConstructor(promise, %Promise%).
const nativeContext = LoadNativeContext(context);
const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX);
let constructor: Constructor = UnsafeCast<Constructor>(promiseFun);
const receiverMap = jsReceiver.map;
if (!IsJSPromiseMap(receiverMap) ||
!IsPromiseSpeciesLookupChainIntact(nativeContext, receiverMap))
deferred {
constructor =
UnsafeCast<Constructor>(SpeciesConstructor(jsReceiver, promiseFun));
}
// 4. Assert: IsConstructor(C) is true.
assert(IsConstructor(constructor));
// 5. If IsCallable(onFinally) is not true,
// a. Let thenFinally be onFinally.
// b. Let catchFinally be onFinally.
// 6. Else,
// a. Let thenFinally be a new built-in function object as defined
// in ThenFinally Function.
// b. Let catchFinally be a new built-in function object as
// defined in CatchFinally Function.
// c. Set thenFinally and catchFinally's [[Constructor]] internal
// slots to C.
// d. Set thenFinally and catchFinally's [[OnFinally]] internal
// slots to onFinally.
let thenFinally: JSAny;
let catchFinally: JSAny;
typeswitch (onFinally) {
case (onFinally: Callable): {
const pair =
CreatePromiseFinallyFunctions(nativeContext, onFinally, constructor);
thenFinally = pair.then_finally;
catchFinally = pair.catch_finally;
}
case (JSAny): deferred {
thenFinally = onFinally;
catchFinally = onFinally;
}
}
// 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
return UnsafeCast<JSAny>(
InvokeThen(nativeContext, receiver, thenFinally, catchFinally));
}
extern macro PromiseCatchFinallySharedFunConstant(): SharedFunctionInfo;
extern macro PromiseThenFinallySharedFunConstant(): SharedFunctionInfo;
extern macro PromiseThrowerFinallySharedFunConstant(): SharedFunctionInfo;
extern macro PromiseValueThunkFinallySharedFunConstant(): SharedFunctionInfo;
}