Revision: 9064
Author:   [email protected]
Date:     Tue Aug 30 01:22:41 2011
Log:      Generated code for substring slices in ia32.

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

Modified:
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/test/mjsunit/string-slices.js

=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Aug 29 06:02:35 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Aug 30 01:22:41 2011
@@ -3473,8 +3473,6 @@

   // Dispatch on the indirect string shape: slice or cons.
   Label cons_string;
-  const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
-  ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
   __ tst(result, Operand(kSlicedNotConsMask));
   __ b(eq, &cons_string);

=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Aug 29 04:41:23 2011 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Aug 30 01:22:41 2011
@@ -5642,9 +5642,6 @@
 void SubStringStub::Generate(MacroAssembler* masm) {
   Label runtime;

-  if (FLAG_string_slices) {
-    __ jmp(&runtime);
-  }
   // Stack frame on entry.
   //  esp[0]: return address
   //  esp[4]: to
@@ -5706,7 +5703,83 @@
   __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
   __ Set(ecx, Immediate(2));

-  __ bind(&result_longer_than_two);
+  if (FLAG_string_slices) {
+    Label copy_rountine;
+    // If coming from the make_two_character_string path, the string
+    // is too short to be sliced anyways.
+    STATIC_ASSERT(2 < SlicedString::kMinLength);
+    __ jmp(&copy_routine);
+    __ bind(&result_longer_than_two);
+
+    // eax: string
+    // ebx: instance type
+    // ecx: sub string length
+    // edx: from index (smi)
+   Label allocate_slice, sliced_string, seq_string;
+    __ cmp(ecx, SlicedString::kMinLength);
+    // Short slice.  Copy instead of slicing.
+    __ j(less, &copy_routine);
+    STATIC_ASSERT(kSeqStringTag == 0);
+    __ test(ebx, Immediate(kStringRepresentationMask));
+    __ j(zero, &seq_string, Label::kNear);
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+    STATIC_ASSERT(kIsIndirectStringMask != 0);
+    __ test(ebx, Immediate(kIsIndirectStringMask));
+    // External string.  Jump to runtime.
+    __ j(zero, &runtime);
+
+    Factory* factory = masm->isolate()->factory();
+    __ test(ebx, Immediate(kSlicedNotConsMask));
+    __ j(not_zero, &sliced_string, Label::kNear);
+    // Cons string.  Check whether it is flat, then fetch first part.
+    __ cmp(FieldOperand(eax, ConsString::kSecondOffset),
+           factory->empty_string());
+    __ j(not_equal, &runtime);
+    __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
+    __ jmp(&allocate_slice, Label::kNear);
+
+    __ bind(&sliced_string);
+    // Sliced string.  Fetch parent and correct start index by offset.
+    __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
+    __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
+    __ jmp(&allocate_slice, Label::kNear);
+
+    __ bind(&seq_string);
+    // Sequential string.  Just move string to the right register.
+    __ mov(edi, eax);
+
+    __ bind(&allocate_slice);
+    // edi: underlying subject string
+    // ebx: instance type of original subject string
+    // edx: offset
+    // ecx: length
+ // Allocate new sliced string. At this point we do not reload the instance + // type including the string encoding because we simply rely on the info
+    // provided by the original string.  It does not matter if the original
+ // string's encoding is wrong because we always have to recheck encoding of + // the newly created string's parent anyways due to externalized strings.
+    Label two_byte_slice, set_slice_header;
+    STATIC_ASSERT(kAsciiStringTag != 0);
+    __ test(ebx, Immediate(kAsciiStringTag));
+    __ j(zero, &two_byte_slice, Label::kNear);
+    __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime);
+    __ jmp(&set_slice_header, Label::kNear);
+    __ bind(&two_byte_slice);
+    __ AllocateSlicedString(eax, ebx, no_reg, &runtime);
+    __ bind(&set_slice_header);
+    __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
+    __ SmiTag(ecx);
+    __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
+    __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
+    __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
+           Immediate(String::kEmptyHashField));
+    __ jmp(&return_eax);
+
+    __ bind(&copy_routine);
+  } else {
+    __ bind(&result_longer_than_two);
+  }
+
   // eax: string
   // ebx: instance type
   // ecx: result string length
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Aug 26 06:03:30 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Aug 30 01:22:41 2011
@@ -3234,8 +3234,6 @@

   // Dispatch on the indirect string shape: slice or cons.
   Label cons_string;
-  const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
-  ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
   __ test(result, Immediate(kSlicedNotConsMask));
   __ j(zero, &cons_string, Label::kNear);

=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Mon Aug 29 06:02:35 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Aug 30 01:22:41 2011
@@ -1206,6 +1206,42 @@
   mov(FieldOperand(result, HeapObject::kMapOffset),
       Immediate(isolate()->factory()->cons_ascii_string_map()));
 }
+
+
+void MacroAssembler::AllocateSlicedString(Register result,
+                                          Register scratch1,
+                                          Register scratch2,
+                                          Label* gc_required) {
+  // Allocate heap number in new space.
+  AllocateInNewSpace(SlicedString::kSize,
+                     result,
+                     scratch1,
+                     scratch2,
+                     gc_required,
+                     TAG_OBJECT);
+
+  // Set the map. The other fields are left uninitialized.
+  mov(FieldOperand(result, HeapObject::kMapOffset),
+      Immediate(isolate()->factory()->sliced_string_map()));
+}
+
+
+void MacroAssembler::AllocateAsciiSlicedString(Register result,
+                                               Register scratch1,
+                                               Register scratch2,
+                                               Label* gc_required) {
+  // Allocate heap number in new space.
+  AllocateInNewSpace(SlicedString::kSize,
+                     result,
+                     scratch1,
+                     scratch2,
+                     gc_required,
+                     TAG_OBJECT);
+
+  // Set the map. The other fields are left uninitialized.
+  mov(FieldOperand(result, HeapObject::kMapOffset),
+      Immediate(isolate()->factory()->sliced_ascii_string_map()));
+}


// Copy memory, byte-by-byte, from source to destination. Not optimized for
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Mon Aug 29 06:02:35 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue Aug 30 01:22:41 2011
@@ -446,6 +446,17 @@
                                Register scratch2,
                                Label* gc_required);

+ // Allocate a raw sliced string object. Only the map field of the result is
+  // initialized.
+  void AllocateSlicedString(Register result,
+                            Register scratch1,
+                            Register scratch2,
+                            Label* gc_required);
+  void AllocateAsciiSlicedString(Register result,
+                                 Register scratch1,
+                                 Register scratch2,
+                                 Label* gc_required);
+
// Copy memory, byte-by-byte, from source to destination. Not optimized for
   // long or aligned copies.
   // The contents of index and scratch are destroyed.
=======================================
--- /branches/bleeding_edge/src/objects.h       Fri Aug 26 06:03:30 2011
+++ /branches/bleeding_edge/src/objects.h       Tue Aug 30 01:22:41 2011
@@ -496,6 +496,11 @@
 STATIC_ASSERT(
     (kSlicedStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);

+// Use this mask to distinguish between cons and slice only after making
+// sure that the string is one of the two (an indirect string).
+const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
+STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
+
 // If bit 7 is clear, then bit 3 indicates whether this two-byte
 // string actually contains ascii data.
 const uint32_t kAsciiDataHintMask = 0x08;
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Aug 26 06:03:30 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Aug 30 01:22:41 2011
@@ -3217,8 +3217,6 @@

   // Dispatch on the indirect string shape: slice or cons.
   Label cons_string;
-  const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
-  ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
   __ testb(result, Immediate(kSlicedNotConsMask));
   __ j(zero, &cons_string, Label::kNear);

=======================================
--- /branches/bleeding_edge/test/mjsunit/string-slices.js Fri Aug 26 06:03:30 2011 +++ /branches/bleeding_edge/test/mjsunit/string-slices.js Tue Aug 30 01:22:41 2011
@@ -72,7 +72,7 @@
 }
 /x/.exec(x);  // Try to force a flatten.
 for (var i = 5; i < 25; i++) {
-  for (var j = 12; j < 25; j++) {
+  for (var j = 0; j < 25; j++) {
     var z = x.substring(i, i+j);
     var w = Math.random() * 42;  // Allocate something new in new-space.
     assertEquals(j, z.length);
@@ -110,7 +110,7 @@
 x += x;
 var xl = x.length;
 var cache = [];
-for (var i = 0; i < 10000; i++) {
+for (var i = 0; i < 1000; i++) {
   var z = x.substring(i % xl);
   assertEquals(xl - (i % xl), z.length);
   cache.push(z);
@@ -129,7 +129,7 @@
 x += x;
 var xl = x.length;
 var cache = [];
-for (var i = 0; i < 10000; i++) {
+for (var i = 0; i < 1000; i++) {
   var z = x.substring(i % xl);
   assertEquals(xl - (i % xl), z.length);
   cache.push(z);
@@ -149,6 +149,7 @@
   var z = cache.pop();
   assertTrue(/\u2028123456789ABCDEF/.test(z));
   assertEquals(xl - offset, z.length);
+  assertEquals(x.charAt(i*(i+1)/2), z.charAt(0));
   offset -= i;
 }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to