chore: cherry-pick 62af07e96173 from v8

This commit is contained in:
Keeley Hammond
2025-11-18 09:09:41 -08:00
parent d1d6befcf1
commit 4edc4ca5e5
2 changed files with 405 additions and 0 deletions

View File

@@ -1 +1,2 @@
chore_allow_customizing_microtask_policy_per_context.patch
cherry-pick-62af07e96173.patch

View File

@@ -0,0 +1,404 @@
From 62af07e96173fb03b504f60b01e67d9f2dda695b Mon Sep 17 00:00:00 2001
From: Igor Sheludko <ishell@chromium.org>
Date: Mon, 13 Oct 2025 14:22:20 +0200
Subject: [PATCH] [ic] Cleanup AccessorAssembler::CallGetterIfAccessor()
This CL
- reorders parameters to make |expected_receiver_mode| a mandatory
one and properly computed,
- makes sure we don't pass PropertyCell as a holder when JSReceiver is
expected.
Bug: 450328966
Change-Id: I921dfbd99245d01143600b4f4713fe602c817657
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7036691
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#103085}
---
diff --git a/src/codegen/code-stub-assembler.cc b/src/codegen/code-stub-assembler.cc
index a8e0c85..b749310 100644
--- a/src/codegen/code-stub-assembler.cc
+++ b/src/codegen/code-stub-assembler.cc
@@ -11662,7 +11662,8 @@
var_value = CallGetterIfAccessor(
value_or_accessor, object, var_details.value(), context,
- object, next_key, &slow_load, kCallJSGetterUseCachedName);
+ object, kExpectingJSReceiver, next_key, &slow_load,
+ kCallJSGetterUseCachedName);
Goto(&value_ready);
BIND(&slow_load);
@@ -12158,15 +12159,11 @@
TNode<SwissNameDictionary> dictionary, TNode<IntPtrT> name_index,
TVariable<Uint32T>* var_details, TVariable<Object>* var_value);
-// |value| is the property backing store's contents, which is either a value or
-// an accessor pair, as specified by |details|. |holder| is a JSReceiver or a
-// PropertyCell. Returns either the original value, or the result of the getter
-// call.
TNode<Object> CodeStubAssembler::CallGetterIfAccessor(
- TNode<Object> value, TNode<Union<JSReceiver, PropertyCell>> holder,
+ TNode<Object> value, std::optional<TNode<JSReceiver>> holder,
TNode<Uint32T> details, TNode<Context> context, TNode<JSAny> receiver,
- TNode<Object> name, Label* if_bailout, GetOwnPropertyMode mode,
- ExpectedReceiverMode expected_receiver_mode) {
+ ExpectedReceiverMode expected_receiver_mode, TNode<Object> name,
+ Label* if_bailout, GetOwnPropertyMode mode) {
TVARIABLE(Object, var_value, value);
Label done(this), if_accessor_info(this, Label::kDeferred);
@@ -12207,44 +12204,51 @@
BIND(&if_function_template_info);
{
- Label use_cached_property(this);
- TNode<HeapObject> cached_property_name = LoadObjectField<HeapObject>(
- getter, FunctionTemplateInfo::kCachedPropertyNameOffset);
+ if (holder.has_value()) {
+ Label use_cached_property(this);
+ TNode<HeapObject> cached_property_name = LoadObjectField<HeapObject>(
+ getter, FunctionTemplateInfo::kCachedPropertyNameOffset);
- Label* has_cached_property = mode == kCallJSGetterUseCachedName
- ? &use_cached_property
- : if_bailout;
- GotoIfNot(IsTheHole(cached_property_name), has_cached_property);
+ Label* has_cached_property = mode == kCallJSGetterUseCachedName
+ ? &use_cached_property
+ : if_bailout;
+ GotoIfNot(IsTheHole(cached_property_name), has_cached_property);
- TNode<JSReceiver> js_receiver;
- switch (expected_receiver_mode) {
- case kExpectingJSReceiver:
- js_receiver = CAST(receiver);
- break;
- case kExpectingAnyReceiver:
- // TODO(ishell): in case the function template info has a signature
- // and receiver is not a JSReceiver the signature check in
- // CallFunctionTemplate builtin will fail anyway, so we can short
- // cut it here and throw kIllegalInvocation immediately.
- js_receiver = ToObject_Inline(context, receiver);
- break;
- }
- TNode<JSReceiver> holder_receiver = CAST(holder);
- TNode<NativeContext> creation_context =
- GetCreationContext(holder_receiver, if_bailout);
- TNode<Context> caller_context = context;
- var_value = CallBuiltin(
- Builtin::kCallFunctionTemplate_Generic, creation_context, getter,
- Int32Constant(i::JSParameterCount(0)), caller_context, js_receiver);
- Goto(&done);
-
- if (mode == kCallJSGetterUseCachedName) {
- Bind(&use_cached_property);
-
- var_value =
- GetProperty(context, holder_receiver, cached_property_name);
-
+ TNode<JSReceiver> js_receiver;
+ switch (expected_receiver_mode) {
+ case kExpectingJSReceiver:
+ js_receiver = CAST(receiver);
+ break;
+ case kExpectingAnyReceiver:
+ // TODO(ishell): in case the function template info has a
+ // signature and receiver is not a JSReceiver the signature check
+ // in CallFunctionTemplate builtin will fail anyway, so we can
+ // short cut it here and throw kIllegalInvocation immediately.
+ js_receiver = ToObject_Inline(context, receiver);
+ break;
+ }
+ TNode<JSReceiver> holder_receiver = *holder;
+ TNode<NativeContext> creation_context =
+ GetCreationContext(holder_receiver, if_bailout);
+ TNode<Context> caller_context = context;
+ var_value = CallBuiltin(Builtin::kCallFunctionTemplate_Generic,
+ creation_context, getter,
+ Int32Constant(i::JSParameterCount(0)),
+ caller_context, js_receiver);
Goto(&done);
+
+ if (mode == kCallJSGetterUseCachedName) {
+ Bind(&use_cached_property);
+
+ var_value =
+ GetProperty(context, holder_receiver, cached_property_name);
+
+ Goto(&done);
+ }
+ } else {
+ // |holder| must be available in order to handle lazy AccessorPair
+ // case (we need it for computing the function's context).
+ Unreachable();
}
}
} else {
@@ -12256,56 +12260,61 @@
// AccessorInfo case.
BIND(&if_accessor_info);
{
- TNode<AccessorInfo> accessor_info = CAST(value);
- Label if_array(this), if_function(this), if_wrapper(this);
+ if (holder.has_value()) {
+ TNode<AccessorInfo> accessor_info = CAST(value);
+ Label if_array(this), if_function(this), if_wrapper(this);
+ // Dispatch based on {holder} instance type.
+ TNode<Map> holder_map = LoadMap(*holder);
+ TNode<Uint16T> holder_instance_type = LoadMapInstanceType(holder_map);
+ GotoIf(IsJSArrayInstanceType(holder_instance_type), &if_array);
+ GotoIf(IsJSFunctionInstanceType(holder_instance_type), &if_function);
+ Branch(IsJSPrimitiveWrapperInstanceType(holder_instance_type),
+ &if_wrapper, if_bailout);
- // Dispatch based on {holder} instance type.
- TNode<Map> holder_map = LoadMap(holder);
- TNode<Uint16T> holder_instance_type = LoadMapInstanceType(holder_map);
- GotoIf(IsJSArrayInstanceType(holder_instance_type), &if_array);
- GotoIf(IsJSFunctionInstanceType(holder_instance_type), &if_function);
- Branch(IsJSPrimitiveWrapperInstanceType(holder_instance_type), &if_wrapper,
- if_bailout);
+ // JSArray AccessorInfo case.
+ BIND(&if_array);
+ {
+ // We only deal with the "length" accessor on JSArray.
+ GotoIfNot(IsLengthString(LoadObjectField(accessor_info,
+ AccessorInfo::kNameOffset)),
+ if_bailout);
+ TNode<JSArray> array = CAST(*holder);
+ var_value = LoadJSArrayLength(array);
+ Goto(&done);
+ }
- // JSArray AccessorInfo case.
- BIND(&if_array);
- {
- // We only deal with the "length" accessor on JSArray.
- GotoIfNot(IsLengthString(
- LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
- if_bailout);
- TNode<JSArray> array = CAST(holder);
- var_value = LoadJSArrayLength(array);
- Goto(&done);
- }
+ // JSFunction AccessorInfo case.
+ BIND(&if_function);
+ {
+ // We only deal with the "prototype" accessor on JSFunction here.
+ GotoIfNot(IsPrototypeString(LoadObjectField(accessor_info,
+ AccessorInfo::kNameOffset)),
+ if_bailout);
- // JSFunction AccessorInfo case.
- BIND(&if_function);
- {
- // We only deal with the "prototype" accessor on JSFunction here.
- GotoIfNot(IsPrototypeString(
- LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
- if_bailout);
+ TNode<JSFunction> function = CAST(*holder);
+ GotoIfPrototypeRequiresRuntimeLookup(function, holder_map, if_bailout);
+ var_value = LoadJSFunctionPrototype(function, if_bailout);
+ Goto(&done);
+ }
- TNode<JSFunction> function = CAST(holder);
- GotoIfPrototypeRequiresRuntimeLookup(function, holder_map, if_bailout);
- var_value = LoadJSFunctionPrototype(function, if_bailout);
- Goto(&done);
- }
-
- // JSPrimitiveWrapper AccessorInfo case.
- BIND(&if_wrapper);
- {
- // We only deal with the "length" accessor on JSPrimitiveWrapper string
- // wrappers.
- GotoIfNot(IsLengthString(
- LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
- if_bailout);
- TNode<Object> holder_value = LoadJSPrimitiveWrapperValue(CAST(holder));
- GotoIfNot(TaggedIsNotSmi(holder_value), if_bailout);
- GotoIfNot(IsString(CAST(holder_value)), if_bailout);
- var_value = LoadStringLengthAsSmi(CAST(holder_value));
- Goto(&done);
+ // JSPrimitiveWrapper AccessorInfo case.
+ BIND(&if_wrapper);
+ {
+ // We only deal with the "length" accessor on JSPrimitiveWrapper string
+ // wrappers.
+ GotoIfNot(IsLengthString(LoadObjectField(accessor_info,
+ AccessorInfo::kNameOffset)),
+ if_bailout);
+ TNode<Object> holder_value = LoadJSPrimitiveWrapperValue(CAST(*holder));
+ GotoIfNot(TaggedIsNotSmi(holder_value), if_bailout);
+ GotoIfNot(IsString(CAST(holder_value)), if_bailout);
+ var_value = LoadStringLengthAsSmi(CAST(holder_value));
+ Goto(&done);
+ }
+ } else {
+ // |holder| must be available in order to handle AccessorInfo case (we
+ // need to pass it to the callback).
+ Unreachable();
}
}
@@ -12390,7 +12399,7 @@
}
TNode<Object> value = CallGetterIfAccessor(
var_value->value(), object, var_details->value(), context, receiver,
- unique_name, if_bailout, mode, expected_receiver_mode);
+ expected_receiver_mode, unique_name, if_bailout, mode);
*var_value = value;
Goto(if_found_value);
}
diff --git a/src/codegen/code-stub-assembler.h b/src/codegen/code-stub-assembler.h
index 090c349..00e7b9e 100644
--- a/src/codegen/code-stub-assembler.h
+++ b/src/codegen/code-stub-assembler.h
@@ -4646,12 +4646,16 @@
const ForEachKeyValueFunction& body,
Label* bailout);
+ // |value| is the property backing store's contents, which is either a value
+ // or an accessor pair, as specified by |details|. |holder| is a JSReceiver
+ // or empty std::nullopt if holder is not available.
+ // Returns either the original value, or the result of the getter call.
TNode<Object> CallGetterIfAccessor(
- TNode<Object> value, TNode<Union<JSReceiver, PropertyCell>> holder,
+ TNode<Object> value, std::optional<TNode<JSReceiver>> holder,
TNode<Uint32T> details, TNode<Context> context, TNode<JSAny> receiver,
- TNode<Object> name, Label* if_bailout,
- GetOwnPropertyMode mode = kCallJSGetterDontUseCachedName,
- ExpectedReceiverMode expected_receiver_mode = kExpectingJSReceiver);
+ ExpectedReceiverMode expected_receiver_mode, TNode<Object> name,
+ Label* if_bailout,
+ GetOwnPropertyMode mode = kCallJSGetterDontUseCachedName);
TNode<IntPtrT> TryToIntptr(TNode<Object> key, Label* if_not_intptr,
TVariable<Int32T>* var_instance_type = nullptr);
diff --git a/src/ic/accessor-assembler.cc b/src/ic/accessor-assembler.cc
index af8e6dd..6ed2691 100644
--- a/src/ic/accessor-assembler.cc
+++ b/src/ic/accessor-assembler.cc
@@ -845,9 +845,13 @@
TVARIABLE(Object, var_value);
LoadPropertyFromDictionary<PropertyDictionary>(
properties, var_name_index.value(), &var_details, &var_value);
+
+ ExpectedReceiverMode expected_receiver_mode =
+ p->IsLoadSuperIC() ? kExpectingAnyReceiver : kExpectingJSReceiver;
+
TNode<Object> value = CallGetterIfAccessor(
var_value.value(), CAST(holder), var_details.value(), p->context(),
- p->receiver(), p->name(), miss);
+ p->receiver(), expected_receiver_mode, p->name(), miss);
exit_point->Return(value);
}
}
@@ -925,17 +929,18 @@
BIND(&global);
{
- CSA_DCHECK(this, IsPropertyCell(CAST(holder)));
// Ensure the property cell doesn't contain the hole.
- TNode<Object> value =
- LoadObjectField(CAST(holder), PropertyCell::kValueOffset);
+ TNode<Object> value = LoadPropertyCellValue(CAST(holder));
+ GotoIf(IsPropertyCellHole(value), miss);
TNode<Uint32T> details = Unsigned(LoadAndUntagToWord32ObjectField(
CAST(holder), PropertyCell::kPropertyDetailsRawOffset));
- GotoIf(IsPropertyCellHole(value), miss);
- exit_point->Return(CallGetterIfAccessor(value, CAST(holder), details,
- p->context(), p->receiver(),
- p->name(), miss));
+ ExpectedReceiverMode expected_receiver_mode =
+ p->IsLoadSuperIC() ? kExpectingAnyReceiver : kExpectingJSReceiver;
+
+ exit_point->Return(CallGetterIfAccessor(
+ value, std::nullopt, details, p->context(), p->receiver(),
+ expected_receiver_mode, p->name(), miss));
}
BIND(&interceptor);
@@ -1221,9 +1226,14 @@
TVARIABLE(Object, var_value);
LoadPropertyFromDictionary<PropertyDictionary>(
properties, name_index, &var_details, &var_value);
+
+ ExpectedReceiverMode expected_receiver_mode =
+ p->IsLoadSuperIC() ? kExpectingAnyReceiver : kExpectingJSReceiver;
+
TNode<Object> value = CallGetterIfAccessor(
var_value.value(), CAST(var_holder->value()), var_details.value(),
- p->context(), p->receiver(), p->name(), miss);
+ p->context(), p->receiver(), expected_receiver_mode, p->name(),
+ miss);
exit_point->Return(value);
}
},
@@ -2960,9 +2970,12 @@
BIND(&if_found_on_lookup_start_object);
{
+ ExpectedReceiverMode expected_receiver_mode =
+ p->IsLoadSuperIC() ? kExpectingAnyReceiver : kExpectingJSReceiver;
+
TNode<Object> value = CallGetterIfAccessor(
var_value.value(), CAST(lookup_start_object), var_details.value(),
- p->context(), p->receiver(), p->name(), slow);
+ p->context(), p->receiver(), expected_receiver_mode, p->name(), slow);
Return(value);
}
diff --git a/src/ic/accessor-assembler.h b/src/ic/accessor-assembler.h
index 29cbf28..30bb186 100644
--- a/src/ic/accessor-assembler.h
+++ b/src/ic/accessor-assembler.h
@@ -138,9 +138,7 @@
TNode<Object> name() const { return name_; }
TNode<TaggedIndex> slot() const { return slot_; }
TNode<HeapObject> vector() const { return vector_; }
- TNode<JSAny> lookup_start_object() const {
- return lookup_start_object_.value();
- }
+ TNode<JSAny> lookup_start_object() const { return lookup_start_object_; }
TNode<Smi> enum_index() const { return *enum_index_; }
TNode<Object> cache_type() const { return *cache_type_; }
@@ -152,6 +150,11 @@
return receiver_;
}
+ // This is useful for figuring out whether we know anything about receiver
+ // type. If |receiver| and |lookup_start_object| are different TNodes
+ // then this ICParameters object belongs to LoadSuperIC.
+ bool IsLoadSuperIC() const { return lookup_start_object_ != receiver_; }
+
bool IsEnumeratedKeyedLoad() const { return enum_index_ != std::nullopt; }
private:
@@ -160,7 +163,7 @@
TNode<Object> name_;
TNode<TaggedIndex> slot_;
TNode<HeapObject> vector_;
- std::optional<TNode<JSAny>> lookup_start_object_;
+ TNode<JSAny> lookup_start_object_;
std::optional<TNode<Smi>> enum_index_;
std::optional<TNode<Object>> cache_type_;
};
@@ -202,6 +205,11 @@
return receiver_;
}
+ // This is useful for figuring out whether we know anything about receiver
+ // type. If |receiver| and |lookup_start_object| are different TNodes
+ // then this ICParameters object belongs to LoadSuperIC.
+ bool IsLoadSuperIC() const { return lookup_start_object_ != receiver_; }
+
private:
LazyNode<Context> context_;
TNode<JSAny> receiver_;