[csa] Avoid calling to Builtin::StringEqual if possible
Check strings length before calling to Builtin::StringEqual. If length is not equal, the strings must also be not equal. Change-Id: I4f8c2e72720d0919b3fd57013d06dcc8d83f2ab4 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4090410 Commit-Queue: Hao A Xu <hao.a.xu@intel.com> Reviewed-by: Igor Sheludko <ishell@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/main@{#85005}
This commit is contained in:
parent
3175117293
commit
8a795a593e
@ -1293,10 +1293,7 @@ void CollectionsBuiltinsAssembler::SameValueZeroString(
|
||||
GotoIf(TaggedIsSmi(candidate_key), if_not_same);
|
||||
GotoIfNot(IsString(CAST(candidate_key)), if_not_same);
|
||||
|
||||
Branch(TaggedEqual(CallBuiltin(Builtin::kStringEqual, NoContextConstant(),
|
||||
key_string, candidate_key),
|
||||
TrueConstant()),
|
||||
if_same, if_not_same);
|
||||
BranchIfStringEqual(key_string, CAST(candidate_key), if_same, if_not_same);
|
||||
}
|
||||
|
||||
void CollectionsBuiltinsAssembler::SameValueZeroBigInt(
|
||||
|
@ -207,18 +207,11 @@ TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
|
||||
// Slow-case with actual string comparisons.
|
||||
GotoIf(TaggedIsSmi(hint), &hint_is_invalid);
|
||||
GotoIfNot(IsString(CAST(hint)), &hint_is_invalid);
|
||||
GotoIf(TaggedEqual(
|
||||
CallBuiltin(Builtin::kStringEqual, context, hint, number_string),
|
||||
TrueConstant()),
|
||||
&hint_is_number);
|
||||
GotoIf(TaggedEqual(
|
||||
CallBuiltin(Builtin::kStringEqual, context, hint, default_string),
|
||||
TrueConstant()),
|
||||
&hint_is_string);
|
||||
GotoIf(TaggedEqual(
|
||||
CallBuiltin(Builtin::kStringEqual, context, hint, string_string),
|
||||
TrueConstant()),
|
||||
&hint_is_string);
|
||||
|
||||
TNode<IntPtrT> hint_length = LoadStringLengthAsWord(CAST(hint));
|
||||
GotoIfStringEqual(CAST(hint), hint_length, number_string, &hint_is_number);
|
||||
GotoIfStringEqual(CAST(hint), hint_length, default_string, &hint_is_string);
|
||||
GotoIfStringEqual(CAST(hint), hint_length, string_string, &hint_is_string);
|
||||
Goto(&hint_is_invalid);
|
||||
|
||||
// Use the OrdinaryToPrimitive builtin to convert to a Number.
|
||||
|
@ -160,7 +160,7 @@ namespace internal {
|
||||
\
|
||||
/* String helpers */ \
|
||||
TFC(StringFromCodePointAt, StringAtAsString) \
|
||||
TFC(StringEqual, Compare) \
|
||||
TFC(StringEqual, StringEqual) \
|
||||
TFC(StringGreaterThan, Compare) \
|
||||
TFC(StringGreaterThanOrEqual, Compare) \
|
||||
TFC(StringLessThan, Compare) \
|
||||
|
@ -124,17 +124,15 @@ TNode<IntPtrT> StringBuiltinsAssembler::SearchOneByteInOneByteString(
|
||||
}
|
||||
|
||||
void StringBuiltinsAssembler::GenerateStringEqual(TNode<String> left,
|
||||
TNode<String> right) {
|
||||
TNode<String> right,
|
||||
TNode<IntPtrT> length) {
|
||||
TVARIABLE(String, var_left, left);
|
||||
TVARIABLE(String, var_right, right);
|
||||
Label if_equal(this), if_notequal(this), if_indirect(this, Label::kDeferred),
|
||||
restart(this, {&var_left, &var_right});
|
||||
|
||||
TNode<IntPtrT> lhs_length = LoadStringLengthAsWord(left);
|
||||
TNode<IntPtrT> rhs_length = LoadStringLengthAsWord(right);
|
||||
|
||||
// Strings with different lengths cannot be equal.
|
||||
GotoIf(WordNotEqual(lhs_length, rhs_length), &if_notequal);
|
||||
CSA_DCHECK(this, IntPtrEqual(LoadStringLengthAsWord(left), length));
|
||||
CSA_DCHECK(this, IntPtrEqual(LoadStringLengthAsWord(right), length));
|
||||
|
||||
Goto(&restart);
|
||||
BIND(&restart);
|
||||
@ -144,7 +142,7 @@ void StringBuiltinsAssembler::GenerateStringEqual(TNode<String> left,
|
||||
TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs);
|
||||
TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
|
||||
|
||||
StringEqual_Core(lhs, lhs_instance_type, rhs, rhs_instance_type, lhs_length,
|
||||
StringEqual_Core(lhs, lhs_instance_type, rhs, rhs_instance_type, length,
|
||||
&if_equal, &if_notequal, &if_indirect);
|
||||
|
||||
BIND(&if_indirect);
|
||||
@ -716,7 +714,8 @@ void StringBuiltinsAssembler::GenerateStringRelationalComparison(
|
||||
TF_BUILTIN(StringEqual, StringBuiltinsAssembler) {
|
||||
auto left = Parameter<String>(Descriptor::kLeft);
|
||||
auto right = Parameter<String>(Descriptor::kRight);
|
||||
GenerateStringEqual(left, right);
|
||||
auto length = UncheckedParameter<IntPtrT>(Descriptor::kLength);
|
||||
GenerateStringEqual(left, right, length);
|
||||
}
|
||||
|
||||
TF_BUILTIN(StringLessThan, StringBuiltinsAssembler) {
|
||||
|
@ -104,7 +104,8 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
||||
const TNode<IntPtrT> search_length,
|
||||
const TNode<IntPtrT> start_position);
|
||||
|
||||
void GenerateStringEqual(TNode<String> left, TNode<String> right);
|
||||
void GenerateStringEqual(TNode<String> left, TNode<String> right,
|
||||
TNode<IntPtrT> length);
|
||||
void GenerateStringRelationalComparison(TNode<String> left,
|
||||
TNode<String> right, Operation op);
|
||||
|
||||
|
@ -13277,12 +13277,16 @@ TNode<Oddball> CodeStubAssembler::Equal(TNode<Object> left, TNode<Object> right,
|
||||
BIND(&if_left_string);
|
||||
{
|
||||
GotoIfNot(IsStringInstanceType(right_type), &use_symmetry);
|
||||
result =
|
||||
CAST(CallBuiltin(Builtin::kStringEqual, context(), left, right));
|
||||
CombineFeedback(var_type_feedback,
|
||||
SmiOr(CollectFeedbackForString(left_type),
|
||||
CollectFeedbackForString(right_type)));
|
||||
Goto(&end);
|
||||
Label combine_feedback(this);
|
||||
BranchIfStringEqual(CAST(left), CAST(right), &combine_feedback,
|
||||
&combine_feedback, &result);
|
||||
BIND(&combine_feedback);
|
||||
{
|
||||
CombineFeedback(var_type_feedback,
|
||||
SmiOr(CollectFeedbackForString(left_type),
|
||||
CollectFeedbackForString(right_type)));
|
||||
Goto(&end);
|
||||
}
|
||||
}
|
||||
|
||||
BIND(&if_left_number);
|
||||
@ -13755,9 +13759,7 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(
|
||||
CollectFeedbackForString(rhs_instance_type);
|
||||
*var_type_feedback = SmiOr(lhs_feedback, rhs_feedback);
|
||||
}
|
||||
result = CAST(CallBuiltin(Builtin::kStringEqual,
|
||||
NoContextConstant(), lhs, rhs));
|
||||
Goto(&end);
|
||||
BranchIfStringEqual(CAST(lhs), CAST(rhs), &end, &end, &result);
|
||||
}
|
||||
|
||||
BIND(&if_rhsisnotstring);
|
||||
@ -13969,6 +13971,36 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(
|
||||
return result.value();
|
||||
}
|
||||
|
||||
void CodeStubAssembler::BranchIfStringEqual(TNode<String> lhs,
|
||||
TNode<IntPtrT> lhs_length,
|
||||
TNode<String> rhs,
|
||||
TNode<IntPtrT> rhs_length,
|
||||
Label* if_true, Label* if_false,
|
||||
TVariable<Oddball>* result) {
|
||||
Label length_equal(this), length_not_equal(this);
|
||||
Branch(IntPtrEqual(lhs_length, rhs_length), &length_equal, &length_not_equal);
|
||||
|
||||
BIND(&length_not_equal);
|
||||
{
|
||||
if (result != nullptr) *result = FalseConstant();
|
||||
Goto(if_false);
|
||||
}
|
||||
|
||||
BIND(&length_equal);
|
||||
{
|
||||
TNode<Oddball> value = CAST(CallBuiltin(
|
||||
Builtin::kStringEqual, NoContextConstant(), lhs, rhs, lhs_length));
|
||||
if (result != nullptr) {
|
||||
*result = value;
|
||||
}
|
||||
if (if_true == if_false) {
|
||||
Goto(if_true);
|
||||
} else {
|
||||
Branch(TaggedEqual(value, TrueConstant()), if_true, if_false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ECMA#sec-samevalue
|
||||
// This algorithm differs from the Strict Equality Comparison Algorithm in its
|
||||
// treatment of signed zeroes and NaNs.
|
||||
@ -14043,9 +14075,7 @@ void CodeStubAssembler::BranchIfSameValue(TNode<Object> lhs, TNode<Object> rhs,
|
||||
// Now we can only yield true if {rhs} is also a String
|
||||
// with the same sequence of characters.
|
||||
GotoIfNot(IsString(CAST(rhs)), if_false);
|
||||
const TNode<Object> result = CallBuiltin(
|
||||
Builtin::kStringEqual, NoContextConstant(), lhs, rhs);
|
||||
Branch(IsTrue(result), if_true, if_false);
|
||||
BranchIfStringEqual(CAST(lhs), CAST(rhs), if_true, if_false);
|
||||
}
|
||||
|
||||
BIND(&if_lhsisbigint);
|
||||
|
@ -3739,6 +3739,29 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TNode<Oddball> StrictEqual(TNode<Object> lhs, TNode<Object> rhs,
|
||||
TVariable<Smi>* var_type_feedback = nullptr);
|
||||
|
||||
void GotoIfStringEqual(TNode<String> lhs, TNode<IntPtrT> lhs_length,
|
||||
TNode<String> rhs, Label* if_true) {
|
||||
Label if_false(this);
|
||||
TNode<IntPtrT> rhs_length = LoadStringLengthAsWord(rhs);
|
||||
BranchIfStringEqual(lhs, lhs_length, rhs, rhs_length, if_true, &if_false,
|
||||
nullptr);
|
||||
|
||||
BIND(&if_false);
|
||||
}
|
||||
|
||||
void BranchIfStringEqual(TNode<String> lhs, TNode<String> rhs, Label* if_true,
|
||||
Label* if_false,
|
||||
TVariable<Oddball>* result = nullptr) {
|
||||
return BranchIfStringEqual(lhs, LoadStringLengthAsWord(lhs), rhs,
|
||||
LoadStringLengthAsWord(rhs), if_true, if_false,
|
||||
result);
|
||||
}
|
||||
|
||||
void BranchIfStringEqual(TNode<String> lhs, TNode<IntPtrT> lhs_length,
|
||||
TNode<String> rhs, TNode<IntPtrT> rhs_length,
|
||||
Label* if_true, Label* if_false,
|
||||
TVariable<Oddball>* result = nullptr);
|
||||
|
||||
// ECMA#sec-samevalue
|
||||
// Similar to StrictEqual except that NaNs are treated as equal and minus zero
|
||||
// differs from positive zero.
|
||||
|
@ -55,6 +55,7 @@ namespace internal {
|
||||
V(CloneObjectBaseline) \
|
||||
V(CloneObjectWithVector) \
|
||||
V(Compare) \
|
||||
V(StringEqual) \
|
||||
V(Compare_Baseline) \
|
||||
V(Compare_WithFeedback) \
|
||||
V(Construct_Baseline) \
|
||||
@ -1563,6 +1564,16 @@ class CompareDescriptor
|
||||
static constexpr inline auto registers();
|
||||
};
|
||||
|
||||
class StringEqualDescriptor
|
||||
: public StaticCallInterfaceDescriptor<StringEqualDescriptor> {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kLeft, kRight, kLength)
|
||||
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kLeft
|
||||
MachineType::AnyTagged(), // kRight
|
||||
MachineType::IntPtr()) // kLength
|
||||
DECLARE_DEFAULT_DESCRIPTOR(StringEqualDescriptor)
|
||||
};
|
||||
|
||||
class BinaryOpDescriptor
|
||||
: public StaticCallInterfaceDescriptor<BinaryOpDescriptor> {
|
||||
public:
|
||||
|
@ -4495,6 +4495,33 @@ Node* EffectControlLinearizer::LowerStringLength(Node* node) {
|
||||
return __ LoadField(AccessBuilder::ForStringLength(), subject);
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerStringEqual(Node* node) {
|
||||
Callable callable = Builtins::CallableFor(isolate(), Builtin::kStringEqual);
|
||||
Node* lhs = node->InputAt(0);
|
||||
Node* rhs = node->InputAt(1);
|
||||
Node* lhs_length = __ LoadField(AccessBuilder::ForStringLength(), lhs);
|
||||
Node* rhs_length = __ LoadField(AccessBuilder::ForStringLength(), rhs);
|
||||
|
||||
auto if_length_equal = __ MakeLabel();
|
||||
auto done = __ MakeLabel(MachineRepresentation::kTagged);
|
||||
|
||||
__ GotoIf(__ Word32Equal(lhs_length, rhs_length), &if_length_equal);
|
||||
__ Goto(&done, __ FalseConstant());
|
||||
|
||||
__ Bind(&if_length_equal);
|
||||
Operator::Properties properties = Operator::kEliminatable;
|
||||
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
|
||||
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
||||
graph()->zone(), callable.descriptor(),
|
||||
callable.descriptor().GetStackParameterCount(), flags, properties);
|
||||
Node* result = __ Call(call_descriptor, __ HeapConstant(callable.code()), lhs,
|
||||
rhs, lhs_length, __ NoContextConstant());
|
||||
__ Goto(&done, result);
|
||||
|
||||
__ Bind(&done);
|
||||
return done.PhiAt(0);
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerStringComparison(Callable const& callable,
|
||||
Node* node) {
|
||||
Node* lhs = node->InputAt(0);
|
||||
@ -4525,11 +4552,6 @@ Node* EffectControlLinearizer::LowerStringSubstring(Node* node) {
|
||||
start, end, __ NoContextConstant());
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerStringEqual(Node* node) {
|
||||
return LowerStringComparison(
|
||||
Builtins::CallableFor(isolate(), Builtin::kStringEqual), node);
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerStringLessThan(Node* node) {
|
||||
return LowerStringComparison(
|
||||
Builtins::CallableFor(isolate(), Builtin::kStringLessThan), node);
|
||||
|
Loading…
Reference in New Issue
Block a user