 Chromium Code Reviews
 Chromium Code Reviews Issue 8889012:
  Avoid bailing out to runtime for short substrings.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 8889012:
  Avoid bailing out to runtime for short substrings.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| Index: src/ia32/code-stubs-ia32.cc | 
| diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc | 
| index fa706fbf501fee19aa0b95919577d76c65770fc0..445877ad84ff57aed6a739b1a4469869731b655d 100644 | 
| --- a/src/ia32/code-stubs-ia32.cc | 
| +++ b/src/ia32/code-stubs-ia32.cc | 
| @@ -6129,54 +6129,59 @@ void SubStringStub::Generate(MacroAssembler* masm) { | 
| __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 
| __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 
| __ Set(ecx, Immediate(2)); | 
| + __ mov(edx, Operand(esp, 2 * kPointerSize)); // Load index. | 
| + | 
| + __ bind(&result_longer_than_two); | 
| + // eax: string | 
| + // ebx: instance type | 
| + // ecx: sub string length | 
| + // edx: from index (smi) | 
| + // Deal with different string types: update the index if necessary | 
| + // and put the underlying string into edi. | 
| + Label underlying_unpacked, sliced_string, seq_or_external_string; | 
| + // If the string is not indirect, it can only be sequential or external. | 
| + STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | 
| + STATIC_ASSERT(kIsIndirectStringMask != 0); | 
| + __ test(ebx, Immediate(kIsIndirectStringMask)); | 
| + __ j(zero, &seq_or_external_string, Label::kNear); | 
| + | 
| + 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. | 
| 
rossberg
2011/12/08 15:36:32
Nit: Maybe add comment about the flat cons invaria
 | 
| + __ cmp(FieldOperand(eax, ConsString::kSecondOffset), | 
| + factory->empty_string()); | 
| + __ j(not_equal, &runtime); | 
| + __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset)); | 
| + // Update instance type. | 
| + __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); | 
| + __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 
| + __ jmp(&underlying_unpacked, Label::kNear); | 
| + | 
| + __ bind(&sliced_string); | 
| + // Sliced string. Fetch parent and adjust start index by offset. | 
| + __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset)); | 
| + __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset)); | 
| + // Update instance type. | 
| + __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); | 
| + __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 
| + __ jmp(&underlying_unpacked, Label::kNear); | 
| + | 
| + __ bind(&seq_or_external_string); | 
| + // Sequential or external string. Just move string to the correct register. | 
| + __ mov(edi, eax); | 
| + | 
| + __ bind(&underlying_unpacked); | 
| if (FLAG_string_slices) { | 
| Label copy_routine; | 
| - // If coming from the make_two_character_string path, the string | 
| - // is too short to be sliced anyways. | 
| - STATIC_ASSERT(2 < SlicedString::kMinLength); | 
| - __ jmp(©_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_or_external_string; | 
| - __ cmp(ecx, SlicedString::kMinLength); | 
| - // Short slice. Copy instead of slicing. | 
| - __ j(less, ©_routine); | 
| - // If the string is not indirect, it can only be sequential or external. | 
| - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | 
| - STATIC_ASSERT(kIsIndirectStringMask != 0); | 
| - __ test(ebx, Immediate(kIsIndirectStringMask)); | 
| - __ j(zero, &seq_or_external_string, Label::kNear); | 
| - | 
| - 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_or_external_string); | 
| - // Sequential or external string. Just move string to the correct register. | 
| - __ mov(edi, eax); | 
| - | 
| - __ bind(&allocate_slice); | 
| // edi: underlying subject string | 
| // ebx: instance type of original subject string | 
| - // edx: offset | 
| + // edx: adjusted start index (smi) | 
| // ecx: length | 
| + __ cmp(ecx, SlicedString::kMinLength); | 
| + // Short slice. Copy instead of slicing. | 
| + __ j(less, ©_routine); | 
| // 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 | 
| @@ -6201,19 +6206,41 @@ void SubStringStub::Generate(MacroAssembler* masm) { | 
| __ jmp(&return_eax); | 
| __ bind(©_routine); | 
| - } else { | 
| - __ bind(&result_longer_than_two); | 
| } | 
| - // eax: string | 
| - // ebx: instance type | 
| - // ecx: result string length | 
| - // Check for flat ascii string | 
| - Label non_ascii_flat; | 
| - __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat); | 
| + // edi: underlying subject string | 
| + // ebx: instance type of original subject string | 
| + // edx: adjusted start index (smi) | 
| + // ecx: length | 
| + // The subject string can only be external or sequential string of either | 
| + // encoding at this point. | 
| + Label two_byte_sequential, runtime_drop_two, sequential_string; | 
| + STATIC_ASSERT(kExternalStringTag != 0); | 
| + STATIC_ASSERT(kSeqStringTag == 0); | 
| + __ test_b(ebx, kExternalStringTag); | 
| + __ j(zero, &sequential_string); | 
| + | 
| + // Handle external string. | 
| + Label ascii_external, done; | 
| + // Rule out short external strings. | 
| + STATIC_CHECK(kShortExternalStringTag != 0); | 
| + __ test_b(ebx, kShortExternalStringMask); | 
| + __ j(not_zero, &runtime); | 
| + __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset)); | 
| + // Move the pointer so that offset-wise, it looks like a sequential string. | 
| + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); | 
| + __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 
| + | 
| + __ bind(&sequential_string); | 
| + // Stash away (adjusted) index and (underlying) string. | 
| + __ push(edx); | 
| + __ push(edi); | 
| + STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); | 
| + __ test_b(ebx, kStringEncodingMask); | 
| + __ j(zero, &two_byte_sequential); | 
| - // Allocate the result. | 
| - __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime); | 
| + // Sequential ascii string. Allocate the result. | 
| + __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two); | 
| // eax: result string | 
| // ecx: result string length | 
| @@ -6222,11 +6249,10 @@ void SubStringStub::Generate(MacroAssembler* masm) { | 
| __ mov(edi, eax); | 
| __ add(edi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
| // Load string argument and locate character of sub string start. | 
| - __ mov(esi, Operand(esp, 3 * kPointerSize)); | 
| - __ add(esi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
| - __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from | 
| + __ pop(esi); | 
| + __ pop(ebx); | 
| __ SmiUntag(ebx); | 
| - __ add(esi, ebx); | 
| + __ lea(esi, FieldOperand(esi, ebx, times_1, SeqAsciiString::kHeaderSize)); | 
| // eax: result string | 
| // ecx: result length | 
| @@ -6239,16 +6265,9 @@ void SubStringStub::Generate(MacroAssembler* masm) { | 
| __ IncrementCounter(counters->sub_string_native(), 1); | 
| __ ret(3 * kPointerSize); | 
| - __ bind(&non_ascii_flat); | 
| - // eax: string | 
| - // ebx: instance type & kStringRepresentationMask | kStringEncodingMask | 
| - // ecx: result string length | 
| - // Check for flat two byte string | 
| - __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); | 
| - __ j(not_equal, &runtime); | 
| - | 
| - // Allocate the result. | 
| - __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime); | 
| + __ bind(&two_byte_sequential); | 
| + // Sequential two-byte string. Allocate the result. | 
| + __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two); | 
| // eax: result string | 
| // ecx: result string length | 
| @@ -6258,14 +6277,13 @@ void SubStringStub::Generate(MacroAssembler* masm) { | 
| __ add(edi, | 
| Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 
| // Load string argument and locate character of sub string start. | 
| - __ mov(esi, Operand(esp, 3 * kPointerSize)); | 
| - __ add(esi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 
| - __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from | 
| + __ pop(esi); | 
| + __ pop(ebx); | 
| // As from is a smi it is 2 times the value which matches the size of a two | 
| // byte character. | 
| STATIC_ASSERT(kSmiTag == 0); | 
| STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 
| - __ add(esi, ebx); | 
| + __ lea(esi, FieldOperand(esi, ebx, times_1, SeqTwoByteString::kHeaderSize)); | 
| // eax: result string | 
| // ecx: result length | 
| @@ -6279,6 +6297,10 @@ void SubStringStub::Generate(MacroAssembler* masm) { | 
| __ IncrementCounter(counters->sub_string_native(), 1); | 
| __ ret(3 * kPointerSize); | 
| + // Drop pushed values on the stack before tail call. | 
| + __ bind(&runtime_drop_two); | 
| + __ Drop(2); | 
| + | 
| // Just jump to runtime to create the sub string. | 
| __ bind(&runtime); | 
| __ TailCallRuntime(Runtime::kSubString, 3, 1); |