| Index: src/arm/codegen-arm.cc
|
| diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
|
| index 1dac4ccb3a18cc8310c5465e170a2f57fe062322..72cff12d7c28f00b7036e35252b4807a4aafca3e 100644
|
| --- a/src/arm/codegen-arm.cc
|
| +++ b/src/arm/codegen-arm.cc
|
| @@ -3576,7 +3576,8 @@ void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) {
|
| Load(args->at(0));
|
| Load(args->at(1));
|
|
|
| - frame_->CallRuntime(Runtime::kStringCompare, 2);
|
| + StringCompareStub stub;
|
| + frame_->CallStub(&stub, 2);
|
| frame_->EmitPush(r0);
|
| }
|
|
|
| @@ -5089,8 +5090,9 @@ static void EmitCheckForSymbols(MacroAssembler* masm, Label* slow) {
|
| }
|
|
|
|
|
| -// On entry r0 and r1 are the things to be compared. On exit r0 is 0,
|
| -// positive or negative to indicate the result of the comparison.
|
| +// On entry r0 (rhs) and r1 (lhs) are the values to be compared.
|
| +// On exit r0 is 0, positive or negative to indicate the result of
|
| +// the comparison.
|
| void CompareStub::Generate(MacroAssembler* masm) {
|
| Label slow; // Call builtin.
|
| Label not_smis, both_loaded_as_doubles, lhs_not_nan;
|
| @@ -5168,6 +5170,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
| }
|
|
|
| Label check_for_symbols;
|
| + Label flat_string_check;
|
| // Check for heap-number-heap-number comparison. Can jump to slow case,
|
| // or load both doubles into r0, r1, r2, r3 and jump to the code that handles
|
| // that case. If the inputs are not doubles then jumps to check_for_symbols.
|
| @@ -5175,7 +5178,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
| EmitCheckForTwoHeapNumbers(masm,
|
| &both_loaded_as_doubles,
|
| &check_for_symbols,
|
| - &slow);
|
| + &flat_string_check);
|
|
|
| __ bind(&check_for_symbols);
|
| // In the strict case the EmitStrictTwoHeapObjectCompare already took care of
|
| @@ -5183,10 +5186,27 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
| if (cc_ == eq && !strict_) {
|
| // Either jumps to slow or returns the answer. Assumes that r2 is the type
|
| // of r0 on entry.
|
| - EmitCheckForSymbols(masm, &slow);
|
| + EmitCheckForSymbols(masm, &flat_string_check);
|
| }
|
|
|
| + // Check for both being sequential ASCII strings, and inline if that is the
|
| + // case.
|
| + __ bind(&flat_string_check);
|
| +
|
| + __ JumpIfNonSmisNotBothSequentialAsciiStrings(r0, r1, r2, r3, &slow);
|
| +
|
| + __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3);
|
| + StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
|
| + r1,
|
| + r0,
|
| + r2,
|
| + r3,
|
| + r4,
|
| + r5);
|
| + // Never falls through to here.
|
| +
|
| __ bind(&slow);
|
| +
|
| __ push(r1);
|
| __ push(r0);
|
| // Figure out which native to call and setup the arguments.
|
| @@ -6737,6 +6757,101 @@ int CompareStub::MinorKey() {
|
| }
|
|
|
|
|
| +
|
| +
|
| +void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
|
| + Register left,
|
| + Register right,
|
| + Register scratch1,
|
| + Register scratch2,
|
| + Register scratch3,
|
| + Register scratch4) {
|
| + Label compare_lengths;
|
| + // Find minimum length and length difference.
|
| + __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset));
|
| + __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
|
| + __ sub(scratch3, scratch1, Operand(scratch2), SetCC);
|
| + Register length_delta = scratch3;
|
| + __ mov(scratch1, scratch2, LeaveCC, gt);
|
| + Register min_length = scratch1;
|
| + __ tst(min_length, Operand(min_length));
|
| + __ b(eq, &compare_lengths);
|
| +
|
| + // Setup registers so that we only need to increment one register
|
| + // in the loop.
|
| + __ add(scratch2, min_length,
|
| + Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
|
| + __ add(left, left, Operand(scratch2));
|
| + __ add(right, right, Operand(scratch2));
|
| + // Registers left and right points to the min_length character of strings.
|
| + __ rsb(min_length, min_length, Operand(-1));
|
| + Register index = min_length;
|
| + // Index starts at -min_length.
|
| +
|
| + {
|
| + // Compare loop.
|
| + Label loop;
|
| + __ bind(&loop);
|
| + // Compare characters.
|
| + __ add(index, index, Operand(1), SetCC);
|
| + __ ldrb(scratch2, MemOperand(left, index), ne);
|
| + __ ldrb(scratch4, MemOperand(right, index), ne);
|
| + // Skip to compare lengths with eq condition true.
|
| + __ b(eq, &compare_lengths);
|
| + __ cmp(scratch2, scratch4);
|
| + __ b(eq, &loop);
|
| + // Fallthrough with eq condition false.
|
| + }
|
| + // Compare lengths - strings up to min-length are equal.
|
| + __ bind(&compare_lengths);
|
| + ASSERT(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
|
| + // Use zero length_delta as result.
|
| + __ mov(r0, Operand(length_delta), SetCC, eq);
|
| + // Fall through to here if characters compare not-equal.
|
| + __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt);
|
| + __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt);
|
| + __ Ret();
|
| +}
|
| +
|
| +
|
| +void StringCompareStub::Generate(MacroAssembler* masm) {
|
| + Label runtime;
|
| +
|
| + // Stack frame on entry.
|
| + // sp[0]: return address
|
| + // sp[4]: right string
|
| + // sp[8]: left string
|
| +
|
| + __ ldr(r0, MemOperand(sp, 2 * kPointerSize)); // left
|
| + __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // right
|
| +
|
| + Label not_same;
|
| + __ cmp(r0, r1);
|
| + __ b(ne, ¬_same);
|
| + ASSERT_EQ(0, EQUAL);
|
| + ASSERT_EQ(0, kSmiTag);
|
| + __ mov(r0, Operand(Smi::FromInt(EQUAL)));
|
| + __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2);
|
| + __ add(sp, sp, Operand(2 * kPointerSize));
|
| + __ Ret();
|
| +
|
| + __ bind(¬_same);
|
| +
|
| + // Check that both objects are sequential ascii strings.
|
| + __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime);
|
| +
|
| + // Compare flat ascii strings natively. Remove arguments from stack first.
|
| + __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3);
|
| + __ add(sp, sp, Operand(2 * kPointerSize));
|
| + GenerateCompareFlatAsciiStrings(masm, r0, r1, r2, r3, r4, r5);
|
| +
|
| + // 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
|
|
|