diff --git a/src/builtins/base.tq b/src/builtins/base.tq index a2ce67a19b..e1319fb3f0 100644 --- a/src/builtins/base.tq +++ b/src/builtins/base.tq @@ -1151,12 +1151,16 @@ const kPromisePending: constexpr PromiseState generates 'Promise::kPending'; const kPromiseFulfilled: constexpr PromiseState generates 'Promise::kFulfilled'; +const kPromiseRejected: constexpr PromiseState + generates 'Promise::kRejected'; // JSPromise constants const kJSPromiseStatusMask: constexpr int31 generates 'JSPromise::kStatusMask'; const kJSPromiseStatusShift: constexpr int31 generates 'JSPromise::kStatusShift'; +const kJSPromiseHasHandlerMask: constexpr int31 + generates 'JSPromise::kHasHandlerMask'; @generateCppClass extern class JSPromise extends JSObject { @@ -1174,9 +1178,13 @@ extern class JSPromise extends JSObject { this.flags = this.flags | mask; } + HasHandler(): bool { + return (this.flags & kJSPromiseHasHandlerMask) != 0; + } + // Smi 0 terminated list of PromiseReaction objects in case the JSPromise was // not settled yet, otherwise the result. - reactions_or_result: Smi|PromiseReaction|JSAny; + reactions_or_result: Zero|PromiseReaction|JSAny; flags: Smi; } @@ -1356,6 +1364,10 @@ const kEmptyFixedArrayRootIndex: constexpr RootIndex generates 'RootIndex::kEmptyFixedArray'; const kTheHoleValueRootIndex: constexpr RootIndex generates 'RootIndex::kTheHoleValue'; +const kPromiseFulfillReactionJobTaskMapRootIndex: constexpr RootIndex + generates 'RootIndex::kPromiseFulfillReactionJobTaskMap'; +const kPromiseRejectReactionJobTaskMapRootIndex: constexpr RootIndex + generates 'RootIndex::kPromiseRejectReactionJobTaskMap'; const kInvalidArrayBufferLength: constexpr MessageTemplate generates 'MessageTemplate::kInvalidArrayBufferLength'; @@ -1490,6 +1502,7 @@ const False: False = FalseConstant(); const kEmptyString: EmptyString = EmptyStringConstant(); const kLengthString: String = LengthStringConstant(); const kNaN: NaN = NanConstant(); +const kZero: Zero = %RawDownCast(SmiConstant(0)); const true: constexpr bool generates 'true'; const false: constexpr bool generates 'false'; @@ -1532,6 +1545,14 @@ extern class PromiseCapability extends Struct { type PromiseReactionType extends int31 constexpr 'PromiseReaction::Type'; const kPromiseReactionFulfill: constexpr PromiseReactionType generates 'PromiseReaction::kFulfill'; +const kPromiseReactionReject: constexpr PromiseReactionType + generates 'PromiseReaction::kReject'; +const kPromiseReactionSize: + constexpr int31 generates 'PromiseReaction::kSize'; +const kPromiseReactionFulfillHandlerOffset: constexpr int31 + generates 'PromiseReaction::kFulfillHandlerOffset'; +const kPromiseReactionPromiseOrCapabilityOffset: constexpr int31 + generates 'PromiseReaction::kPromiseOrCapabilityOffset'; @generateCppClass extern class PromiseReaction extends Struct { @@ -1543,6 +1564,14 @@ extern class PromiseReaction extends Struct { promise_or_capability: JSPromise|PromiseCapability|Undefined; } +// PromiseReactionJobTask constants +const kPromiseReactionJobTaskSizeOfAllPromiseReactionJobTasks: constexpr int31 + generates 'PromiseReactionJobTask::kSizeOfAllPromiseReactionJobTasks'; +const kPromiseReactionJobTaskHandlerOffset: constexpr int31 + generates 'PromiseReactionJobTask::kHandlerOffset'; +const kPromiseReactionJobTaskPromiseOrCapabilityOffset: constexpr int31 + generates 'PromiseReactionJobTask::kPromiseOrCapabilityOffset'; + @abstract @generateCppClass extern class PromiseReactionJobTask extends Microtask { @@ -2275,6 +2304,11 @@ Cast(o: Object): PositiveSmi return TaggedToPositiveSmi(o) otherwise CastError; } +Cast(o: Object): Zero labels CastError { + if (TaggedEqual(o, SmiConstant(0))) return %RawDownCast(o); + goto CastError; +} + Cast(o: Object): Number labels CastError { return TaggedToNumber(o) otherwise CastError; @@ -2754,6 +2788,22 @@ Cast(o: HeapObject): JSReceiver|Null } } +Cast(o: HeapObject): + PromiseFulfillReactionJobTask labels CastError { + if (IsPromiseFulfillReactionJobTask(o)) { + return %RawDownCast(o); + } + goto CastError; +} + +Cast(o: HeapObject): + PromiseRejectReactionJobTask labels CastError { + if (IsPromiseRejectReactionJobTask(o)) { + return %RawDownCast(o); + } + goto CastError; +} + Cast(o: HeapObject): PromiseReaction labels CastError { if (IsPromiseReaction(o)) return %RawDownCast(o); goto CastError; @@ -2773,6 +2823,26 @@ Cast(o: Object): Smi|PromiseReaction labels CastError { } } +Cast(implicit context: Context)(o: Object): Zero| + PromiseReaction labels CastError { + typeswitch (o) { + case (o: Zero): { + return o; + } + case (o: PromiseReaction): { + return o; + } + case (Object): { + goto CastError; + } + } +} + +Cast(o: HeapObject): JSBoundFunction labels CastError { + if (IsJSBoundFunction(o)) return %RawDownCast(o); + goto CastError; +} + Cast(o: HeapObject): PromiseCapability labels CastError { if (IsPromiseCapability(o)) return %RawDownCast(o); goto CastError; @@ -3566,6 +3636,7 @@ extern macro IsJSRegExp(HeapObject): bool; extern macro IsJSRegExpStringIterator(HeapObject): bool; extern macro IsMap(HeapObject): bool; extern macro IsJSFunction(HeapObject): bool; +extern macro IsJSBoundFunction(HeapObject): bool; extern macro IsJSObject(HeapObject): bool; extern macro IsJSPromise(HeapObject): bool; extern macro IsJSTypedArray(HeapObject): bool; @@ -3589,6 +3660,8 @@ extern macro IsExtensibleMap(Map): bool; extern macro IsJSPrimitiveWrapper(HeapObject): bool; extern macro IsPromiseCapability(HeapObject): bool; extern macro IsPromiseReaction(HeapObject): bool; +extern macro IsPromiseRejectReactionJobTask(HeapObject): bool; +extern macro IsPromiseFulfillReactionJobTask(HeapObject): bool; extern macro IsSharedFunctionInfo(HeapObject): bool; extern macro IsCustomElementsReceiverInstanceType(int32): bool; extern macro Typeof(JSAny): String; diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index 741d7fbbab..6803ae53b1 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -747,8 +747,6 @@ namespace internal { TFS(ForInFilter, kKey, kObject) \ \ /* Promise */ \ - /* ES #sec-rejectpromise */ \ - TFS(RejectPromise, kPromise, kReason, kDebugEvent) \ /* ES #sec-promise-resolve-functions */ \ /* Starting at step 6 of "Promise Resolve Functions" */ \ TFS(ResolvePromise, kPromise, kResolution) \ diff --git a/src/builtins/builtins-promise-gen.cc b/src/builtins/builtins-promise-gen.cc index 6c84bfe4f8..09c1376845 100644 --- a/src/builtins/builtins-promise-gen.cc +++ b/src/builtins/builtins-promise-gen.cc @@ -246,19 +246,6 @@ TNode PromiseBuiltinsAssembler::PromiseStatus(Node* promise) { return Word32And(SmiToInt32(flags), Int32Constant(JSPromise::kStatusMask)); } -void PromiseBuiltinsAssembler::PromiseSetStatus( - Node* promise, v8::Promise::PromiseState const status) { - CSA_ASSERT(this, - IsPromiseStatus(PromiseStatus(promise), v8::Promise::kPending)); - CHECK_NE(status, v8::Promise::kPending); - - TNode mask = SmiConstant(status); - const TNode flags = - CAST(LoadObjectField(promise, JSPromise::kFlagsOffset)); - StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, - SmiOr(flags, mask)); -} - void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) { const TNode flags = CAST(LoadObjectField(promise, JSPromise::kFlagsOffset)); @@ -441,128 +428,6 @@ PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobTask( return CAST(microtask); } -// ES #sec-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 - // JSPromise in the reverse order. - { - VARIABLE(var_current, MachineRepresentation::kTagged, reactions); - VARIABLE(var_reversed, MachineRepresentation::kTagged, - SmiConstant(Smi::zero())); - - // As an additional safety net against misuse of the V8 Extras API, we - // sanity check the {reactions} to make sure that they are actually - // PromiseReaction instances and not actual JavaScript values (which - // would indicate that we're rejecting or resolving an already settled - // promise), see https://crbug.com/931640 for details on this. - TNode promise_reaction_map = PromiseReactionMapConstant(); - - Label loop(this, {&var_current, &var_reversed}), done_loop(this); - Goto(&loop); - BIND(&loop); - { - Node* current = var_current.value(); - GotoIf(TaggedIsSmi(current), &done_loop); - CSA_CHECK(this, - TaggedEqual(LoadMap(CAST(current)), promise_reaction_map)); - var_current.Bind(LoadObjectField(current, PromiseReaction::kNextOffset)); - StoreObjectField(current, PromiseReaction::kNextOffset, - var_reversed.value()); - var_reversed.Bind(current); - Goto(&loop); - } - BIND(&done_loop); - reactions = var_reversed.value(); - } - - // Morph the {reactions} into PromiseReactionJobTasks and push them - // onto the microtask queue. - { - VARIABLE(var_current, MachineRepresentation::kTagged, reactions); - - Label loop(this, {&var_current}), done_loop(this); - Goto(&loop); - BIND(&loop); - { - Node* current = var_current.value(); - GotoIf(TaggedIsSmi(current), &done_loop); - var_current.Bind(LoadObjectField(current, PromiseReaction::kNextOffset)); - - VARIABLE(var_context, MachineRepresentation::kTagged, - UndefinedConstant()); - - Node* primary_handler; - Node* secondary_handler; - if (type == PromiseReaction::kFulfill) { - primary_handler = - LoadObjectField(current, PromiseReaction::kFulfillHandlerOffset); - secondary_handler = - LoadObjectField(current, PromiseReaction::kRejectHandlerOffset); - } else { - primary_handler = - LoadObjectField(current, PromiseReaction::kRejectHandlerOffset); - secondary_handler = - LoadObjectField(current, PromiseReaction::kFulfillHandlerOffset); - } - - { - Label use_fallback(this, Label::kDeferred), done(this); - ExtractHandlerContext(primary_handler, &var_context); - Branch(IsUndefined(var_context.value()), &use_fallback, &done); - - BIND(&use_fallback); - var_context.Bind(context); - ExtractHandlerContext(secondary_handler, &var_context); - CSA_ASSERT(this, IsNotUndefined(var_context.value())); - Goto(&done); - - BIND(&done); - } - - // Morph {current} from a PromiseReaction into a PromiseReactionJobTask - // and schedule that on the microtask queue. We try to minimize the number - // of stores here to avoid screwing up the store buffer. - STATIC_ASSERT( - static_cast(PromiseReaction::kSize) == - static_cast( - PromiseReactionJobTask::kSizeOfAllPromiseReactionJobTasks)); - if (type == PromiseReaction::kFulfill) { - StoreMapNoWriteBarrier(current, - RootIndex::kPromiseFulfillReactionJobTaskMap); - StoreObjectField(current, PromiseReactionJobTask::kArgumentOffset, - argument); - StoreObjectField(current, PromiseReactionJobTask::kContextOffset, - var_context.value()); - STATIC_ASSERT( - static_cast(PromiseReaction::kFulfillHandlerOffset) == - static_cast(PromiseReactionJobTask::kHandlerOffset)); - STATIC_ASSERT( - static_cast(PromiseReaction::kPromiseOrCapabilityOffset) == - static_cast( - PromiseReactionJobTask::kPromiseOrCapabilityOffset)); - } else { - StoreMapNoWriteBarrier(current, - RootIndex::kPromiseRejectReactionJobTaskMap); - StoreObjectField(current, PromiseReactionJobTask::kArgumentOffset, - argument); - StoreObjectField(current, PromiseReactionJobTask::kContextOffset, - var_context.value()); - StoreObjectField(current, PromiseReactionJobTask::kHandlerOffset, - primary_handler); - STATIC_ASSERT( - static_cast(PromiseReaction::kPromiseOrCapabilityOffset) == - static_cast( - PromiseReactionJobTask::kPromiseOrCapabilityOffset)); - } - CallBuiltin(Builtins::kEnqueueMicrotask, var_context.value(), current); - Goto(&loop); - } - BIND(&done_loop); - } -} - template Node* PromiseBuiltinsAssembler::InvokeThen(Node* native_context, Node* receiver, TArgs... args) { @@ -1680,52 +1545,6 @@ TF_BUILTIN(PromisePrototypeFinally, PromiseBuiltinsAssembler) { var_catch_finally.value())); } -// ES #sec-rejectpromise -TF_BUILTIN(RejectPromise, PromiseBuiltinsAssembler) { - Node* const promise = Parameter(Descriptor::kPromise); - Node* const reason = Parameter(Descriptor::kReason); - Node* const debug_event = Parameter(Descriptor::kDebugEvent); - Node* const context = Parameter(Descriptor::kContext); - - CSA_ASSERT(this, TaggedIsNotSmi(promise)); - CSA_ASSERT(this, IsJSPromise(promise)); - CSA_ASSERT(this, IsBoolean(debug_event)); - Label if_runtime(this, Label::kDeferred); - - // If promise hook is enabled or the debugger is active, let - // the runtime handle this operation, which greatly reduces - // the complexity here and also avoids a couple of back and - // forth between JavaScript and C++ land. - GotoIf(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(), - &if_runtime); - - // 7. If promise.[[PromiseIsHandled]] is false, perform - // HostPromiseRejectionTracker(promise, "reject"). - // We don't try to handle rejecting {promise} without handler - // here, but we let the C++ code take care of this completely. - GotoIfNot(PromiseHasHandler(promise), &if_runtime); - - // 2. Let reactions be promise.[[PromiseRejectReactions]]. - TNode reactions = - LoadObjectField(promise, JSPromise::kReactionsOrResultOffset); - - // 3. Set promise.[[PromiseResult]] to reason. - // 4. Set promise.[[PromiseFulfillReactions]] to undefined. - // 5. Set promise.[[PromiseRejectReactions]] to undefined. - StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reason); - - // 6. Set promise.[[PromiseState]] to "rejected". - PromiseSetStatus(promise, Promise::kRejected); - - // 7. Return TriggerPromiseReactions(reactions, reason). - TriggerPromiseReactions(context, reactions, reason, PromiseReaction::kReject); - Return(UndefinedConstant()); - - BIND(&if_runtime); - TailCallRuntime(Runtime::kRejectPromise, context, promise, reason, - debug_event); -} - // ES #sec-promise-resolve-functions TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) { const TNode promise = CAST(Parameter(Descriptor::kPromise)); diff --git a/src/builtins/builtins-promise-gen.h b/src/builtins/builtins-promise-gen.h index 983e6cbf73..2a905283a6 100644 --- a/src/builtins/builtins-promise-gen.h +++ b/src/builtins/builtins-promise-gen.h @@ -66,11 +66,6 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler { TNode promise, TNode debug_event, TNode 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); @@ -158,8 +153,6 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler { TNode IsPromiseStatus(TNode actual, v8::Promise::PromiseState expected); - void PromiseSetStatus(Node* promise, v8::Promise::PromiseState status); - TNode AllocateJSPromise(TNode context); void ExtractHandlerContext(Node* handler, Variable* var_context); diff --git a/src/builtins/promise-abstract-operations.tq b/src/builtins/promise-abstract-operations.tq index a53236dab9..e4c25447e9 100644 --- a/src/builtins/promise-abstract-operations.tq +++ b/src/builtins/promise-abstract-operations.tq @@ -5,6 +5,11 @@ #include 'src/builtins/builtins-promise.h' #include 'src/builtins/builtins-promise-gen.h' +namespace runtime { + extern transitioning runtime + RejectPromise(implicit context: Context)(JSPromise, JSAny, Boolean): Object; +} + // https://tc39.es/ecma262/#sec-promise-abstract-operations namespace promise { const PROMISE_FUNCTION_INDEX: constexpr NativeContextSlot @@ -30,10 +35,138 @@ namespace promise { extern macro AllocateFunctionWithMapAndContext( Map, SharedFunctionInfo, Context): JSFunction; - extern macro PromiseBuiltinsAssembler::TriggerPromiseReactions( - implicit context: - Context)(Smi|PromiseReaction, JSAny, constexpr PromiseReactionType): - void; + extern macro PromiseReactionMapConstant(): Map; + extern macro PromiseFulfillReactionJobTaskMapConstant(): Map; + extern macro PromiseRejectReactionJobTaskMapConstant(): Map; + + extern transitioning builtin + EnqueueMicrotask(Context, PromiseReactionJobTask): Undefined; + + macro + ExtractHandlerContext(implicit context: Context)(handler: Callable|Undefined): + Context labels NotFound { + let iter: JSAny = handler; + while (true) { + typeswitch (iter) { + case (b: JSBoundFunction): { + iter = b.bound_target_function; + } + case (p: JSProxy): { + iter = p.target; + } + case (f: JSFunction): { + return f.context; + } + case (JSAny): { + break; + } + } + } + goto NotFound; + } + + transitioning macro MorpAndEnqueuePromiseReaction(implicit context: Context)( + promiseReaction: PromiseReaction, argument: JSAny, + reactionType: constexpr PromiseReactionType): void { + let primaryHandler: Callable|Undefined; + let secondaryHandler: Callable|Undefined; + if constexpr (reactionType == kPromiseReactionFulfill) { + primaryHandler = promiseReaction.fulfill_handler; + secondaryHandler = promiseReaction.reject_handler; + } else { + StaticAssert(reactionType == kPromiseReactionReject); + primaryHandler = promiseReaction.reject_handler; + secondaryHandler = promiseReaction.fulfill_handler; + } + + let handlerContext: Context; + try { + handlerContext = ExtractHandlerContext(primaryHandler) otherwise NotFound; + } + label NotFound { + handlerContext = + ExtractHandlerContext(secondaryHandler) otherwise Default; + } + label Default { + handlerContext = context; + } + + // Morph {current} from a PromiseReaction into a PromiseReactionJobTask + // and schedule that on the microtask queue. We try to minimize the number + // of stores here to avoid screwing up the store buffer. + StaticAssert( + kPromiseReactionSize == + kPromiseReactionJobTaskSizeOfAllPromiseReactionJobTasks); + if constexpr (reactionType == kPromiseReactionFulfill) { + promiseReaction.map = PromiseFulfillReactionJobTaskMapConstant(); + const promiseReactionJobTask = + UnsafeCast(promiseReaction); + promiseReactionJobTask.argument = argument; + promiseReactionJobTask.context = handlerContext; + EnqueueMicrotask(handlerContext, promiseReactionJobTask); + StaticAssert( + kPromiseReactionFulfillHandlerOffset == + kPromiseReactionJobTaskHandlerOffset); + StaticAssert( + kPromiseReactionPromiseOrCapabilityOffset == + kPromiseReactionJobTaskPromiseOrCapabilityOffset); + } else { + StaticAssert(reactionType == kPromiseReactionReject); + promiseReaction.map = PromiseRejectReactionJobTaskMapConstant(); + const promiseReactionJobTask = + UnsafeCast(promiseReaction); + promiseReactionJobTask.argument = argument; + promiseReactionJobTask.context = handlerContext; + promiseReactionJobTask.handler = primaryHandler; + EnqueueMicrotask(handlerContext, promiseReactionJobTask); + StaticAssert( + kPromiseReactionPromiseOrCapabilityOffset == + kPromiseReactionJobTaskPromiseOrCapabilityOffset); + } + } + + // https://tc39.es/ecma262/#sec-triggerpromisereactions + transitioning macro TriggerPromiseReactions(implicit context: Context)( + reactions: Zero|PromiseReaction, argument: JSAny, + reactionType: constexpr PromiseReactionType): void { + // We need to reverse the {reactions} here, since we record them on the + // JSPromise in the reverse order. + let current = reactions; + let reversed: Zero|PromiseReaction = kZero; + + // As an additional safety net against misuse of the V8 Extras API, we + // sanity check the {reactions} to make sure that they are actually + // PromiseReaction instances and not actual JavaScript values (which + // would indicate that we're rejecting or resolving an already settled + // promise), see https://crbug.com/931640 for details on this. + while (true) { + typeswitch (current) { + case (Zero): { + break; + } + case (currentReaction: PromiseReaction): { + current = currentReaction.next; + currentReaction.next = reversed; + reversed = currentReaction; + } + } + } + // Morph the {reactions} into PromiseReactionJobTasks and push them + // onto the microtask queue. + current = reversed; + while (true) { + typeswitch (current) { + case (Zero): { + break; + } + case (currentReaction: PromiseReaction): { + current = currentReaction.next; + MorpAndEnqueuePromiseReaction( + currentReaction, argument, reactionType); + } + } + } + } // https://tc39.es/ecma262/#sec-fulfillpromise transitioning builtin @@ -44,7 +177,7 @@ namespace promise { // 2. Let reactions be promise.[[PromiseFulfillReactions]]. const reactions = - UnsafeCast<(Smi | PromiseReaction)>(promise.reactions_or_result); + UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); // 3. Set promise.[[PromiseResult]] to value. // 4. Set promise.[[PromiseFulfillReactions]] to undefined. @@ -59,6 +192,43 @@ namespace promise { return Undefined; } + extern macro PromiseBuiltinsAssembler:: + IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(): bool; + + // https://tc39.es/ecma262/#sec-rejectpromise + transitioning builtin + RejectPromise(implicit context: Context)( + promise: JSPromise, reason: JSAny, debugEvent: Boolean): Object { + // If promise hook is enabled or the debugger is active, let + // the runtime handle this operation, which greatly reduces + // the complexity here and also avoids a couple of back and + // forth between JavaScript and C++ land. + if (IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() || + !promise.HasHandler()) { + // 7. If promise.[[PromiseIsHandled]] is false, perform + // HostPromiseRejectionTracker(promise, "reject"). + // We don't try to handle rejecting {promise} without handler + // here, but we let the C++ code take care of this completely. + return runtime::RejectPromise(promise, reason, debugEvent); + } + + // 2. Let reactions be promise.[[PromiseRejectReactions]]. + const reactions = + UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result); + + // 3. Set promise.[[PromiseResult]] to reason. + // 4. Set promise.[[PromiseFulfillReactions]] to undefined. + // 5. Set promise.[[PromiseRejectReactions]] to undefined. + promise.reactions_or_result = reason; + + // 6. Set promise.[[PromiseState]] to "rejected". + promise.SetStatus(kPromiseRejected); + + // 8. Return TriggerPromiseReactions(reactions, reason). + TriggerPromiseReactions(reactions, reason, kPromiseReactionReject); + return Undefined; + } + const kPromiseCapabilitySize: constexpr int31 generates 'PromiseCapability::kSize'; const kPromiseBuiltinsCapabilitiesContextLength: constexpr int31 diff --git a/src/codegen/code-stub-assembler.cc b/src/codegen/code-stub-assembler.cc index 8c86f67d08..bf7c16b25f 100644 --- a/src/codegen/code-stub-assembler.cc +++ b/src/codegen/code-stub-assembler.cc @@ -6332,6 +6332,16 @@ TNode CodeStubAssembler::IsPromiseReaction( return HasInstanceType(object, PROMISE_REACTION_TYPE); } +TNode CodeStubAssembler::IsPromiseRejectReactionJobTask( + SloppyTNode object) { + return HasInstanceType(object, PROMISE_REJECT_REACTION_JOB_TASK_TYPE); +} + +TNode CodeStubAssembler::IsPromiseFulfillReactionJobTask( + SloppyTNode object) { + return HasInstanceType(object, PROMISE_FULFILL_REACTION_JOB_TASK_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 @@ -6557,6 +6567,11 @@ TNode CodeStubAssembler::IsJSFunction(SloppyTNode object) { return IsJSFunctionMap(LoadMap(object)); } +TNode CodeStubAssembler::IsJSBoundFunction( + SloppyTNode object) { + return HasInstanceType(object, JS_BOUND_FUNCTION_TYPE); +} + TNode CodeStubAssembler::IsJSFunctionMap(SloppyTNode map) { return IsJSFunctionInstanceType(LoadMapInstanceType(map)); } @@ -13102,25 +13117,25 @@ TNode CodeStubAssembler::IsElementsKindInRange( Int32Constant(higher_reference_kind - lower_reference_kind)); } -Node* CodeStubAssembler::IsDebugActive() { +TNode CodeStubAssembler::IsDebugActive() { TNode is_debug_active = Load( ExternalConstant(ExternalReference::debug_is_active_address(isolate()))); return Word32NotEqual(is_debug_active, Int32Constant(0)); } -Node* CodeStubAssembler::IsPromiseHookEnabled() { +TNode CodeStubAssembler::IsPromiseHookEnabled() { const TNode promise_hook = Load( ExternalConstant(ExternalReference::promise_hook_address(isolate()))); return WordNotEqual(promise_hook, IntPtrConstant(0)); } -Node* CodeStubAssembler::HasAsyncEventDelegate() { +TNode CodeStubAssembler::HasAsyncEventDelegate() { const TNode async_event_delegate = Load(ExternalConstant( ExternalReference::async_event_delegate_address(isolate()))); return WordNotEqual(async_event_delegate, IntPtrConstant(0)); } -Node* CodeStubAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate() { +TNode CodeStubAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate() { const TNode promise_hook_or_async_event_delegate = Load(ExternalConstant( ExternalReference::promise_hook_or_async_event_delegate_address( @@ -13128,7 +13143,7 @@ Node* CodeStubAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate() { return Word32NotEqual(promise_hook_or_async_event_delegate, Int32Constant(0)); } -Node* CodeStubAssembler:: +TNode CodeStubAssembler:: IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() { const TNode promise_hook_or_debug_is_active_or_async_event_delegate = Load(ExternalConstant( diff --git a/src/codegen/code-stub-assembler.h b/src/codegen/code-stub-assembler.h index cade3a11ad..f8fbac33e0 100644 --- a/src/codegen/code-stub-assembler.h +++ b/src/codegen/code-stub-assembler.h @@ -15,6 +15,7 @@ #include "src/objects/arguments.h" #include "src/objects/bigint.h" #include "src/objects/objects.h" +#include "src/objects/promise.h" #include "src/objects/shared-function-info.h" #include "src/objects/smi.h" #include "src/roots/roots.h" @@ -2441,6 +2442,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode IsAllocationSiteInstanceType(SloppyTNode instance_type); TNode IsJSFunctionMap(SloppyTNode map); TNode IsJSFunction(SloppyTNode object); + TNode IsJSBoundFunction(SloppyTNode object); TNode IsJSGeneratorObject(TNode object); TNode IsJSGlobalProxyInstanceType(SloppyTNode instance_type); TNode IsJSGlobalProxyMap(SloppyTNode map); @@ -2480,6 +2482,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode IsPropertyArray(SloppyTNode object); TNode IsPropertyCell(SloppyTNode object); TNode IsPromiseReaction(SloppyTNode object); + TNode IsPromiseRejectReactionJobTask(SloppyTNode object); + TNode IsPromiseFulfillReactionJobTask(SloppyTNode object); TNode IsPrototypeInitialArrayPrototype(SloppyTNode context, SloppyTNode map); TNode IsPrototypeTypedArrayPrototype(SloppyTNode context, @@ -3457,7 +3461,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode context); // Debug helpers - Node* IsDebugActive(); + TNode IsDebugActive(); // JSArrayBuffer helpers TNode LoadJSArrayBufferBitField(TNode array_buffer); @@ -3510,10 +3514,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode context); // Promise helpers - Node* IsPromiseHookEnabled(); - Node* HasAsyncEventDelegate(); - Node* IsPromiseHookEnabledOrHasAsyncEventDelegate(); - Node* IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(); + TNode IsPromiseHookEnabled(); + TNode HasAsyncEventDelegate(); + TNode IsPromiseHookEnabledOrHasAsyncEventDelegate(); + TNode IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(); // for..in helpers void CheckPrototypeEnumCache(Node* receiver, Node* receiver_map, diff --git a/src/objects/js-promise.h b/src/objects/js-promise.h index 06569a3fcd..0ca0e5c5a6 100644 --- a/src/objects/js-promise.h +++ b/src/objects/js-promise.h @@ -74,6 +74,7 @@ class JSPromise : public TorqueGeneratedJSPromise { static const int kStatusShift = 0; static const int kStatusMask = 0x3; + static const int kHasHandlerMask = 0x4; STATIC_ASSERT(v8::Promise::kPending == 0); STATIC_ASSERT(v8::Promise::kFulfilled == 1); STATIC_ASSERT(v8::Promise::kRejected == 2);