Commit 5a0e3df6 authored by Joshua Litt's avatar Joshua Litt Committed by Commit Bot

[promises] Port NewPromiseCapability to torque.

Bug: v8:9838
Change-Id: Ibdb985243fe121057f982712b2909f45e0ae175c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1869490
Commit-Queue: Joshua Litt <joshualitt@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64656}
parent 0fb929af
......@@ -1578,6 +1578,8 @@ extern class JSRegExp extends JSObject {
extern transitioning macro AllocateJSIteratorResult(implicit context: Context)(
JSAny, Boolean): JSObject;
extern macro AllocateSyntheticFunctionContext(
NativeContext, constexpr int32): Context;
// Note: Although a condition for a FastJSRegExp is having a positive smi
// lastIndex (see RegExpBuiltinsAssembler::BranchIfFastRegExp), it is possible
......@@ -2770,6 +2772,21 @@ Cast<Smi|PromiseReaction>(o: Object): Smi|PromiseReaction labels CastError {
}
}
Cast<PromiseCapability>(o: HeapObject): PromiseCapability labels CastError {
if (IsPromiseCapability(o)) return %RawDownCast<PromiseCapability>(o);
goto CastError;
}
Cast<SharedFunctionInfo>(o: HeapObject): SharedFunctionInfo labels CastError {
if (IsSharedFunctionInfo(o)) return %RawDownCast<SharedFunctionInfo>(o);
goto CastError;
}
Cast<JSPromise>(o: HeapObject): JSPromise labels CastError {
if (IsJSPromise(o)) return %RawDownCast<JSPromise>(o);
goto CastError;
}
extern macro AllocateHeapNumberWithValue(float64): HeapNumber;
extern macro ChangeInt32ToTagged(int32): Number;
extern macro ChangeUint32ToTagged(uint32): Number;
......@@ -3076,11 +3093,13 @@ extern macro FixedArrayMapConstant(): Map;
extern macro FixedCOWArrayMapConstant(): Map;
extern macro EmptyByteArrayConstant(): ByteArray;
extern macro EmptyFixedArrayConstant(): FixedArray;
extern macro PromiseCapabilityMapConstant(): Map;
const kFixedArrayMap: Map = FixedArrayMapConstant();
const kCOWMap: Map = FixedCOWArrayMapConstant();
const kEmptyByteArray: ByteArray = EmptyByteArrayConstant();
const kEmptyFixedArray: FixedArray = EmptyFixedArrayConstant();
const kPromiseCapabilityMap: Map = PromiseCapabilityMapConstant();
extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
bool;
......@@ -3544,6 +3563,7 @@ extern macro IsJSRegExpStringIterator(HeapObject): bool;
extern macro IsMap(HeapObject): bool;
extern macro IsJSFunction(HeapObject): bool;
extern macro IsJSObject(HeapObject): bool;
extern macro IsJSPromise(HeapObject): bool;
extern macro IsJSTypedArray(HeapObject): bool;
extern macro IsNumberDictionary(HeapObject): bool;
extern macro IsContext(HeapObject): bool;
......@@ -3563,7 +3583,9 @@ extern macro IsSymbol(HeapObject): bool;
extern macro IsJSArrayMap(Map): bool;
extern macro IsExtensibleMap(Map): bool;
extern macro IsJSPrimitiveWrapper(HeapObject): bool;
extern macro IsPromiseCapability(HeapObject): bool;
extern macro IsPromiseReaction(HeapObject): bool;
extern macro IsSharedFunctionInfo(HeapObject): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
extern macro Typeof(JSAny): String;
......
......@@ -295,8 +295,8 @@ TNode<Context> AsyncBuiltinsAssembler::AllocateAsyncIteratorValueUnwrapContext(
TNode<NativeContext> native_context, TNode<Oddball> done) {
CSA_ASSERT(this, IsBoolean(done));
TNode<Context> context =
CreatePromiseContext(native_context, ValueUnwrapContext::kLength);
TNode<Context> context = AllocateSyntheticFunctionContext(
native_context, ValueUnwrapContext::kLength);
StoreContextElementNoWriteBarrier(context, ValueUnwrapContext::kDoneSlot,
done);
return context;
......
......@@ -757,8 +757,6 @@ namespace internal {
TFJ(PromiseCapabilityDefaultResolve, 1, kReceiver, kResolution) \
/* ES6 #sec-getcapabilitiesexecutor-functions */ \
TFJ(PromiseGetCapabilitiesExecutor, 2, kReceiver, kResolve, kReject) \
/* ES6 #sec-newpromisecapability */ \
TFS(NewPromiseCapability, kConstructor, kDebugEvent) \
TFJ(PromiseConstructorLazyDeoptContinuation, 4, kReceiver, kPromise, \
kReject, kException, kResult) \
/* ES6 #sec-promise-executor */ \
......
This diff is collapsed.
......@@ -46,11 +46,6 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
TNode<JSPromise> promise_to_resolve, TNode<JSReceiver> then,
TNode<JSReceiver> thenable, TNode<Context> context);
std::pair<TNode<JSFunction>, TNode<JSFunction>>
CreatePromiseResolvingFunctions(TNode<JSPromise> promise,
TNode<Object> debug_event,
TNode<NativeContext> native_context);
Node* PromiseHasHandler(Node* promise);
// Creates the context used by all Promise.all resolve element closures,
......@@ -71,9 +66,6 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
TNode<JSPromise> promise, TNode<Object> debug_event,
TNode<NativeContext> native_context);
Node* CreatePromiseGetCapabilitiesExecutorContext(Node* promise_capability,
Node* native_context);
// The below methods are only temporarily public until they are
// migrated to torque.
void TriggerPromiseReactions(Node* context, Node* promise, Node* result,
......@@ -90,9 +82,6 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
TNode<HeapObject> on_rejected,
TNode<HeapObject> result_promise_or_capability);
TNode<Context> CreatePromiseContext(TNode<NativeContext> native_context,
int slots);
// We can skip the "resolve" lookup on {constructor} if it's the (initial)
// Promise constructor and the Promise.resolve() protector is intact, as
// that guards the lookup path for the "resolve" property on the %Promise%
......
......@@ -117,14 +117,9 @@ Node* ProxiesCodeStubAssembler::AllocateJSArrayForCodeStubArguments(
Node* ProxiesCodeStubAssembler::CreateProxyRevokeFunctionContext(
Node* proxy, Node* native_context) {
TNode<HeapObject> const context =
Allocate(FixedArray::SizeFor(kProxyContextLength));
TNode<Map> map = CAST(
LoadContextElement(native_context, Context::FUNCTION_CONTEXT_MAP_INDEX));
StoreMapNoWriteBarrier(context, map);
InitializeSyntheticFunctionContext(native_context, context,
kProxyContextLength);
StoreContextElementNoWriteBarrier(CAST(context), kProxySlot, proxy);
TNode<Context> const context = AllocateSyntheticFunctionContext(
CAST(native_context), kProxyContextLength);
StoreContextElementNoWriteBarrier(context, kProxySlot, proxy);
return context;
}
......
......@@ -2,10 +2,34 @@
// 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'
// https://tc39.es/ecma262/#sec-promise-abstract-operations
namespace promise {
const PROMISE_FUNCTION_INDEX: constexpr NativeContextSlot
generates 'Context::PROMISE_FUNCTION_INDEX';
const STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX: constexpr NativeContextSlot
generates 'Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX';
const PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX:
constexpr NativeContextSlot
generates 'Context::PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX'
;
const PROMISE_CAPABILITY_DEFAULT_REJECT_SHARED_FUN_INDEX:
constexpr NativeContextSlot
generates 'Context::PROMISE_CAPABILITY_DEFAULT_REJECT_SHARED_FUN_INDEX'
;
const PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN:
constexpr NativeContextSlot
generates 'Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN';
const kNotConstructor: constexpr MessageTemplate
generates 'MessageTemplate::kNotConstructor';
const kPromiseNonCallable: constexpr MessageTemplate
generates 'MessageTemplate::kPromiseNonCallable';
extern macro AllocateFunctionWithMapAndContext(
Map, SharedFunctionInfo, Context): JSFunction;
extern macro PromiseBuiltinsAssembler::TriggerPromiseReactions(
implicit context:
Context)(Smi|PromiseReaction, JSAny, constexpr PromiseReactionType):
......@@ -34,4 +58,118 @@ namespace promise {
TriggerPromiseReactions(reactions, value, kPromiseReactionFulfill);
return Undefined;
}
const kPromiseCapabilitySize:
constexpr int31 generates 'PromiseCapability::kSize';
const kPromiseBuiltinsCapabilitiesContextLength: constexpr int31
generates 'PromiseBuiltins::kCapabilitiesContextLength';
const kPromiseBuiltinsCapabilitySlot: constexpr ContextSlot
generates 'PromiseBuiltins::kCapabilitySlot';
extern macro
PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Context): JSPromise;
extern macro
PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
JSPromise, Object, NativeContext): Context;
@export
macro CreatePromiseCapabilitiesExecutorContext(
nativeContext: NativeContext, capability: PromiseCapability): Context {
const executorContext = AllocateSyntheticFunctionContext(
nativeContext, kPromiseBuiltinsCapabilitiesContextLength);
executorContext[kPromiseBuiltinsCapabilitySlot] = capability;
return executorContext;
}
macro CreatePromiseCapability(
promise: JSReceiver|Undefined, resolve: JSFunction|Undefined,
reject: JSFunction|Undefined): PromiseCapability {
return new PromiseCapability{
map: kPromiseCapabilityMap,
promise: promise,
resolve: resolve,
reject: reject
};
}
@export
struct PromiseResolvingFunctions {
resolve: JSFunction;
reject: JSFunction;
}
@export
macro CreatePromiseResolvingFunctions(implicit context: Context)(
promise: JSPromise, debugEvent: Object, nativeContext: NativeContext):
PromiseResolvingFunctions {
const promiseContext = CreatePromiseResolvingFunctionsContext(
promise, debugEvent, nativeContext);
const map = UnsafeCast<Map>(
nativeContext[STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]);
const resolveInfo = UnsafeCast<SharedFunctionInfo>(
nativeContext[PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX]);
const resolve: JSFunction =
AllocateFunctionWithMapAndContext(map, resolveInfo, promiseContext);
const rejectInfo = UnsafeCast<SharedFunctionInfo>(
nativeContext[PROMISE_CAPABILITY_DEFAULT_REJECT_SHARED_FUN_INDEX]);
const reject: JSFunction =
AllocateFunctionWithMapAndContext(map, rejectInfo, promiseContext);
return PromiseResolvingFunctions{resolve: resolve, reject: reject};
}
transitioning macro
InnerNewPromiseCapability(implicit context: Context)(
constructor: HeapObject, debugEvent: Object): PromiseCapability {
const nativeContext = LoadNativeContext(context);
if (TaggedEqual(constructor, nativeContext[PROMISE_FUNCTION_INDEX])) {
const promise = AllocateAndInitJSPromise(nativeContext);
const pair =
CreatePromiseResolvingFunctions(promise, debugEvent, nativeContext);
return CreatePromiseCapability(promise, pair.resolve, pair.reject);
} else {
// We have to create the capability before the associated promise
// because the builtin PromiseConstructor uses the executor.
const capability =
CreatePromiseCapability(Undefined, Undefined, Undefined);
const executorContext =
CreatePromiseCapabilitiesExecutorContext(nativeContext, capability);
const executorInfo = UnsafeCast<SharedFunctionInfo>(
nativeContext[PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN]);
const functionMap = UnsafeCast<Map>(
nativeContext[STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX]);
const executor = AllocateFunctionWithMapAndContext(
functionMap, executorInfo, executorContext);
const promiseConstructor = UnsafeCast<Constructor>(constructor);
const promise = Construct(promiseConstructor, executor);
capability.promise = promise;
if (!TaggedIsCallable(capability.resolve) ||
!TaggedIsCallable(capability.reject)) {
ThrowTypeError(kPromiseNonCallable);
}
return capability;
}
}
// https://tc39.es/ecma262/#sec-newpromisecapability
transitioning builtin
NewPromiseCapability(implicit context: Context)(
maybeConstructor: Object, debugEvent: Object): PromiseCapability {
typeswitch (maybeConstructor) {
case (Smi): {
ThrowTypeError(kNotConstructor, maybeConstructor);
}
case (constructor: HeapObject): {
if (!IsConstructor(constructor)) {
ThrowTypeError(kNotConstructor, maybeConstructor);
}
return InnerNewPromiseCapability(constructor, debugEvent);
}
}
}
}
......@@ -13411,16 +13411,27 @@ void CodeStubAssembler::PerformStackCheck(TNode<Context> context) {
BIND(&ok);
}
void CodeStubAssembler::InitializeSyntheticFunctionContext(Node* native_context,
Node* context,
int slots) {
TNode<Context> CodeStubAssembler::AllocateSyntheticFunctionContext(
TNode<NativeContext> native_context, int slots) {
DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
TNode<HeapObject> context_heap_object =
AllocateInNewSpace(FixedArray::SizeFor(slots));
InitializeSyntheticFunctionContext(native_context, context_heap_object,
slots);
return CAST(context_heap_object);
}
void CodeStubAssembler::InitializeSyntheticFunctionContext(
TNode<NativeContext> native_context, TNode<HeapObject> context_heap_object,
int slots) {
DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
TNode<Map> map = CAST(
LoadContextElement(native_context, Context::FUNCTION_CONTEXT_MAP_INDEX));
StoreMapNoWriteBarrier(context, map);
StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
StoreMapNoWriteBarrier(context_heap_object, map);
StoreObjectFieldNoWriteBarrier(context_heap_object, FixedArray::kLengthOffset,
SmiConstant(slots));
TNode<Context> context = CAST(context_heap_object);
TNode<Object> const empty_scope_info =
LoadContextElement(native_context, Context::SCOPE_INFO_INDEX);
StoreContextElementNoWriteBarrier(context, Context::SCOPE_INFO_INDEX,
......
......@@ -2514,7 +2514,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsNotWeakFixedArraySubclass(SloppyTNode<HeapObject> object);
TNode<BoolT> IsZeroOrContext(SloppyTNode<Object> object);
inline Node* IsSharedFunctionInfo(Node* object) {
inline TNode<BoolT> IsSharedFunctionInfo(Node* object) {
return IsSharedFunctionInfoMap(LoadMap(object));
}
......@@ -3556,6 +3556,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
bool ConstexprInt31Equal(int31_t a, int31_t b) { return a == b; }
bool ConstexprInt31NotEqual(int31_t a, int31_t b) { return a != b; }
bool ConstexprInt31GreaterThanEqual(int31_t a, int31_t b) { return a >= b; }
bool ConstexprInt32GreaterThanEqual(int32_t a, int32_t b) { return a >= b; }
uint32_t ConstexprUint32Add(uint32_t a, uint32_t b) { return a + b; }
int31_t ConstexprInt31Add(int31_t a, int31_t b) {
int32_t val;
......@@ -3682,7 +3683,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
Label* if_bailout = nullptr,
TVariable<Int32T>* var_instance_type = nullptr);
void InitializeSyntheticFunctionContext(Node* native_context, Node* context,
TNode<Context> AllocateSyntheticFunctionContext(
TNode<NativeContext> native_context, int slots);
void InitializeSyntheticFunctionContext(TNode<NativeContext> native_context,
TNode<HeapObject> context_heap_object,
int slots);
TNode<JSArray> ArrayCreate(TNode<Context> context, TNode<Number> length);
......
......@@ -40,6 +40,7 @@ using Label = CodeAssemblerLabel;
using Variable = CodeAssemblerVariable;
template <class T>
using TVariable = TypedCodeAssemblerVariable<T>;
using PromiseResolvingFunctions = TorqueStructPromiseResolvingFunctions;
Handle<String> MakeString(const char* str) {
Isolate* isolate = CcTest::i_isolate();
......@@ -2584,9 +2585,9 @@ TEST(CreatePromiseResolvingFunctions) {
TNode<NativeContext> const native_context = m.LoadNativeContext(context);
const TNode<JSPromise> promise =
m.AllocateAndInitJSPromise(m.CAST(context), m.UndefinedConstant());
Node *resolve, *reject;
std::tie(resolve, reject) = m.CreatePromiseResolvingFunctions(
promise, m.BooleanConstant(false), native_context);
PromiseResolvingFunctions funcs = m.CreatePromiseResolvingFunctions(
m.CAST(context), promise, m.BooleanConstant(false), native_context);
Node *resolve = funcs.resolve, *reject = funcs.reject;
TNode<IntPtrT> const kSize = m.IntPtrConstant(2);
TNode<FixedArray> const arr =
m.Cast(m.AllocateFixedArray(PACKED_ELEMENTS, kSize));
......@@ -2719,8 +2720,8 @@ TEST(CreatePromiseGetCapabilitiesExecutorContext) {
capability, PromiseCapability::kResolveOffset, m.UndefinedConstant());
m.StoreObjectFieldNoWriteBarrier(capability, PromiseCapability::kRejectOffset,
m.UndefinedConstant());
Node* const executor_context =
m.CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
Node* const executor_context = m.CreatePromiseCapabilitiesExecutorContext(
native_context, m.CAST(capability));
m.Return(executor_context);
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment