Commit 2689548e authored by bmeurer's avatar bmeurer Committed by Commit bot

[compiler] Introduce StringEqualStub and StringNotEqualStub.

These new stubs perform exactly the same job as the string equality case
for the CompareIC, but are platform independent and usable outside of
fullcodegen and Crankshaft. We use them in the StrictEqualStub and the
StrictNotEqualStub instead of falling back to the runtime immediately
for String comparisons, and we also use them in TurboFan to perform
String equality or inequality comparisons.

These stubs currently handle only internalized and one byte strings w/o
going to C++, but it should be easy to add support for more string cases
later, i.e. utilizing already flattened cons strings or comparing two
byte strings as well.

Review URL: https://codereview.chromium.org/1761823002

Cr-Commit-Position: refs/heads/master@{#34459}
parent 0b3e436a
......@@ -220,6 +220,17 @@ Callable CodeFactory::StringCompare(Isolate* isolate) {
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StringEqual(Isolate* isolate) {
StringEqualStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StringNotEqual(Isolate* isolate) {
StringNotEqualStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::SubString(Isolate* isolate) {
......
......@@ -81,6 +81,8 @@ class CodeFactory final {
static Callable StringAdd(Isolate* isolate, StringAddFlags flags,
PretenureFlag pretenure_flag);
static Callable StringCompare(Isolate* isolate);
static Callable StringEqual(Isolate* isolate);
static Callable StringNotEqual(Isolate* isolate);
static Callable SubString(Isolate* isolate);
static Callable Typeof(Isolate* isolate);
......
This diff is collapsed.
......@@ -103,6 +103,8 @@ namespace internal {
V(StringLength) \
V(StrictEqual) \
V(StrictNotEqual) \
V(StringEqual) \
V(StringNotEqual) \
V(ToBoolean) \
/* IC Handler stubs */ \
V(ArrayBufferViewLoadField) \
......@@ -653,6 +655,26 @@ class StrictNotEqualStub final : public TurboFanCodeStub {
DEFINE_CODE_STUB(StrictNotEqual, TurboFanCodeStub);
};
class StringEqualStub final : public TurboFanCodeStub {
public:
explicit StringEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final;
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_CODE_STUB(StringEqual, TurboFanCodeStub);
};
class StringNotEqualStub final : public TurboFanCodeStub {
public:
explicit StringNotEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final;
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_CODE_STUB(StringNotEqual, TurboFanCodeStub);
};
class ToBooleanStub final : public TurboFanCodeStub {
public:
explicit ToBooleanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
......
......@@ -602,6 +602,14 @@ Node* CodeStubAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
return CallN(call_descriptor, target, args);
}
Node* CodeStubAssembler::TailCallStub(Callable const& callable, Node* context,
Node* arg1, Node* arg2,
size_t result_size) {
Node* target = HeapConstant(callable.code());
return TailCallStub(callable.descriptor(), target, context, arg1, arg2,
result_size);
}
Node* CodeStubAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
Node* target, Node* context, Node* arg1,
Node* arg2, size_t result_size) {
......
......@@ -19,6 +19,7 @@
namespace v8 {
namespace internal {
class Callable;
class CallInterfaceDescriptor;
class Isolate;
class Factory;
......@@ -215,6 +216,9 @@ class CodeStubAssembler {
Node* context, Node* arg1, Node* arg2, Node* arg3, Node* arg4,
Node* arg5, size_t result_size = 1);
Node* TailCallStub(Callable const& callable, Node* context, Node* arg1,
Node* arg2, size_t result_size = 1);
Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, Node* arg1, Node* arg2,
size_t result_size = 1);
......
......@@ -294,6 +294,10 @@ class RepresentationSelector {
return NodeOutputInfo(MachineRepresentation::kTagged, Type::Any());
}
static NodeOutputInfo BoolTagged() {
return NodeOutputInfo(MachineRepresentation::kTagged, Type::Boolean());
}
static NodeOutputInfo NumberTagged() {
return NodeOutputInfo(MachineRepresentation::kTagged, Type::Number());
}
......@@ -1139,8 +1143,20 @@ class RepresentationSelector {
break;
}
case IrOpcode::kStringEqual: {
VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
if (lower()) lowering->DoStringEqual(node);
VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::BoolTagged());
if (lower()) {
// StringEqual(x, y) => Call(StringEqualStub, x, y, no-context)
Operator::Properties properties = node->op()->properties();
Callable callable = CodeFactory::StringEqual(jsgraph_->isolate());
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0,
flags, properties);
node->InsertInput(jsgraph_->zone(), 0,
jsgraph_->HeapConstant(callable.code()));
node->InsertInput(jsgraph_->zone(), 3, jsgraph_->NoContextConstant());
NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
}
break;
}
case IrOpcode::kStringLessThan: {
......@@ -1890,16 +1906,6 @@ void ReplaceEffectUses(Node* node, Node* replacement) {
} // namespace
void SimplifiedLowering::DoStringEqual(Node* node) {
Node* comparison = StringComparison(node);
ReplaceEffectUses(node, comparison);
node->ReplaceInput(0, comparison);
node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
node->TrimInputCount(2);
NodeProperties::ChangeOp(node, machine()->WordEqual());
}
void SimplifiedLowering::DoStringLessThan(Node* node) {
Node* comparison = StringComparison(node);
ReplaceEffectUses(node, comparison);
......
......@@ -37,7 +37,6 @@ class SimplifiedLowering final {
RepresentationChanger* changer);
void DoStoreBuffer(Node* node);
void DoShift(Node* node, Operator const* op, Type* rhs_type);
void DoStringEqual(Node* node);
void DoStringLessThan(Node* node);
void DoStringLessThanOrEqual(Node* node);
......
......@@ -2366,9 +2366,15 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
DCHECK(ToRegister(instr->left()).is(r1));
DCHECK(ToRegister(instr->right()).is(r0));
if (Token::IsOrderedRelationalCompareOp(instr->op())) {
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ cmp(r0, Operand::Zero());
} else {
Handle<Code> code = CodeFactory::StringEqual(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ CompareRoot(r0, Heap::kTrueValueRootIndex);
}
EmitBranch(instr, ComputeCompareCondition(instr->op()));
}
......
......@@ -5193,10 +5193,18 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
DCHECK(ToRegister(instr->left()).is(x1));
DCHECK(ToRegister(instr->right()).is(x0));
if (Token::IsOrderedRelationalCompareOp(instr->op())) {
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
EmitCompareAndBranch(instr, TokenToCondition(instr->op(), false), x0, 0);
} else {
Handle<Code> code = CodeFactory::StringEqual(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ CompareRoot(x0, Heap::kTrueValueRootIndex);
EmitBranch(instr, TokenToCondition(instr->op(), false));
}
}
......
......@@ -2168,9 +2168,15 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
DCHECK(ToRegister(instr->left()).is(edx));
DCHECK(ToRegister(instr->right()).is(eax));
if (Token::IsOrderedRelationalCompareOp(instr->op())) {
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ test(eax, eax);
} else {
Handle<Code> code = CodeFactory::StringEqual(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ CompareRoot(eax, Heap::kTrueValueRootIndex);
}
EmitBranch(instr, ComputeCompareCondition(instr->op()));
}
......
......@@ -2275,11 +2275,19 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
DCHECK(ToRegister(instr->left()).is(a1));
DCHECK(ToRegister(instr->right()).is(a0));
if (Token::IsOrderedRelationalCompareOp(instr->op())) {
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
EmitBranch(instr, ComputeCompareCondition(instr->op()), v0,
Operand(zero_reg));
} else {
Handle<Code> code = CodeFactory::StringEqual(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ LoadRoot(at, Heap::kTrueValueRootIndex);
EmitBranch(instr, ComputeCompareCondition(instr->op()), v0, Operand(at));
}
}
......
......@@ -2392,11 +2392,19 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
DCHECK(ToRegister(instr->left()).is(a1));
DCHECK(ToRegister(instr->right()).is(a0));
if (Token::IsOrderedRelationalCompareOp(instr->op())) {
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
EmitBranch(instr, ComputeCompareCondition(instr->op()), v0,
Operand(zero_reg));
} else {
Handle<Code> code = CodeFactory::StringEqual(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ LoadRoot(at, Heap::kTrueValueRootIndex);
EmitBranch(instr, ComputeCompareCondition(instr->op()), v0, Operand(at));
}
}
......
......@@ -2318,9 +2318,15 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
DCHECK(ToRegister(instr->left()).is(rdx));
DCHECK(ToRegister(instr->right()).is(rax));
if (Token::IsOrderedRelationalCompareOp(instr->op())) {
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ testp(rax, rax);
} else {
Handle<Code> code = CodeFactory::StringEqual(isolate()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
}
EmitBranch(instr, TokenToCondition(instr->op(), false));
}
......
......@@ -1144,13 +1144,10 @@ TEST(LowerReferenceEqual_to_wordeq) {
TEST(LowerStringOps_to_call_and_compare) {
// These tests need linkage for the calls.
TestingGraph t(Type::String(), Type::String());
IrOpcode::Value compare_eq =
static_cast<IrOpcode::Value>(t.machine()->WordEqual()->opcode());
IrOpcode::Value compare_lt =
static_cast<IrOpcode::Value>(t.machine()->IntLessThan()->opcode());
IrOpcode::Value compare_le = static_cast<IrOpcode::Value>(
t.machine()->IntLessThanOrEqual()->opcode());
t.CheckLoweringStringBinop(compare_eq, t.simplified()->StringEqual());
t.CheckLoweringStringBinop(compare_lt, t.simplified()->StringLessThan());
t.CheckLoweringStringBinop(compare_le,
t.simplified()->StringLessThanOrEqual());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment