Index: src/ia32/codegen-ia32.cc |
=================================================================== |
--- src/ia32/codegen-ia32.cc (revision 3568) |
+++ src/ia32/codegen-ia32.cc (working copy) |
@@ -5447,6 +5447,18 @@ |
} |
+void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) { |
+ ASSERT_EQ(2, args->length()); |
+ |
+ Load(args->at(0)); |
+ Load(args->at(1)); |
+ |
+ StringCompareStub stub; |
+ Result answer = frame_->CallStub(&stub, 2); |
+ frame_->Push(&answer); |
+} |
+ |
+ |
void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) { |
ASSERT_EQ(args->length(), 4); |
@@ -8562,9 +8574,10 @@ |
// Fast negative check for symbol-to-symbol equality. |
__ bind(&check_for_symbols); |
+ Label check_for_strings; |
if (cc_ == equal) { |
- BranchIfNonSymbol(masm, &call_builtin, eax, ecx); |
- BranchIfNonSymbol(masm, &call_builtin, edx, ecx); |
+ BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); |
+ BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); |
// We've already checked for object identity, so if both operands |
// are symbols they aren't equal. Register eax already holds a |
@@ -8572,6 +8585,44 @@ |
__ ret(2 * kPointerSize); |
} |
+ __ 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); |
+ |
+ // Inline comparison of ascii strings. |
+ StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
+ edx, |
+ eax, |
+ ecx, |
+ ebx, |
+ edi); |
+#ifdef DEBUG |
+ __ Abort("Unexpected fall-through from string comparison"); |
+#endif |
+ |
__ bind(&call_builtin); |
// must swap argument order |
__ pop(ecx); |
@@ -9579,6 +9630,144 @@ |
__ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); |
} |
+ |
+void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
+ Register left, |
+ Register right, |
+ Register counter, |
+ Register scratch1, |
+ Register scratch2) { |
+ ASSERT(counter.is(ecx)); |
+ Label compare_lengths, compare_lengths_1; |
+ |
+ // Find minimum length. If either length is zero just compare lengths. |
+ __ mov(counter, FieldOperand(left, String::kLengthOffset)); |
+ __ test(counter, Operand(counter)); |
+ __ j(zero, &compare_lengths_1); |
+ __ mov(scratch1, FieldOperand(right, String::kLengthOffset)); |
+ __ test(scratch1, Operand(scratch1)); |
+ __ j(zero, &compare_lengths_1); |
+ __ cmp(counter, Operand(scratch1)); |
+ if (CpuFeatures::IsSupported(CMOV)) { |
+ CpuFeatures::Scope use_cmov(CMOV); |
+ __ cmov(less, counter, Operand(scratch1)); |
+ } else { |
+ Label l; |
+ __ j(less, &l); |
+ __ mov(counter, scratch1); |
+ __ bind(&l); |
+ } |
+ |
+ Label result_greater, result_less; |
+ Label loop; |
+ // Compare next character. |
+ __ mov(scratch2, Immediate(-1)); // Index into strings. |
+ __ bind(&loop); |
+ // Compare characters. |
+ __ add(Operand(scratch2), Immediate(1)); |
+ __ mov_b(scratch1, Operand(left, |
+ scratch2, |
+ times_1, |
+ SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ subb(scratch1, Operand(right, |
+ scratch2, |
+ times_1, |
+ SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ loope(&loop); |
+ // If min length characters match compare lengths otherwise last character |
+ // compare is the result. |
+ __ j(equal, &compare_lengths); |
+ __ j(less, &result_less); |
+ __ jmp(&result_greater); |
+ |
+ // Compare lengths. |
+ Label result_not_equal; |
+ __ bind(&compare_lengths); |
+ __ mov(counter, FieldOperand(left, String::kLengthOffset)); |
+ __ bind(&compare_lengths_1); |
+ __ sub(counter, FieldOperand(right, String::kLengthOffset)); |
+ __ 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); |
+ __ 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); |
+ __ ret(2 * kPointerSize); |
+ |
+ // Result is GREATER. |
+ __ bind(&result_greater); |
+ __ mov(eax, Immediate(Smi::FromInt(GREATER)->value())); |
+ __ IncrementCounter(&Counters::string_compare_native, 1); |
+ __ ret(2 * kPointerSize); |
+} |
+ |
+ |
+void StringCompareStub::Generate(MacroAssembler* masm) { |
+ Label runtime; |
+ |
+ // Stack frame on entry. |
+ // esp[0]: return address |
+ // esp[4]: right string |
+ // esp[8]: left string |
+ |
+ __ mov(edx, Operand(esp, 2 * kPointerSize)); // left |
+ __ mov(eax, Operand(esp, 1 * kPointerSize)); // right |
+ |
+ Label not_same; |
+ __ cmp(edx, Operand(eax)); |
+ __ j(not_equal, ¬_same); |
+ ASSERT_EQ(0, EQUAL); |
+ ASSERT_EQ(0, kSmiTag); |
+ __ xor_(eax, Operand(eax)); |
+ __ 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); |
+ |
+ // Compare flat ascii strings. |
+ 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); |
+ __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
+} |
+ |
#undef __ |
} } // namespace v8::internal |