Revision: 3670
Author: [email protected]
Date: Thu Jan 21 04:10:56 2010
Log: Implement inline string compare on ARM.
Backport optimizations from x64 version to ia32.

Review URL: http://codereview.chromium.org/546087
http://code.google.com/p/v8/source/detail?r=3670

Modified:
 /branches/bleeding_edge/src/arm/codegen-arm.cc
 /branches/bleeding_edge/src/arm/codegen-arm.h
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h
 /branches/bleeding_edge/src/ia32/assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/assembler-ia32.h
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/disasm-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
 /branches/bleeding_edge/src/list.h
 /branches/bleeding_edge/src/x64/codegen-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/test/cctest/test-disasm-ia32.cc

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Tue Jan 19 06:15:47 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Jan 21 04:10:56 2010
@@ -3576,7 +3576,8 @@
   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 @@
 }


-// 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 @@
   }

   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 @@
   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 @@
   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.
@@ -6735,6 +6755,101 @@
   if (cc_ != eq) nnn_value = 0;  // Avoid duplicate stubs.
return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0);
 }
+
+
+
+
+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, &not_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(&not_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 __
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Wed Jan 20 07:51:03 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Thu Jan 21 04:10:56 2010
@@ -512,6 +512,28 @@
 };


+class StringCompareStub: public CodeStub {
+ public:
+  StringCompareStub() { }
+
+  // Compare two flat ASCII strings and returns result in r0.
+  // Does not use the stack.
+  static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
+                                              Register left,
+                                              Register right,
+                                              Register scratch1,
+                                              Register scratch2,
+                                              Register scratch3,
+                                              Register scratch4);
+
+ private:
+  Major MajorKey() { return StringCompare; }
+  int MinorKey() { return 0; }
+
+  void Generate(MacroAssembler* masm);
+};
+
+
 } }  // namespace v8::internal

 #endif  // V8_ARM_CODEGEN_ARM_H_
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Jan 12 00:48:26 2010 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Jan 21 04:10:56 2010
@@ -1220,6 +1220,46 @@
   }
 }

+
+void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings(
+    Register first,
+    Register second,
+    Register scratch1,
+    Register scratch2,
+    Label* failure) {
+  // Test that both first and second are sequential ASCII strings.
+  // Assume that they are non-smis.
+  ldr(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
+  ldr(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
+  ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+  ldrb(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
+  int kFlatAsciiStringMask =
+      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+  int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+  and_(scratch1, scratch1, Operand(kFlatAsciiStringMask));
+  and_(scratch2, scratch2, Operand(kFlatAsciiStringMask));
+  cmp(scratch1, Operand(kFlatAsciiStringTag));
+  // Ignore second test if first test failed.
+  cmp(scratch2, Operand(kFlatAsciiStringTag), eq);
+  b(ne, failure);
+}
+
+void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first,
+                                                         Register second,
+                                                         Register scratch1,
+                                                         Register scratch2,
+                                                         Label* failure) {
+  // Check that neither is a smi.
+  ASSERT_EQ(0, kSmiTag);
+  and_(scratch1, first, Operand(second));
+  tst(scratch1, Operand(kSmiTagMask));
+  b(eq, failure);
+  JumpIfNonSmisNotBothSequentialAsciiStrings(first,
+                                             second,
+                                             scratch1,
+                                             scratch2,
+                                             failure);
+}


 #ifdef ENABLE_DEBUGGER_SUPPORT
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Jan 12 00:48:26 2010 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Thu Jan 21 04:10:56 2010
@@ -336,6 +336,25 @@
   bool generating_stub() { return generating_stub_; }
   void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
   bool allow_stub_calls() { return allow_stub_calls_; }
+
+ // ---------------------------------------------------------------------------
+  // String utilities
+
+  // Checks if both objects are sequential ASCII strings and jumps to label
+  // if either is not. Assumes that neither object is a smi.
+  void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1,
+                                                  Register object2,
+                                                  Register scratch1,
+                                                  Register scratch2,
+                                                  Label *failure);
+
+  // Checks if both objects are sequential ASCII strings and jumps to label
+  // if either is not.
+  void JumpIfNotBothSequentialAsciiStrings(Register first,
+                                           Register second,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Label* not_flat_ascii_strings);

  private:
   List<Unresolved> unresolved_;
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.cc Mon Jan 18 01:49:50 2010 +++ /branches/bleeding_edge/src/ia32/assembler-ia32.cc Thu Jan 21 04:10:56 2010
@@ -858,6 +858,24 @@
   emit_operand(edi, op);  // edi == 7
   EMIT(imm8);
 }
+
+
+void Assembler::cmpb(const Operand& dst, Register src) {
+  ASSERT(src.is_byte_register());
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x38);
+  emit_operand(src, dst);
+}
+
+
+void Assembler::cmpb(Register dst, const Operand& src) {
+  ASSERT(dst.is_byte_register());
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0x3A);
+  emit_operand(dst, src);
+}


 void Assembler::cmpw(const Operand& op, Immediate imm16) {
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.h Mon Jan 18 01:49:50 2010 +++ /branches/bleeding_edge/src/ia32/assembler-ia32.h Thu Jan 21 04:10:56 2010
@@ -559,6 +559,8 @@
   void and_(const Operand& dst, const Immediate& x);

   void cmpb(const Operand& op, int8_t imm8);
+  void cmpb(Register src, const Operand& dst);
+  void cmpb(const Operand& dst, Register src);
   void cmpb_al(const Operand& op);
   void cmpw_ax(const Operand& op);
   void cmpw(const Operand& op, Immediate imm16);
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Wed Jan 20 08:13:53 2010 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Jan 21 04:10:56 2010
@@ -8575,30 +8575,7 @@

   __ 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 @@
                                                         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);
-  }
-
-  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;
+  __ 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);
+  }
+
+  // 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 @@
   __ j(not_equal, &not_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(&not_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);
=======================================
--- /branches/bleeding_edge/src/ia32/disasm-ia32.cc     Mon Jan 18 01:49:50 2010
+++ /branches/bleeding_edge/src/ia32/disasm-ia32.cc     Thu Jan 21 04:10:56 2010
@@ -53,23 +53,25 @@

 static ByteMnemonic two_operands_instr[] = {
   {0x03, "add", REG_OPER_OP_ORDER},
-  {0x21, "and", OPER_REG_OP_ORDER},
-  {0x23, "and", REG_OPER_OP_ORDER},
-  {0x3B, "cmp", REG_OPER_OP_ORDER},
-  {0x8D, "lea", REG_OPER_OP_ORDER},
   {0x09, "or", OPER_REG_OP_ORDER},
   {0x0B, "or", REG_OPER_OP_ORDER},
   {0x1B, "sbb", REG_OPER_OP_ORDER},
+  {0x21, "and", OPER_REG_OP_ORDER},
+  {0x23, "and", REG_OPER_OP_ORDER},
   {0x29, "sub", OPER_REG_OP_ORDER},
   {0x2A, "subb", REG_OPER_OP_ORDER},
   {0x2B, "sub", REG_OPER_OP_ORDER},
-  {0x84, "test_b", REG_OPER_OP_ORDER},
-  {0x85, "test", REG_OPER_OP_ORDER},
   {0x31, "xor", OPER_REG_OP_ORDER},
   {0x33, "xor", REG_OPER_OP_ORDER},
+  {0x38, "cmpb", OPER_REG_OP_ORDER},
+  {0x3A, "cmpb", REG_OPER_OP_ORDER},
+  {0x3B, "cmp", REG_OPER_OP_ORDER},
+  {0x84, "test_b", REG_OPER_OP_ORDER},
+  {0x85, "test", REG_OPER_OP_ORDER},
   {0x87, "xchg", REG_OPER_OP_ORDER},
   {0x8A, "mov_b", REG_OPER_OP_ORDER},
   {0x8B, "mov", REG_OPER_OP_ORDER},
+  {0x8D, "lea", REG_OPER_OP_ORDER},
   {-1, "", UNSET_OP_ORDER}
 };

=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Jan 19 06:17:34 2010 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Thu Jan 21 04:10:56 2010
@@ -1523,6 +1523,38 @@
   // will not return here
   int3();
 }
+
+
+void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1,
+                                                         Register object2,
+                                                         Register scratch1,
+                                                         Register scratch2,
+                                                         Label* failure) {
+  // Check that both objects are not smis.
+  ASSERT_EQ(0, kSmiTag);
+  mov(scratch1, Operand(object1));
+  and_(scratch1, Operand(object2));
+  test(scratch1, Immediate(kSmiTagMask));
+  j(zero, failure);
+
+  // Load instance type for both strings.
+  mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
+  mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
+  movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
+  movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
+
+  // Check that both are flat ascii strings.
+  const int kFlatAsciiStringMask =
+      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
+  const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+ // Interleave bits from both instance types and compare them in one check.
+  ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
+  and_(scratch1, kFlatAsciiStringMask);
+  and_(scratch2, kFlatAsciiStringMask);
+  lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
+  cmp(scratch1, kFlatAsciiStringTag | (kFlatAsciiStringTag << 3));
+  j(not_equal, failure);
+}


 CodePatcher::CodePatcher(byte* address, int size)
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue Jan 19 06:17:34 2010 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Thu Jan 21 04:10:56 2010
@@ -414,6 +414,17 @@
   bool generating_stub() { return generating_stub_; }
   void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
   bool allow_stub_calls() { return allow_stub_calls_; }
+
+ // ---------------------------------------------------------------------------
+  // String utilities.
+
+ // Checks if both objects are sequential ASCII strings, and jumps to label
+  // if either is not.
+  void JumpIfNotBothSequentialAsciiStrings(Register object1,
+                                           Register object2,
+                                           Register scratch1,
+                                           Register scratch2,
+ Label *on_not_flat_ascii_strings);

  private:
   List<Unresolved> unresolved_;
=======================================
--- /branches/bleeding_edge/src/list.h  Wed Nov 11 01:50:06 2009
+++ /branches/bleeding_edge/src/list.h  Thu Jan 21 04:10:56 2010
@@ -68,7 +68,8 @@
   // not safe to use after operations that can change the list's
   // backing store (eg, Add).
   inline T& operator[](int i) const  {
-    ASSERT(0 <= i && i < length_);
+    ASSERT(0 <= i);
+    ASSERT(i < length_);
     return data_[i];
   }
   inline T& at(int i) const  { return operator[](i); }
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Wed Jan 20 09:01:34 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Thu Jan 21 04:10:56 2010
@@ -8231,7 +8231,6 @@

   // Result is EQUAL.
   __ Move(rax, Smi::FromInt(EQUAL));
-  __ IncrementCounter(&Counters::string_compare_native, 1);
   __ ret(2 * kPointerSize);

   Label result_greater;
@@ -8241,13 +8240,11 @@

   // 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);
 }

@@ -8277,6 +8274,7 @@
   __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime);

   // Inline comparison of ascii strings.
+  __ IncrementCounter(&Counters::string_compare_native, 1);
   GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);

   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Jan 19 04:27:04 2010 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Jan 21 04:10:56 2010
@@ -1311,8 +1311,7 @@
   ASSERT(kNotStringTag != 0);
   const int kFlatAsciiStringMask =
       kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
-  const int kFlatAsciiStringBits =
-      kNotStringTag | kSeqStringTag | kAsciiStringTag;
+  const int kFlatAsciiStringTag = ASCII_STRING_TYPE;

   andl(scratch1, Immediate(kFlatAsciiStringMask));
   andl(scratch2, Immediate(kFlatAsciiStringMask));
@@ -1320,7 +1319,7 @@
   ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
   lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
   cmpl(scratch1,
-       Immediate(kFlatAsciiStringBits + (kFlatAsciiStringBits << 3)));
+       Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
   j(not_equal, on_fail);
 }

=======================================
--- /branches/bleeding_edge/test/cctest/test-disasm-ia32.cc Mon Jan 11 07:19:53 2010 +++ /branches/bleeding_edge/test/cctest/test-disasm-ia32.cc Thu Jan 21 04:10:56 2010
@@ -101,6 +101,8 @@
   __ cmp(Operand(ebp, ecx, times_4, 0), Immediate(1000));
   Handle<FixedArray> foo2 = Factory::NewFixedArray(10, TENURED);
   __ cmp(ebx, foo2);
+  __ cmpb(ebx, Operand(ebp, ecx, times_2, 0));
+  __ cmpb(Operand(ebp, ecx, times_2, 0), ebx);
   __ or_(edx, 3);
   __ xor_(edx, 3);
   __ nop();
-- 
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to