[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}
This commit is contained in:
parent
0b3e436aa5
commit
2689548e38
@ -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);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/code-factory.h"
|
||||
#include "src/compiler/code-stub-assembler.h"
|
||||
#include "src/factory.h"
|
||||
#include "src/gdb-jit.h"
|
||||
@ -500,12 +501,12 @@ void StringLengthStub::GenerateAssembly(
|
||||
|
||||
namespace {
|
||||
|
||||
enum StrictEqualMode { kStrictEqual, kStrictNotEqual };
|
||||
enum ResultMode { kDontNegateResult, kNegateResult };
|
||||
|
||||
void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
|
||||
StrictEqualMode mode) {
|
||||
// Here's pseudo-code for the algorithm below in case of kStrictEqual mode;
|
||||
// for kStrictNotEqual mode we properly negate the result.
|
||||
Isolate* isolate, ResultMode mode) {
|
||||
// Here's pseudo-code for the algorithm below in case of kDontNegateResult
|
||||
// mode; for kNegateResult mode we properly negate the result.
|
||||
//
|
||||
// if (lhs == rhs) {
|
||||
// if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN;
|
||||
@ -705,12 +706,10 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
|
||||
|
||||
assembler->Bind(&if_rhsisstring);
|
||||
{
|
||||
// TODO(bmeurer): Optimize this further once the StringEqual
|
||||
// functionality is available in TurboFan land.
|
||||
Runtime::FunctionId function_id = (mode == kStrictEqual)
|
||||
? Runtime::kStringEqual
|
||||
: Runtime::kStringNotEqual;
|
||||
assembler->TailCallRuntime(function_id, context, lhs, rhs);
|
||||
Callable callable = (mode == kDontNegateResult)
|
||||
? CodeFactory::StringEqual(isolate)
|
||||
: CodeFactory::StringNotEqual(isolate);
|
||||
assembler->TailCallStub(callable, context, lhs, rhs);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotstring);
|
||||
@ -730,7 +729,7 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
|
||||
assembler->Bind(&if_lhsissimd128value);
|
||||
{
|
||||
// TODO(bmeurer): Inline the Simd128Value equality check.
|
||||
Runtime::FunctionId function_id = (mode == kStrictEqual)
|
||||
Runtime::FunctionId function_id = (mode == kDontNegateResult)
|
||||
? Runtime::kStrictEqual
|
||||
: Runtime::kStrictNotEqual;
|
||||
assembler->TailCallRuntime(function_id, context, lhs, rhs);
|
||||
@ -785,22 +784,209 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
|
||||
}
|
||||
|
||||
assembler->Bind(&if_equal);
|
||||
assembler->Return(assembler->BooleanConstant(mode == kStrictEqual));
|
||||
assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
|
||||
|
||||
assembler->Bind(&if_notequal);
|
||||
assembler->Return(assembler->BooleanConstant(mode == kStrictNotEqual));
|
||||
assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
|
||||
}
|
||||
|
||||
void GenerateStringEqual(compiler::CodeStubAssembler* assembler,
|
||||
ResultMode mode) {
|
||||
// Here's pseudo-code for the algorithm below in case of kDontNegateResult
|
||||
// mode; for kNegateResult mode we properly negate the result.
|
||||
//
|
||||
// if (lhs == rhs) return true;
|
||||
// if (lhs->length() != rhs->length()) return false;
|
||||
// if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
|
||||
// return false;
|
||||
// }
|
||||
// if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
|
||||
// for (i = 0; i != lhs->length(); ++i) {
|
||||
// if (lhs[i] != rhs[i]) return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// return %StringEqual(lhs, rhs);
|
||||
|
||||
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_equal(assembler), if_notequal(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);
|
||||
{
|
||||
// The {lhs} and {rhs} don't refer to the exact same String object.
|
||||
|
||||
// Load the length of {lhs} and {rhs}.
|
||||
Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
|
||||
Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
|
||||
|
||||
// Check if the lengths of {lhs} and {rhs} are equal.
|
||||
Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
|
||||
assembler->Branch(assembler->WordEqual(lhs_length, rhs_length),
|
||||
&if_lengthisequal, &if_lengthisnotequal);
|
||||
|
||||
assembler->Bind(&if_lengthisequal);
|
||||
{
|
||||
// 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 if both {lhs} and {rhs} are internalized.
|
||||
int const kBothInternalizedMask =
|
||||
kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
|
||||
int const kBothInternalizedTag =
|
||||
kInternalizedTag | (kInternalizedTag << 8);
|
||||
Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
|
||||
assembler->Branch(assembler->Word32Equal(
|
||||
assembler->Word32And(both_instance_types,
|
||||
assembler->Int32Constant(
|
||||
kBothInternalizedMask)),
|
||||
assembler->Int32Constant(kBothInternalizedTag)),
|
||||
&if_bothinternalized, &if_notbothinternalized);
|
||||
|
||||
assembler->Bind(&if_bothinternalized);
|
||||
{
|
||||
// Fast negative check for internalized-to-internalized equality.
|
||||
assembler->Goto(&if_notequal);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_notbothinternalized);
|
||||
{
|
||||
// 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);
|
||||
{
|
||||
// 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(lhs_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->Goto(&if_notequal);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_done);
|
||||
assembler->Goto(&if_equal);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_notbothonebyteseqstrings);
|
||||
{
|
||||
// TODO(bmeurer): Add fast case support for flattened cons strings;
|
||||
// also add support for two byte string equality checks.
|
||||
Runtime::FunctionId function_id = (mode == kDontNegateResult)
|
||||
? Runtime::kStringEqual
|
||||
: Runtime::kStringNotEqual;
|
||||
assembler->TailCallRuntime(function_id, context, lhs, rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lengthisnotequal);
|
||||
{
|
||||
// Mismatch in length of {lhs} and {rhs}, cannot be equal.
|
||||
assembler->Goto(&if_notequal);
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_equal);
|
||||
assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
|
||||
|
||||
assembler->Bind(&if_notequal);
|
||||
assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void StrictEqualStub::GenerateAssembly(
|
||||
compiler::CodeStubAssembler* assembler) const {
|
||||
GenerateStrictEqual(assembler, kStrictEqual);
|
||||
GenerateStrictEqual(assembler, isolate(), kDontNegateResult);
|
||||
}
|
||||
|
||||
void StrictNotEqualStub::GenerateAssembly(
|
||||
compiler::CodeStubAssembler* assembler) const {
|
||||
GenerateStrictEqual(assembler, kStrictNotEqual);
|
||||
GenerateStrictEqual(assembler, isolate(), kNegateResult);
|
||||
}
|
||||
|
||||
void StringEqualStub::GenerateAssembly(
|
||||
compiler::CodeStubAssembler* assembler) const {
|
||||
GenerateStringEqual(assembler, kDontNegateResult);
|
||||
}
|
||||
|
||||
void StringNotEqualStub::GenerateAssembly(
|
||||
compiler::CodeStubAssembler* assembler) const {
|
||||
GenerateStringEqual(assembler, kNegateResult);
|
||||
}
|
||||
|
||||
void ToBooleanStub::GenerateAssembly(
|
||||
|
@ -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));
|
||||
|
||||
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
|
||||
CallCode(code, RelocInfo::CODE_TARGET, instr);
|
||||
__ cmp(r0, Operand::Zero());
|
||||
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));
|
||||
|
||||
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
|
||||
CallCode(code, RelocInfo::CODE_TARGET, instr);
|
||||
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);
|
||||
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));
|
||||
|
||||
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
|
||||
CallCode(code, RelocInfo::CODE_TARGET, instr);
|
||||
__ test(eax, 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));
|
||||
|
||||
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
|
||||
CallCode(code, RelocInfo::CODE_TARGET, instr);
|
||||
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));
|
||||
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));
|
||||
|
||||
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
|
||||
CallCode(code, RelocInfo::CODE_TARGET, instr);
|
||||
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));
|
||||
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));
|
||||
|
||||
Handle<Code> code = CodeFactory::StringCompare(isolate()).code();
|
||||
CallCode(code, RelocInfo::CODE_TARGET, instr);
|
||||
__ testp(rax, 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());
|
||||
|
Loading…
Reference in New Issue
Block a user