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, ¬_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(¬_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 |