Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Unified Diff: src/x64/codegen-x64.cc

Issue 545108: X64 implementation of native ascii string compare. (Closed)
Patch Set: Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/x64/codegen-x64.h ('k') | src/x64/macro-assembler-x64.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/x64/codegen-x64.cc
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index e912bbcff9a80fc34cf9435f0337b23386797ff4..5d60889d43f4399e6cc2e75f0171f95565fdce6b 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -3937,7 +3937,8 @@ void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) {
Load(args->at(0));
Load(args->at(1));
- Result answer = frame_->CallRuntime(Runtime::kStringCompare, 2);
+ StringCompareStub stub;
+ Result answer = frame_->CallStub(&stub, 2);
frame_->Push(&answer);
}
@@ -6496,9 +6497,10 @@ void CompareStub::Generate(MacroAssembler* masm) {
// Fast negative check for symbol-to-symbol equality.
__ bind(&check_for_symbols);
+ Label check_for_strings;
if (cc_ == equal) {
- BranchIfNonSymbol(masm, &call_builtin, rax, kScratchRegister);
- BranchIfNonSymbol(masm, &call_builtin, rdx, kScratchRegister);
+ BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
+ BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);
// We've already checked for object identity, so if both operands
// are symbols they aren't equal. Register eax (not rax) already holds a
@@ -6506,6 +6508,45 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ ret(2 * kPointerSize);
}
+ __ bind(&check_for_strings);
+ Condition either_smi = masm->CheckEitherSmi(rax, rdx);
+ __ j(either_smi, &call_builtin);
+
+ // Load instance type for both objects to check if they are flat
+ // ASCII strings.
+ __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
+ __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
+
+ Label non_ascii_flat;
+ ASSERT(kNotStringTag != 0);
+ const int kFlatAsciiStringMask =
+ kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
+ const int kFlatAsciiStringBits =
+ kNotStringTag | kSeqStringTag | kAsciiStringTag;
+
+ __ andl(rcx, Immediate(kFlatAsciiStringMask));
+ __ andl(rbx, Immediate(kFlatAsciiStringMask));
+ // Interleave the bits to check both rcx and rbx in one test.
+ ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
+ __ lea(rcx, Operand(rcx, rbx, times_8, 0));
+ __ cmpl(rcx, Immediate(kFlatAsciiStringBits + (kFlatAsciiStringBits << 3)));
+ __ j(not_equal, &call_builtin);
+
+ // Inline comparison of ascii strings.
+ StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
+ rdx,
+ rax,
+ rcx,
+ rbx,
+ rdi,
+ r8);
+
+#ifdef DEBUG
+ __ Abort("Unexpected fall-through from string comparison");
+#endif
+
__ bind(&call_builtin);
// must swap argument order
__ pop(rcx);
@@ -8127,6 +8168,152 @@ void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm,
}
+
+void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
+ Register left,
+ Register right,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Register scratch4) {
+ // Ensure that you can always subtract a string length from a non-negative
+ // number (e.g. another length).
+ ASSERT(String::kMaxLength < 0x7fffffff);
+
+ // Find minimum length and length difference.
+ __ movl(scratch1, FieldOperand(left, String::kLengthOffset));
+ __ movl(scratch4, scratch1);
+ __ subl(scratch4, FieldOperand(right, String::kLengthOffset));
+ // Register scratch4 now holds left.length - right.length.
+ const Register length_difference = scratch4;
+ Label left_shorter;
+ __ j(less, &left_shorter);
+ // The right string isn't longer that the left one.
+ // Get the right string's length by subtracting the (non-negative) difference
+ // from the left string's length.
+ __ subl(scratch1, length_difference);
+ __ bind(&left_shorter);
+ // Register scratch1 now holds Min(left.length, right.length).
+ const Register min_length = scratch1;
+
+ Label compare_lengths;
+ // If min-length is zero, go directly to comparing lengths.
+ __ testl(min_length, min_length);
+ __ j(zero, &compare_lengths);
+
+ // Registers scratch2 and scratch3 are free.
+ Label result_not_equal;
+ Label loop;
+ {
+ // Check characters 0 .. min_length - 1 in a loop.
+ // Use scratch3 as loop index, min_length as limit and scratch2
+ // for computation.
+ const Register index = scratch3;
+ __ movl(index, Immediate(0)); // Index into strings.
+ __ bind(&loop);
+ // Compare characters.
+ // TODO(lrn): Could we load more than one character at a time?
+ __ movb(scratch2, FieldOperand(left,
+ index,
+ times_1,
+ SeqAsciiString::kHeaderSize));
+ // Increment index and use -1 modifier on next load to give
+ // the previous load extra time to complete.
+ __ addl(index, Immediate(1));
+ __ cmpb(scratch2, FieldOperand(right,
+ index,
+ times_1,
+ SeqAsciiString::kHeaderSize - 1));
+ __ j(not_equal, &result_not_equal);
+ __ cmpl(index, min_length);
+ __ j(not_equal, &loop);
+ }
+ // Completed loop without finding different characters.
+ // Compare lengths (precomputed).
+ __ bind(&compare_lengths);
+ __ testl(length_difference, length_difference);
+ __ j(not_zero, &result_not_equal);
+
+ // Result is EQUAL.
+ __ Move(rax, Smi::FromInt(EQUAL));
+ __ IncrementCounter(&Counters::string_compare_native, 1);
+ __ ret(2 * kPointerSize);
+
+ Label result_greater;
+ __ bind(&result_not_equal);
+ // Unequal comparison of left to right, either character or length.
+ __ j(greater, &result_greater);
+
+ // Result is LESS.
+ __ Move(rax, Smi::FromInt(LESS));
+ __ IncrementCounter(&Counters::string_compare_native, 1);
+ __ ret(2 * kPointerSize);
+
+ // Result is GREATER.
+ __ bind(&result_greater);
+ __ Move(rax, Smi::FromInt(GREATER));
+ __ IncrementCounter(&Counters::string_compare_native, 1);
+ __ ret(2 * kPointerSize);
+}
+
+
+void StringCompareStub::Generate(MacroAssembler* masm) {
+ Label runtime;
+
+ // Stack frame on entry.
+ // rsp[0]: return address
+ // rsp[8]: right string
+ // rsp[16]: left string
+
+ __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left
+ __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right
+
+ Label not_same;
+ __ cmpq(rdx, rax);
+ __ j(not_equal, &not_same);
+ __ Move(rax, Smi::FromInt(0));
Søren Thygesen Gjesse 2010/01/18 09:58:01 0 -> EQUAL.
Lasse Reichstein 2010/01/18 10:33:02 Fixed
+ __ IncrementCounter(&Counters::string_compare_native, 1);
+ __ ret(2 * kPointerSize);
+
+ __ bind(&not_same);
+
+ // Check that both objects are not smis.
+ Condition either_smi = masm->CheckEitherSmi(rax, rdx);
+ __ j(either_smi, &runtime);
+
+ // Load instance type for both strings.
+ __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
+ __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
+ __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
+
+ // Check that both are flat ascii strings.
+ Label non_ascii_flat;
+ ASSERT(kNotStringTag != 0);
+ const int kFlatAsciiStringMask =
+ kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
+ const int kFlatAsciiStringBits =
+ kNotStringTag | kSeqStringTag | kAsciiStringTag;
+
+ __ andl(rcx, Immediate(kFlatAsciiStringMask));
+ __ andl(rbx, Immediate(kFlatAsciiStringMask));
+ // Interleave the bits to check both rcx and rbx in one test.
+ ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
+ __ lea(rcx, Operand(rcx, rbx, times_8, 0));
+ __ cmpl(rcx, Immediate(kFlatAsciiStringBits + (kFlatAsciiStringBits << 3)));
+ __ j(not_equal, &non_ascii_flat);
+
+ // Inline comparison of ascii strings.
+ GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);
+
+ __ bind(&non_ascii_flat);
+
+ // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
+ // tagged as a small integer.
+ __ bind(&runtime);
+ __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
+}
+
#undef __
#define __ masm.
@@ -8220,6 +8407,7 @@ ModuloFunction CreateModuloFunction() {
#endif
+
#undef __
} } // namespace v8::internal
« no previous file with comments | « src/x64/codegen-x64.h ('k') | src/x64/macro-assembler-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698