[promises] Port FulfillPromise to torque.
Bug: v8:9838 Change-Id: I0675b124b2377ff32cb8ae7bbc5eac8ce60314ff Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1854011 Commit-Queue: Joshua Litt <joshualitt@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#64328}
This commit is contained in:
parent
1f0e8d4277
commit
2f8d440679
1
BUILD.gn
1
BUILD.gn
@ -1023,6 +1023,7 @@ torque_files = [
|
||||
"src/builtins/math.tq",
|
||||
"src/builtins/object-fromentries.tq",
|
||||
"src/builtins/object.tq",
|
||||
"src/builtins/promise-abstract-operations.tq",
|
||||
"src/builtins/proxy-constructor.tq",
|
||||
"src/builtins/proxy-delete-property.tq",
|
||||
"src/builtins/proxy-get-property.tq",
|
||||
|
@ -1150,11 +1150,38 @@ extern class JSAsyncGeneratorObject extends JSGeneratorObject {
|
||||
is_awaiting: Smi;
|
||||
}
|
||||
|
||||
// Promise constants
|
||||
type PromiseState extends int31 constexpr 'Promise::PromiseState';
|
||||
const kPromisePending: constexpr PromiseState
|
||||
generates 'Promise::kPending';
|
||||
const kPromiseFulfilled: constexpr PromiseState
|
||||
generates 'Promise::kFulfilled';
|
||||
|
||||
// JSPromise constants
|
||||
const kJSPromiseStatusMask: constexpr int31
|
||||
generates 'JSPromise::kStatusMask';
|
||||
const kJSPromiseStatusShift: constexpr int31
|
||||
generates 'JSPromise::kStatusShift';
|
||||
|
||||
@generateCppClass
|
||||
extern class JSPromise extends JSObject {
|
||||
Status(): PromiseState {
|
||||
StaticAssert(kJSPromiseStatusShift == 0);
|
||||
const status: int32 = Convert<int32>(this.flags) & kJSPromiseStatusMask;
|
||||
return Convert<PromiseState>(status);
|
||||
}
|
||||
|
||||
SetStatus(status: constexpr PromiseState): void {
|
||||
assert(this.Status() == kPromisePending);
|
||||
assert(status != kPromisePending);
|
||||
|
||||
const mask: Smi = SmiConstant(status);
|
||||
this.flags = this.flags | mask;
|
||||
}
|
||||
|
||||
// Smi 0 terminated list of PromiseReaction objects in case the JSPromise was
|
||||
// not settled yet, otherwise the result.
|
||||
reactions_or_result: Object;
|
||||
reactions_or_result: Smi | PromiseReaction | JSAny;
|
||||
flags: Smi;
|
||||
}
|
||||
|
||||
@ -1498,6 +1525,11 @@ extern class PromiseCapability extends Struct {
|
||||
reject: Object;
|
||||
}
|
||||
|
||||
// PromiseReaction constants
|
||||
type PromiseReactionType extends int31 constexpr 'PromiseReaction::Type';
|
||||
const kPromiseReactionFulfill: constexpr PromiseReactionType
|
||||
generates 'PromiseReaction::kFulfill';
|
||||
|
||||
@generateCppClass
|
||||
extern class PromiseReaction extends Struct {
|
||||
next: PromiseReaction | Zero;
|
||||
@ -2165,6 +2197,11 @@ operator '+' macro StringAdd(implicit context: Context)(
|
||||
return StringAdd_CheckNone(a, b);
|
||||
}
|
||||
|
||||
operator '==' macro PromiseStateEquals(
|
||||
s1: PromiseState, s2: PromiseState): bool {
|
||||
return Word32Equal(s1, s2);
|
||||
}
|
||||
|
||||
extern macro TaggedIsSmi(Object): bool;
|
||||
extern macro TaggedIsNotSmi(Object): bool;
|
||||
extern macro TaggedIsPositiveSmi(Object): bool;
|
||||
@ -2705,6 +2742,26 @@ Cast<JSReceiver | Null>(o: HeapObject): JSReceiver | Null
|
||||
}
|
||||
}
|
||||
|
||||
Cast<PromiseReaction>(o: HeapObject): PromiseReaction labels CastError {
|
||||
if (IsPromiseReaction(o)) return %RawDownCast<PromiseReaction>(o);
|
||||
goto CastError;
|
||||
}
|
||||
|
||||
Cast<Smi | PromiseReaction>(o: Object): Smi |
|
||||
PromiseReaction labels CastError {
|
||||
typeswitch (o) {
|
||||
case (o: Smi): {
|
||||
return o;
|
||||
}
|
||||
case (o: PromiseReaction): {
|
||||
return o;
|
||||
}
|
||||
case (Object): {
|
||||
goto CastError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern macro AllocateHeapNumberWithValue(float64): HeapNumber;
|
||||
extern macro ChangeInt32ToTagged(int32): Number;
|
||||
extern macro ChangeUint32ToTagged(uint32): Number;
|
||||
@ -2857,6 +2914,10 @@ FromConstexpr<ContextSlot, constexpr ContextSlot>(c: constexpr ContextSlot):
|
||||
ContextSlot {
|
||||
return IntPtrConstant(c);
|
||||
}
|
||||
FromConstexpr<PromiseState, constexpr PromiseState>(s: constexpr PromiseState):
|
||||
PromiseState {
|
||||
return %FromConstexpr<PromiseState>(s);
|
||||
}
|
||||
|
||||
macro Convert<To: type, From: type>(i: From): To {
|
||||
return i;
|
||||
@ -2991,6 +3052,9 @@ extern macro SmiToBInt(Smi): bint;
|
||||
Convert<bint, Smi>(v: Smi): bint {
|
||||
return SmiToBInt(v);
|
||||
}
|
||||
Convert<PromiseState, int32>(s: int32): PromiseState {
|
||||
return %RawDownCast<PromiseState>(s);
|
||||
}
|
||||
|
||||
macro Is<A: type, B: type>(implicit context: Context)(o: B): bool {
|
||||
Cast<A>(o) otherwise return false;
|
||||
@ -3491,6 +3555,7 @@ extern macro IsSymbol(HeapObject): bool;
|
||||
extern macro IsJSArrayMap(Map): bool;
|
||||
extern macro IsExtensibleMap(Map): bool;
|
||||
extern macro IsJSPrimitiveWrapper(HeapObject): bool;
|
||||
extern macro IsPromiseReaction(HeapObject): bool;
|
||||
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
|
||||
extern macro Typeof(JSAny): String;
|
||||
|
||||
|
@ -762,8 +762,6 @@ namespace internal {
|
||||
TFS(ForInFilter, kKey, kObject) \
|
||||
\
|
||||
/* Promise */ \
|
||||
/* ES #sec-fulfillpromise */ \
|
||||
TFS(FulfillPromise, kPromise, kValue) \
|
||||
/* ES #sec-rejectpromise */ \
|
||||
TFS(RejectPromise, kPromise, kReason, kDebugEvent) \
|
||||
/* ES #sec-promise-resolve-functions */ \
|
||||
|
@ -564,7 +564,7 @@ PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobTask(
|
||||
}
|
||||
|
||||
// ES #sec-triggerpromisereactions
|
||||
Node* PromiseBuiltinsAssembler::TriggerPromiseReactions(
|
||||
void PromiseBuiltinsAssembler::TriggerPromiseReactions(
|
||||
Node* context, Node* reactions, Node* argument,
|
||||
PromiseReaction::Type type) {
|
||||
// We need to reverse the {reactions} here, since we record them on the
|
||||
@ -683,8 +683,6 @@ Node* PromiseBuiltinsAssembler::TriggerPromiseReactions(
|
||||
}
|
||||
BIND(&done_loop);
|
||||
}
|
||||
|
||||
return UndefinedConstant();
|
||||
}
|
||||
|
||||
template <typename... TArgs>
|
||||
@ -1849,32 +1847,6 @@ TF_BUILTIN(PromisePrototypeFinally, PromiseBuiltinsAssembler) {
|
||||
var_catch_finally.value()));
|
||||
}
|
||||
|
||||
// ES #sec-fulfillpromise
|
||||
TF_BUILTIN(FulfillPromise, PromiseBuiltinsAssembler) {
|
||||
Node* const promise = Parameter(Descriptor::kPromise);
|
||||
Node* const value = Parameter(Descriptor::kValue);
|
||||
Node* const context = Parameter(Descriptor::kContext);
|
||||
|
||||
CSA_ASSERT(this, TaggedIsNotSmi(promise));
|
||||
CSA_ASSERT(this, IsJSPromise(promise));
|
||||
|
||||
// 2. Let reactions be promise.[[PromiseFulfillReactions]].
|
||||
TNode<Object> const reactions =
|
||||
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
|
||||
|
||||
// 3. Set promise.[[PromiseResult]] to value.
|
||||
// 4. Set promise.[[PromiseFulfillReactions]] to undefined.
|
||||
// 5. Set promise.[[PromiseRejectReactions]] to undefined.
|
||||
StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, value);
|
||||
|
||||
// 6. Set promise.[[PromiseState]] to "fulfilled".
|
||||
PromiseSetStatus(promise, Promise::kFulfilled);
|
||||
|
||||
// 7. Return TriggerPromiseReactions(reactions, value).
|
||||
Return(TriggerPromiseReactions(context, reactions, value,
|
||||
PromiseReaction::kFulfill));
|
||||
}
|
||||
|
||||
// ES #sec-rejectpromise
|
||||
TF_BUILTIN(RejectPromise, PromiseBuiltinsAssembler) {
|
||||
Node* const promise = Parameter(Descriptor::kPromise);
|
||||
@ -1913,8 +1885,8 @@ TF_BUILTIN(RejectPromise, PromiseBuiltinsAssembler) {
|
||||
PromiseSetStatus(promise, Promise::kRejected);
|
||||
|
||||
// 7. Return TriggerPromiseReactions(reactions, reason).
|
||||
Return(TriggerPromiseReactions(context, reactions, reason,
|
||||
PromiseReaction::kReject));
|
||||
TriggerPromiseReactions(context, reactions, reason, PromiseReaction::kReject);
|
||||
Return(UndefinedConstant());
|
||||
|
||||
BIND(&if_runtime);
|
||||
TailCallRuntime(Runtime::kRejectPromise, context, promise, reason,
|
||||
|
@ -74,6 +74,11 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
|
||||
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,
|
||||
PromiseReaction::Type type);
|
||||
|
||||
protected:
|
||||
void PromiseInit(Node* promise);
|
||||
|
||||
@ -88,9 +93,6 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<Context> CreatePromiseContext(TNode<NativeContext> native_context,
|
||||
int slots);
|
||||
|
||||
Node* TriggerPromiseReactions(Node* context, Node* promise, Node* result,
|
||||
PromiseReaction::Type type);
|
||||
|
||||
// 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%
|
||||
|
36
src/builtins/promise-abstract-operations.tq
Normal file
36
src/builtins/promise-abstract-operations.tq
Normal file
@ -0,0 +1,36 @@
|
||||
// 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-gen.h'
|
||||
|
||||
// https://tc39.es/ecma262/#sec-promise-abstract-operations
|
||||
namespace promise {
|
||||
extern macro PromiseBuiltinsAssembler::TriggerPromiseReactions(
|
||||
implicit context: Context)(
|
||||
Smi | PromiseReaction, JSAny, constexpr PromiseReactionType): void;
|
||||
|
||||
// https://tc39.es/ecma262/#sec-fulfillpromise
|
||||
transitioning builtin
|
||||
FulfillPromise(implicit context: Context)(promise: JSPromise, value: JSAny):
|
||||
Undefined {
|
||||
// Assert: The value of promise.[[PromiseState]] is "pending".
|
||||
assert(promise.Status() == kPromisePending);
|
||||
|
||||
// 2. Let reactions be promise.[[PromiseFulfillReactions]].
|
||||
const reactions =
|
||||
UnsafeCast<(Smi | PromiseReaction)>(promise.reactions_or_result);
|
||||
|
||||
// 3. Set promise.[[PromiseResult]] to value.
|
||||
// 4. Set promise.[[PromiseFulfillReactions]] to undefined.
|
||||
// 5. Set promise.[[PromiseRejectReactions]] to undefined.
|
||||
promise.reactions_or_result = value;
|
||||
|
||||
// 6. Set promise.[[PromiseState]] to "fulfilled".
|
||||
promise.SetStatus(kPromiseFulfilled);
|
||||
|
||||
// 7. Return TriggerPromiseReactions(reactions, value).
|
||||
TriggerPromiseReactions(reactions, value, kPromiseReactionFulfill);
|
||||
return Undefined;
|
||||
}
|
||||
}
|
@ -6386,6 +6386,11 @@ TNode<BoolT> CodeStubAssembler::IsPropertyArray(
|
||||
return HasInstanceType(object, PROPERTY_ARRAY_TYPE);
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsPromiseReaction(
|
||||
SloppyTNode<HeapObject> object) {
|
||||
return HasInstanceType(object, PROMISE_REACTION_TYPE);
|
||||
}
|
||||
|
||||
// This complicated check is due to elements oddities. If a smi array is empty
|
||||
// after Array.p.shift, it is replaced by the empty array constant. If it is
|
||||
// later filled with a double element, we try to grow it but pass in a double
|
||||
|
@ -2483,6 +2483,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TNode<BoolT> IsPromiseCapability(SloppyTNode<HeapObject> object);
|
||||
TNode<BoolT> IsPropertyArray(SloppyTNode<HeapObject> object);
|
||||
TNode<BoolT> IsPropertyCell(SloppyTNode<HeapObject> object);
|
||||
TNode<BoolT> IsPromiseReaction(SloppyTNode<HeapObject> object);
|
||||
TNode<BoolT> IsPrototypeInitialArrayPrototype(SloppyTNode<Context> context,
|
||||
SloppyTNode<Map> map);
|
||||
TNode<BoolT> IsPrototypeTypedArrayPrototype(SloppyTNode<Context> context,
|
||||
|
Loading…
Reference in New Issue
Block a user