Chromium Code Reviews| 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); |