[compiler] Introduce code stubs for string relational comparisons.

Add StringLessThanStub, StringLessThanOrEqualStub, StringGreaterThanStub
and StringGreaterThanOrEqualStub, based on the CodeStubAssembler, and
hook them up with TurboFan (and Ignition). The stubs are currently
essentially comparable with the StringCompareStub, which is now
obsolete. We can later extend these stubs to cover more interesting
cases (i.e. two byte sequential string comparisons, etc.).

R=epertoso@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#34485}
This commit is contained in:
bmeurer 2016-03-04 01:38:31 -08:00 committed by Commit bot
parent 98c34e600d
commit 5912e0f014
22 changed files with 394 additions and 392 deletions

View File

@ -2850,42 +2850,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void StringCompareStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r1 : left
// -- r0 : right
// -- lr : return address
// -----------------------------------
__ AssertString(r1);
__ AssertString(r0);
Label not_same;
__ cmp(r0, r1);
__ b(ne, &not_same);
__ mov(r0, Operand(Smi::FromInt(EQUAL)));
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r1,
r2);
__ Ret();
__ bind(&not_same);
// Check that both objects are sequential one-byte strings.
Label runtime;
__ JumpIfNotBothSequentialOneByteStrings(r1, r0, r2, r3, &runtime);
// Compare flat one-byte strings natively.
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r2,
r3);
StringHelper::GenerateCompareFlatOneByteStrings(masm, r1, r0, r2, r3, r4, r5);
// Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
// tagged as a small integer.
__ bind(&runtime);
__ Push(r1, r0);
__ TailCallRuntime(Runtime::kStringCompare);
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r1 : left

View File

@ -3468,43 +3468,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void StringCompareStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x1 : left
// -- x0 : right
// -- lr : return address
// -----------------------------------
__ AssertString(x1);
__ AssertString(x0);
Label not_same;
__ Cmp(x0, x1);
__ B(ne, &not_same);
__ Mov(x0, Smi::FromInt(EQUAL));
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1, x3,
x4);
__ Ret();
__ Bind(&not_same);
// Check that both objects are sequential one-byte strings.
Label runtime;
__ JumpIfEitherIsNotSequentialOneByteStrings(x1, x0, x12, x13, &runtime);
// Compare flat one-byte strings natively.
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1, x3,
x4);
StringHelper::GenerateCompareFlatOneByteStrings(masm, x1, x0, x12, x13, x14,
x15);
// Call the runtime.
// Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer.
__ Bind(&runtime);
__ Push(x1, x0);
__ TailCallRuntime(Runtime::kStringCompare);
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x1 : left

View File

@ -237,11 +237,28 @@ Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags,
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StringCompare(Isolate* isolate) {
StringCompareStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
Callable CodeFactory::StringCompare(Isolate* isolate, Token::Value token) {
switch (token) {
case Token::EQ:
case Token::EQ_STRICT:
return StringEqual(isolate);
case Token::NE:
case Token::NE_STRICT:
return StringNotEqual(isolate);
case Token::LT:
return StringLessThan(isolate);
case Token::GT:
return StringGreaterThan(isolate);
case Token::LTE:
return StringLessThanOrEqual(isolate);
case Token::GTE:
return StringGreaterThanOrEqual(isolate);
default:
break;
}
UNREACHABLE();
return StringEqual(isolate);
}
// static
@ -256,6 +273,30 @@ Callable CodeFactory::StringNotEqual(Isolate* isolate) {
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StringLessThan(Isolate* isolate) {
StringLessThanStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StringLessThanOrEqual(Isolate* isolate) {
StringLessThanOrEqualStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StringGreaterThan(Isolate* isolate) {
StringGreaterThanStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StringGreaterThanOrEqual(Isolate* isolate) {
StringGreaterThanOrEqualStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::SubString(Isolate* isolate) {
SubStringStub stub(isolate);

View File

@ -84,9 +84,13 @@ class CodeFactory final {
static Callable StringAdd(Isolate* isolate, StringAddFlags flags,
PretenureFlag pretenure_flag);
static Callable StringCompare(Isolate* isolate);
static Callable StringCompare(Isolate* isolate, Token::Value token);
static Callable StringEqual(Isolate* isolate);
static Callable StringNotEqual(Isolate* isolate);
static Callable StringLessThan(Isolate* isolate);
static Callable StringLessThanOrEqual(Isolate* isolate);
static Callable StringGreaterThan(Isolate* isolate);
static Callable StringGreaterThanOrEqual(Isolate* isolate);
static Callable SubString(Isolate* isolate);
static Callable Typeof(Isolate* isolate);

View File

@ -501,7 +501,7 @@ void StringLengthStub::GenerateAssembly(
namespace {
enum AbstractRelationalComparisonMode {
enum RelationalComparisonMode {
kLessThan,
kLessThanOrEqual,
kGreaterThan,
@ -509,8 +509,7 @@ enum AbstractRelationalComparisonMode {
};
void GenerateAbstractRelationalComparison(
compiler::CodeStubAssembler* assembler,
AbstractRelationalComparisonMode mode) {
compiler::CodeStubAssembler* assembler, RelationalComparisonMode mode) {
typedef compiler::CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef compiler::CodeStubAssembler::Variable Variable;
@ -717,23 +716,26 @@ void GenerateAbstractRelationalComparison(
assembler->Bind(&if_rhsisstring);
{
// Both {lhs} and {rhs} are strings.
// TODO(bmeurer): Hook up String<Compare>Stub once we have it.
switch (mode) {
case kLessThan:
assembler->TailCallRuntime(Runtime::kStringLessThan, context,
lhs, rhs);
assembler->TailCallStub(
CodeFactory::StringLessThan(assembler->isolate()),
context, lhs, rhs);
break;
case kLessThanOrEqual:
assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual,
context, lhs, rhs);
assembler->TailCallStub(
CodeFactory::StringLessThanOrEqual(assembler->isolate()),
context, lhs, rhs);
break;
case kGreaterThan:
assembler->TailCallRuntime(Runtime::kStringGreaterThan,
context, lhs, rhs);
assembler->TailCallStub(
CodeFactory::StringGreaterThan(assembler->isolate()),
context, lhs, rhs);
break;
case kGreaterThanOrEqual:
assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
context, lhs, rhs);
assembler->TailCallStub(CodeFactory::StringGreaterThanOrEqual(
assembler->isolate()),
context, lhs, rhs);
break;
}
}
@ -1134,6 +1136,189 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
}
void GenerateStringRelationalComparison(compiler::CodeStubAssembler* assembler,
RelationalComparisonMode mode) {
typedef compiler::CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef compiler::CodeStubAssembler::Variable Variable;
Node* lhs = assembler->Parameter(0);
Node* rhs = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Label if_less(assembler), if_equal(assembler), if_greater(assembler);
// Fast check to see if {lhs} and {rhs} refer to the same String object.
Label if_same(assembler), if_notsame(assembler);
assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
assembler->Bind(&if_same);
assembler->Goto(&if_equal);
assembler->Bind(&if_notsame);
{
// Load instance types of {lhs} and {rhs}.
Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
// Combine the instance types into a single 16-bit value, so we can check
// both of them at once.
Node* both_instance_types = assembler->Word32Or(
lhs_instance_type,
assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
// Check that both {lhs} and {rhs} are flat one-byte strings.
int const kBothSeqOneByteStringMask =
kStringEncodingMask | kStringRepresentationMask |
((kStringEncodingMask | kStringRepresentationMask) << 8);
int const kBothSeqOneByteStringTag =
kOneByteStringTag | kSeqStringTag |
((kOneByteStringTag | kSeqStringTag) << 8);
Label if_bothonebyteseqstrings(assembler),
if_notbothonebyteseqstrings(assembler);
assembler->Branch(assembler->Word32Equal(
assembler->Word32And(both_instance_types,
assembler->Int32Constant(
kBothSeqOneByteStringMask)),
assembler->Int32Constant(kBothSeqOneByteStringTag)),
&if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
assembler->Bind(&if_bothonebyteseqstrings);
{
// Load the length of {lhs} and {rhs}.
Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
// Determine the minimum length.
Node* length = assembler->SmiMin(lhs_length, rhs_length);
// Compute the effective offset of the first character.
Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
kHeapObjectTag);
// Compute the first offset after the string from the length.
Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
// Loop over the {lhs} and {rhs} strings to see if they are equal.
Variable var_offset(assembler, MachineType::PointerRepresentation());
Label loop(assembler, &var_offset);
var_offset.Bind(begin);
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Check if {offset} equals {end}.
Node* offset = var_offset.value();
Label if_done(assembler), if_notdone(assembler);
assembler->Branch(assembler->WordEqual(offset, end), &if_done,
&if_notdone);
assembler->Bind(&if_notdone);
{
// Load the next characters from {lhs} and {rhs}.
Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
// Check if the characters match.
Label if_valueissame(assembler), if_valueisnotsame(assembler);
assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
&if_valueissame, &if_valueisnotsame);
assembler->Bind(&if_valueissame);
{
// Advance to next character.
var_offset.Bind(
assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
}
assembler->Goto(&loop);
assembler->Bind(&if_valueisnotsame);
assembler->BranchIfInt32LessThan(lhs_value, rhs_value, &if_less,
&if_greater);
}
assembler->Bind(&if_done);
{
// All characters up to the min length are equal, decide based on
// string length.
Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
&if_lengthisequal, &if_lengthisnotequal);
assembler->Bind(&if_lengthisequal);
assembler->Goto(&if_equal);
assembler->Bind(&if_lengthisnotequal);
assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
&if_greater);
}
}
}
assembler->Bind(&if_notbothonebyteseqstrings);
{
// TODO(bmeurer): Add fast case support for flattened cons strings;
// also add support for two byte string relational comparisons.
switch (mode) {
case kLessThan:
assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs,
rhs);
break;
case kLessThanOrEqual:
assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context,
lhs, rhs);
break;
case kGreaterThan:
assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs,
rhs);
break;
case kGreaterThanOrEqual:
assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
context, lhs, rhs);
break;
}
}
}
assembler->Bind(&if_less);
switch (mode) {
case kLessThan:
case kLessThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
case kGreaterThan:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(false));
break;
}
assembler->Bind(&if_equal);
switch (mode) {
case kLessThan:
case kGreaterThan:
assembler->Return(assembler->BooleanConstant(false));
break;
case kLessThanOrEqual:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
}
assembler->Bind(&if_greater);
switch (mode) {
case kLessThan:
case kLessThanOrEqual:
assembler->Return(assembler->BooleanConstant(false));
break;
case kGreaterThan:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
}
}
void GenerateStringEqual(compiler::CodeStubAssembler* assembler,
ResultMode mode) {
// Here's pseudo-code for the algorithm below in case of kDontNegateResult
@ -1353,6 +1538,26 @@ void StringNotEqualStub::GenerateAssembly(
GenerateStringEqual(assembler, kNegateResult);
}
void StringLessThanStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
GenerateStringRelationalComparison(assembler, kLessThan);
}
void StringLessThanOrEqualStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
}
void StringGreaterThanStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
GenerateStringRelationalComparison(assembler, kGreaterThan);
}
void StringGreaterThanOrEqualStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
}
void ToBooleanStub::GenerateAssembly(
compiler::CodeStubAssembler* assembler) const {
typedef compiler::Node Node;

View File

@ -46,7 +46,6 @@ namespace internal {
V(RegExpExec) \
V(StoreBufferOverflow) \
V(StoreElement) \
V(StringCompare) \
V(StubFailureTrampoline) \
V(SubString) \
V(ToNumber) \
@ -109,6 +108,10 @@ namespace internal {
V(StrictNotEqual) \
V(StringEqual) \
V(StringNotEqual) \
V(StringLessThan) \
V(StringLessThanOrEqual) \
V(StringGreaterThan) \
V(StringGreaterThanOrEqual) \
V(ToBoolean) \
/* IC Handler stubs */ \
V(ArrayBufferViewLoadField) \
@ -701,6 +704,41 @@ class StringNotEqualStub final : public TurboFanCodeStub {
DEFINE_TURBOFAN_CODE_STUB(StringNotEqual, TurboFanCodeStub);
};
class StringLessThanStub final : public TurboFanCodeStub {
public:
explicit StringLessThanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringLessThan, TurboFanCodeStub);
};
class StringLessThanOrEqualStub final : public TurboFanCodeStub {
public:
explicit StringLessThanOrEqualStub(Isolate* isolate)
: TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringLessThanOrEqual, TurboFanCodeStub);
};
class StringGreaterThanStub final : public TurboFanCodeStub {
public:
explicit StringGreaterThanStub(Isolate* isolate)
: TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringGreaterThan, TurboFanCodeStub);
};
class StringGreaterThanOrEqualStub final : public TurboFanCodeStub {
public:
explicit StringGreaterThanOrEqualStub(Isolate* isolate)
: TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringGreaterThanOrEqual, TurboFanCodeStub);
};
class ToBooleanStub final : public TurboFanCodeStub {
public:
explicit ToBooleanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
@ -2935,16 +2973,6 @@ class ToObjectStub final : public HydrogenCodeStub {
DEFINE_HYDROGEN_CODE_STUB(ToObject, HydrogenCodeStub);
};
class StringCompareStub : public PlatformCodeStub {
public:
explicit StringCompareStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(StringCompare);
DEFINE_PLATFORM_CODE_STUB(StringCompare, PlatformCodeStub);
};
#undef DEFINE_CALL_INTERFACE_DESCRIPTOR
#undef DEFINE_PLATFORM_CODE_STUB
#undef DEFINE_HANDLER_CODE_STUB

View File

@ -171,6 +171,21 @@ Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) {
return IntPtrLessThanOrEqual(a, b);
}
Node* CodeStubAssembler::SmiMin(Node* a, Node* b) {
// TODO(bmeurer): Consider using Select once available.
Variable min(this, MachineRepresentation::kTagged);
Label if_a(this), if_b(this), join(this);
BranchIfSmiLessThan(a, b, &if_a, &if_b);
Bind(&if_a);
min.Bind(a);
Goto(&join);
Bind(&if_b);
min.Bind(b);
Goto(&join);
Bind(&join);
return min.value();
}
#define DEFINE_CODE_STUB_ASSEMBER_BINARY_OP(name) \
Node* CodeStubAssembler::name(Node* a, Node* b) { \
return raw_assembler_->name(a, b); \
@ -424,6 +439,16 @@ Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift,
raw_assembler_->Int32Constant(shift));
}
void CodeStubAssembler::BranchIfInt32LessThan(Node* a, Node* b, Label* if_true,
Label* if_false) {
Label if_lessthan(this), if_notlessthan(this);
Branch(Int32LessThan(a, b), &if_lessthan, &if_notlessthan);
Bind(&if_lessthan);
Goto(if_true);
Bind(&if_notlessthan);
Goto(if_false);
}
void CodeStubAssembler::BranchIfSmiLessThan(Node* a, Node* b, Label* if_true,
Label* if_false) {
Label if_lessthan(this), if_notlessthan(this);

View File

@ -253,6 +253,7 @@ class CodeStubAssembler {
Node* SmiEqual(Node* a, Node* b);
Node* SmiLessThan(Node* a, Node* b);
Node* SmiLessThanOrEqual(Node* a, Node* b);
Node* SmiMin(Node* a, Node* b);
// Load a value from the root array.
Node* LoadRoot(Heap::RootListIndex root_index);
@ -292,6 +293,7 @@ class CodeStubAssembler {
// Branching helpers.
// TODO(danno): Can we be more cleverish wrt. edge-split?
void BranchIfInt32LessThan(Node* a, Node* b, Label* if_true, Label* if_false);
void BranchIfSmiLessThan(Node* a, Node* b, Label* if_true, Label* if_false);
void BranchIfSmiLessThanOrEqual(Node* a, Node* b, Label* if_true,
Label* if_false);

View File

@ -161,6 +161,11 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kReThrow:
case Runtime::kStringCompare:
case Runtime::kStringEqual:
case Runtime::kStringNotEqual:
case Runtime::kStringLessThan:
case Runtime::kStringLessThanOrEqual:
case Runtime::kStringGreaterThan:
case Runtime::kStringGreaterThanOrEqual:
case Runtime::kToFastProperties: // TODO(jarin): Is it safe?
case Runtime::kTraceEnter:
case Runtime::kTraceExit:

View File

@ -1160,13 +1160,39 @@ class RepresentationSelector {
break;
}
case IrOpcode::kStringLessThan: {
VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
if (lower()) lowering->DoStringLessThan(node);
VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::BoolTagged());
if (lower()) {
// StringLessThan(x, y) => Call(StringLessThanStub, x, y, no-context)
Operator::Properties properties = node->op()->properties();
Callable callable = CodeFactory::StringLessThan(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::kStringLessThanOrEqual: {
VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool());
if (lower()) lowering->DoStringLessThanOrEqual(node);
VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::BoolTagged());
if (lower()) {
// StringLessThanOrEqual(x, y)
// => Call(StringLessThanOrEqualStub, x, y, no-context)
Operator::Properties properties = node->op()->properties();
Callable callable =
CodeFactory::StringLessThanOrEqual(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::kAllocate: {
@ -1610,22 +1636,6 @@ void SimplifiedLowering::DoStoreBuffer(Node* node) {
NodeProperties::ChangeOp(node, machine()->CheckedStore(rep));
}
Node* SimplifiedLowering::StringComparison(Node* node) {
Operator::Properties properties = node->op()->properties();
Callable callable = CodeFactory::StringCompare(isolate());
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), zone(), callable.descriptor(), 0, flags, properties);
return graph()->NewNode(
common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
NodeProperties::GetValueInput(node, 0),
NodeProperties::GetValueInput(node, 1), jsgraph()->NoContextConstant(),
NodeProperties::GetEffectInput(node),
NodeProperties::GetControlInput(node));
}
Node* SimplifiedLowering::Int32Div(Node* const node) {
Int32BinopMatcher m(node);
Node* const zero = jsgraph()->Int32Constant(0);
@ -1888,43 +1898,6 @@ void SimplifiedLowering::DoShift(Node* node, Operator const* op,
NodeProperties::ChangeOp(node, op);
}
namespace {
void ReplaceEffectUses(Node* node, Node* replacement) {
// Requires distinguishing between value and effect edges.
DCHECK(replacement->op()->EffectOutputCount() > 0);
for (Edge edge : node->use_edges()) {
if (NodeProperties::IsEffectEdge(edge)) {
edge.UpdateTo(replacement);
} else {
DCHECK(NodeProperties::IsValueEdge(edge));
}
}
}
} // namespace
void SimplifiedLowering::DoStringLessThan(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()->IntLessThan());
}
void SimplifiedLowering::DoStringLessThanOrEqual(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()->IntLessThanOrEqual());
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -37,8 +37,6 @@ class SimplifiedLowering final {
RepresentationChanger* changer);
void DoStoreBuffer(Node* node);
void DoShift(Node* node, Operator const* op, Type* rhs_type);
void DoStringLessThan(Node* node);
void DoStringLessThanOrEqual(Node* node);
// TODO(bmeurer): This is a gigantic hack to support the gigantic LoadBuffer
// typing hack to support the gigantic "asm.js should be fast without proper
@ -57,7 +55,6 @@ class SimplifiedLowering final {
// position information via the SourcePositionWrapper like all other reducers.
SourcePositionTable* source_positions_;
Node* StringComparison(Node* node);
Node* Int32Div(Node* const node);
Node* Int32Mod(Node* const node);
Node* Uint32Div(Node* const node);

View File

@ -2366,17 +2366,10 @@ 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()));
Handle<Code> code = CodeFactory::StringCompare(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ CompareRoot(r0, Heap::kTrueValueRootIndex);
EmitBranch(instr, eq);
}

View File

@ -5193,18 +5193,10 @@ 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));
}
Handle<Code> code = CodeFactory::StringCompare(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ CompareRoot(x0, Heap::kTrueValueRootIndex);
EmitBranch(instr, eq);
}

View File

@ -2168,17 +2168,10 @@ 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()));
Handle<Code> code = CodeFactory::StringCompare(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ CompareRoot(eax, Heap::kTrueValueRootIndex);
EmitBranch(instr, equal);
}

View File

@ -2275,19 +2275,10 @@ 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));
}
Handle<Code> code = CodeFactory::StringCompare(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ LoadRoot(at, Heap::kTrueValueRootIndex);
EmitBranch(instr, eq, v0, Operand(at));
}

View File

@ -2392,19 +2392,10 @@ 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));
}
Handle<Code> code = CodeFactory::StringCompare(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ LoadRoot(at, Heap::kTrueValueRootIndex);
EmitBranch(instr, eq, v0, Operand(at));
}

View File

@ -2318,17 +2318,10 @@ 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));
Handle<Code> code = CodeFactory::StringCompare(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
EmitBranch(instr, equal);
}

View File

@ -2864,44 +2864,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void StringCompareStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- edx : left string
// -- eax : right string
// -- esp[0] : return address
// -----------------------------------
__ AssertString(edx);
__ AssertString(eax);
Label not_same;
__ cmp(edx, eax);
__ j(not_equal, &not_same, Label::kNear);
__ Move(eax, Immediate(Smi::FromInt(EQUAL)));
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1);
__ Ret();
__ bind(&not_same);
// Check that both objects are sequential one-byte strings.
Label runtime;
__ JumpIfNotBothSequentialOneByteStrings(edx, eax, ecx, ebx, &runtime);
// Compare flat one-byte strings.
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1);
StringHelper::GenerateCompareFlatOneByteStrings(masm, edx, eax, ecx, ebx,
edi);
// Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
// tagged as a small integer.
__ bind(&runtime);
__ PopReturnAddressTo(ecx);
__ Push(edx);
__ Push(eax);
__ PushReturnAddressFrom(ecx);
__ TailCallRuntime(Runtime::kStringCompare);
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- edx : left

View File

@ -3003,39 +3003,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void StringCompareStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a1 : left
// -- a0 : right
// -- ra : return address
// -----------------------------------
__ AssertString(a1);
__ AssertString(a0);
Label not_same;
__ Branch(&not_same, ne, a0, Operand(a1));
__ li(v0, Operand(Smi::FromInt(EQUAL)));
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1, a1,
a2);
__ Ret();
__ bind(&not_same);
// Check that both objects are sequential one-byte strings.
Label runtime;
__ JumpIfNotBothSequentialOneByteStrings(a1, a0, a2, a3, &runtime);
// Compare flat ASCII strings natively.
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1, a2,
a3);
StringHelper::GenerateCompareFlatOneByteStrings(masm, a1, a0, a2, a3, t0, t1);
__ bind(&runtime);
__ Push(a1, a0);
__ TailCallRuntime(Runtime::kStringCompare);
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a1 : left

View File

@ -3007,39 +3007,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void StringCompareStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a1 : left
// -- a0 : right
// -- ra : return address
// -----------------------------------
__ AssertString(a1);
__ AssertString(a0);
Label not_same;
__ Branch(&not_same, ne, a0, Operand(a1));
__ li(v0, Operand(Smi::FromInt(EQUAL)));
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1, a1,
a2);
__ Ret();
__ bind(&not_same);
// Check that both objects are sequential one-byte strings.
Label runtime;
__ JumpIfNotBothSequentialOneByteStrings(a1, a0, a2, a3, &runtime);
// Compare flat ASCII strings natively.
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1, a2,
a3);
StringHelper::GenerateCompareFlatOneByteStrings(masm, a1, a0, a2, a3, t0, t1);
__ bind(&runtime);
__ Push(a1, a0);
__ TailCallRuntime(Runtime::kStringCompare);
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a1 : left

View File

@ -2817,45 +2817,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void StringCompareStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rdx : left string
// -- rax : right string
// -- rsp[0] : return address
// -----------------------------------
__ AssertString(rdx);
__ AssertString(rax);
// Check for identity.
Label not_same;
__ cmpp(rdx, rax);
__ j(not_equal, &not_same, Label::kNear);
__ Move(rax, Smi::FromInt(EQUAL));
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1);
__ Ret();
__ bind(&not_same);
// Check that both are sequential one-byte strings.
Label runtime;
__ JumpIfNotBothSequentialOneByteStrings(rdx, rax, rcx, rbx, &runtime);
// Inline comparison of one-byte strings.
__ IncrementCounter(isolate()->counters()->string_compare_native(), 1);
StringHelper::GenerateCompareFlatOneByteStrings(masm, rdx, rax, rcx, rbx, rdi,
r8);
// Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
// tagged as a small integer.
__ bind(&runtime);
__ PopReturnAddressTo(rcx);
__ Push(rdx);
__ Push(rax);
__ PushReturnAddressFrom(rcx);
__ TailCallRuntime(Runtime::kStringCompare);
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rdx : left

View File

@ -1140,22 +1140,8 @@ TEST(LowerReferenceEqual_to_wordeq) {
t.CheckLoweringBinop(opcode, t.simplified()->ReferenceEqual(Type::Any()));
}
TEST(LowerStringOps_to_call_and_compare) {
// These tests need linkage for the calls.
TestingGraph t(Type::String(), Type::String());
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_lt, t.simplified()->StringLessThan());
t.CheckLoweringStringBinop(compare_le,
t.simplified()->StringLessThanOrEqual());
}
void CheckChangeInsertion(IrOpcode::Value expected, MachineType from,
MachineType to, Type* type = Type::Any()) {
void CheckChangeInsertion(IrOpcode::Value expected, MachineType from,
MachineType to, Type* type = Type::Any()) {
TestingGraph t(Type::Any());
Node* in = t.ExampleWithOutput(from);
NodeProperties::SetType(in, type);
@ -1166,7 +1152,6 @@ TEST(LowerStringOps_to_call_and_compare) {
CHECK_EQ(in, use->InputAt(0)->InputAt(0));
}
TEST(InsertBasicChanges) {
CheckChangeInsertion(IrOpcode::kChangeFloat64ToInt32, MachineType::Float64(),
MachineType::Int32(), Type::Signed32());