Chromium Code Reviews| 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 |