mirror of
https://github.com/electron/electron.git
synced 2026-01-07 22:54:25 -05:00
chore: cherry-pick 62af07e96173 from v8
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
chore_allow_customizing_microtask_policy_per_context.patch
|
||||
turboshaft_avoid_introducing_too_many_variables.patch
|
||||
preserve_field_repr_in_property_array_extension.patch
|
||||
cherry-pick-62af07e96173.patch
|
||||
|
||||
404
patches/v8/cherry-pick-62af07e96173.patch
Normal file
404
patches/v8/cherry-pick-62af07e96173.patch
Normal 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_;
|
||||
Reference in New Issue
Block a user