[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:
Hao Xu 2022-12-13 18:28:13 +08:00 committed by V8 LUCI CQ
parent 3175117293
commit 8a795a593e
9 changed files with 119 additions and 43 deletions

View File

@ -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(

View File

@ -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.

View File

@ -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) \

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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:

View File

@ -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);