Index: src/ia32/codegen-ia32.cc |
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc |
index b6f4cb77c73097f5b14891850fd1b032cd2b4ba9..9d49df51f7e4df78135a1b9f5f407ae976c0bee8 100644 |
--- a/src/ia32/codegen-ia32.cc |
+++ b/src/ia32/codegen-ia32.cc |
@@ -8575,30 +8575,7 @@ void CompareStub::Generate(MacroAssembler* masm) { |
__ bind(&check_for_strings); |
- // Check that both objects are not smis. |
- ASSERT_EQ(0, kSmiTag); |
- __ mov(ebx, Operand(edx)); |
- __ and_(ebx, Operand(eax)); |
- __ test(ebx, Immediate(kSmiTagMask)); |
- __ j(zero, &call_builtin); |
- |
- // Load instance type for both objects. |
- __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
- __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
- __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
- __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
- |
- // Check that both are flat ascii strings. |
- Label non_ascii_flat; |
- ASSERT(kNotStringTag != 0); |
- const int kFlatAsciiString = |
- kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; |
- __ and_(ecx, kFlatAsciiString); |
- __ cmp(ecx, kStringTag | kSeqStringTag | kAsciiStringTag); |
- __ j(not_equal, &call_builtin); |
- __ and_(ebx, kFlatAsciiString); |
- __ cmp(ebx, kStringTag | kSeqStringTag | kAsciiStringTag); |
- __ j(not_equal, &call_builtin); |
+ __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &call_builtin); |
// Inline comparison of ascii strings. |
StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
@@ -9652,79 +9629,76 @@ void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
Register scratch1, |
Register scratch2, |
Register scratch3) { |
- Label compare_lengths, compare_lengths_1; |
- |
- // Find minimum length. If either length is zero just compare lengths. |
+ Label result_not_equal; |
+ Label result_greater; |
+ Label compare_lengths; |
+ // Find minimum length. |
+ Label left_shorter; |
__ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |
- __ test(scratch1, Operand(scratch1)); |
- __ j(zero, &compare_lengths_1); |
- __ mov(scratch2, FieldOperand(right, String::kLengthOffset)); |
- __ test(scratch2, Operand(scratch2)); |
- __ j(zero, &compare_lengths_1); |
- __ cmp(scratch1, Operand(scratch2)); |
- if (CpuFeatures::IsSupported(CMOV)) { |
- CpuFeatures::Scope use_cmov(CMOV); |
- __ cmov(greater, scratch1, Operand(scratch2)); |
- } else { |
- Label l; |
- __ j(less, &l); |
- __ mov(scratch1, scratch2); |
- __ bind(&l); |
+ __ mov(scratch3, scratch1); |
+ __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); |
+ |
+ Register length_delta = scratch3; |
+ |
+ __ j(less_equal, &left_shorter); |
+ // Right string is shorter. Change scratch1 to be length of right string. |
+ __ sub(scratch1, Operand(length_delta)); |
+ __ bind(&left_shorter); |
+ |
+ Register min_length = scratch1; |
+ |
+ // If either length is zero, just compare lengths. |
+ __ test(min_length, Operand(min_length)); |
+ __ j(zero, &compare_lengths); |
+ |
+ // Change index to run from -min_length to -1 by adding min_length |
+ // to string start. This means that loop ends when index reaches zero, |
+ // which doesn't need an additional compare. |
+ __ lea(left, |
+ FieldOperand(left, |
+ min_length, times_1, |
+ SeqAsciiString::kHeaderSize)); |
+ __ lea(right, |
+ FieldOperand(right, |
+ min_length, times_1, |
+ SeqAsciiString::kHeaderSize)); |
+ __ neg(min_length); |
+ |
+ Register index = min_length; // index = -min_length; |
+ |
+ { |
+ // Compare loop. |
+ Label loop; |
+ __ bind(&loop); |
+ // Compare characters. |
+ __ mov_b(scratch2, Operand(left, index, times_1, 0)); |
+ __ cmpb(scratch2, Operand(right, index, times_1, 0)); |
+ __ j(not_equal, &result_not_equal); |
+ __ add(Operand(index), Immediate(1)); |
+ __ j(not_zero, &loop); |
} |
- Label result_greater, result_less; |
- Label loop; |
- // Compare next character. |
- __ mov(scratch3, Immediate(-1)); // Index into strings. |
- __ bind(&loop); |
- // Compare characters. |
- Label character_compare_done; |
- __ add(Operand(scratch3), Immediate(1)); |
- __ mov_b(scratch2, Operand(left, |
- scratch3, |
- times_1, |
- SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
- __ subb(scratch2, Operand(right, |
- scratch3, |
- times_1, |
- SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
- __ j(not_equal, &character_compare_done); |
- __ sub(Operand(scratch1), Immediate(1)); |
- __ j(not_zero, &loop); |
- // If min length characters match compare lengths otherwise last character |
- // compare is the result. |
- __ bind(&character_compare_done); |
- __ j(equal, &compare_lengths); |
- __ j(less, &result_less); |
- __ jmp(&result_greater); |
- |
- // Compare lengths. |
- Label result_not_equal; |
+ // Compare lengths - strings up to min-length are equal. |
__ bind(&compare_lengths); |
- __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |
- __ bind(&compare_lengths_1); |
- __ sub(scratch1, FieldOperand(right, String::kLengthOffset)); |
+ __ test(length_delta, Operand(length_delta)); |
__ j(not_zero, &result_not_equal); |
// Result is EQUAL. |
ASSERT_EQ(0, EQUAL); |
ASSERT_EQ(0, kSmiTag); |
- __ xor_(eax, Operand(eax)); |
- __ IncrementCounter(&Counters::string_compare_native, 1); |
+ __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
__ ret(2 * kPointerSize); |
+ |
__ bind(&result_not_equal); |
__ j(greater, &result_greater); |
// Result is LESS. |
- __ bind(&result_less); |
- __ mov(eax, Immediate(Smi::FromInt(LESS)->value())); |
- __ IncrementCounter(&Counters::string_compare_native, 1); |
+ __ Set(eax, Immediate(Smi::FromInt(LESS))); |
__ ret(2 * kPointerSize); |
// Result is GREATER. |
__ bind(&result_greater); |
- __ mov(eax, Immediate(Smi::FromInt(GREATER)->value())); |
- __ IncrementCounter(&Counters::string_compare_native, 1); |
+ __ Set(eax, Immediate(Smi::FromInt(GREATER))); |
__ ret(2 * kPointerSize); |
} |
@@ -9745,41 +9719,19 @@ void StringCompareStub::Generate(MacroAssembler* masm) { |
__ j(not_equal, ¬_same); |
ASSERT_EQ(0, EQUAL); |
ASSERT_EQ(0, kSmiTag); |
- __ xor_(eax, Operand(eax)); |
+ __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
__ IncrementCounter(&Counters::string_compare_native, 1); |
__ ret(2 * kPointerSize); |
__ bind(¬_same); |
- // Check that both objects are not smis. |
- ASSERT_EQ(0, kSmiTag); |
- __ mov(ebx, Operand(edx)); |
- __ and_(ebx, Operand(eax)); |
- __ test(ebx, Immediate(kSmiTagMask)); |
- __ j(zero, &runtime); |
- |
- // Load instance type for both strings. |
- __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
- __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
- __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
- __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
- |
- // Check that both are flat ascii strings. |
- Label non_ascii_flat; |
- __ and_(ecx, kStringRepresentationMask | kStringEncodingMask); |
- __ cmp(ecx, kSeqStringTag | kAsciiStringTag); |
- __ j(not_equal, &non_ascii_flat); |
- const int kFlatAsciiString = |
- kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; |
- __ and_(ebx, kFlatAsciiString); |
- __ cmp(ebx, kStringTag | kSeqStringTag | kAsciiStringTag); |
- __ j(not_equal, &non_ascii_flat); |
+ // Check that both objects are sequential ascii strings. |
+ __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |
// Compare flat ascii strings. |
+ __ IncrementCounter(&Counters::string_compare_native, 1); |
GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |
- __ bind(&non_ascii_flat); |
- |
// Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
// tagged as a small integer. |
__ bind(&runtime); |