Chromium Code Reviews| Index: src/arm/lithium-codegen-arm.cc |
| diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc |
| index 54ad4581c5ce632e7c74d7f193e5a627fcdff88f..351e9d982a196e2df7038012ab8be053da3c738d 100644 |
| --- a/src/arm/lithium-codegen-arm.cc |
| +++ b/src/arm/lithium-codegen-arm.cc |
| @@ -3421,97 +3421,83 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| LStringCharCodeAt* instr_; |
| }; |
| - Register scratch = scratch0(); |
| Register string = ToRegister(instr->string()); |
| - Register index = no_reg; |
| - int const_index = -1; |
| - if (instr->index()->IsConstantOperand()) { |
| - const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| - STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| - if (!Smi::IsValid(const_index)) { |
| - // Guaranteed to be out of bounds because of the assert above. |
| - // So the bounds check that must dominate this instruction must |
| - // have deoptimized already. |
| - if (FLAG_debug_code) { |
| - __ Abort("StringCharCodeAt: out of bounds index."); |
| - } |
| - // No code needs to be generated. |
| - return; |
| - } |
| - } else { |
| - index = ToRegister(instr->index()); |
| - } |
| + Register index = ToRegister(instr->index()); |
| Register result = ToRegister(instr->result()); |
| DeferredStringCharCodeAt* deferred = |
| new DeferredStringCharCodeAt(this, instr); |
| - Label flat_string, ascii_string, done; |
| - |
| // Fetch the instance type of the receiver into result register. |
| __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
| __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| - // We need special handling for non-flat strings. |
| - STATIC_ASSERT(kSeqStringTag == 0); |
| - __ tst(result, Operand(kStringRepresentationMask)); |
| - __ b(eq, &flat_string); |
| - |
| - // Handle non-flat strings. |
| - __ tst(result, Operand(kIsConsStringMask)); |
| - __ b(eq, deferred->entry()); |
| - |
| - // ConsString. |
| + // We need special handling for indirect strings. |
| + Label check_sequential; |
| + __ tst(result, Operand(kIsIndirectStringMask)); |
| + __ b(eq, &check_sequential); |
| + |
| + // 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); |
| + |
| + // Handle slices. |
| + Label indirect_string_loaded; |
| + __ ldr(result, FieldMemOperand(string, SlicedString::kOffsetOffset)); |
| + __ add(index, index, Operand(result, ASR, kSmiTagSize)); |
| + __ ldr(string, FieldMemOperand(string, SlicedString::kParentOffset)); |
| + __ jmp(&indirect_string_loaded); |
| + |
| + // Handle conses. |
| // Check whether the right hand side is the empty string (i.e. if |
| // this is really a flat string in a cons string). If that is not |
| // the case we would rather go to the runtime system now to flatten |
| // the string. |
| - __ ldr(scratch, FieldMemOperand(string, ConsString::kSecondOffset)); |
| + __ bind(&cons_string); |
| + __ ldr(result, FieldMemOperand(string, ConsString::kSecondOffset)); |
| __ LoadRoot(ip, Heap::kEmptyStringRootIndex); |
| - __ cmp(scratch, ip); |
| + __ cmp(result, ip); |
| __ b(ne, deferred->entry()); |
| // Get the first of the two strings and load its instance type. |
| __ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset)); |
| + |
| + __ bind(&indirect_string_loaded); |
| __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
| __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| - // If the first cons component is also non-flat, then go to runtime. |
| + |
| + // Check whether the string is sequential. The only non-sequential |
| + // shapes we support have just been unwrapped above. |
|
antonm
2011/08/25 12:04:36
again, it might be a good idea to check it in debu
Yang
2011/08/25 13:40:03
Correct. Empty second component can only be in fla
|
| + __ bind(&check_sequential); |
| STATIC_ASSERT(kSeqStringTag == 0); |
| __ tst(result, Operand(kStringRepresentationMask)); |
| __ b(ne, deferred->entry()); |
| - // Check for 1-byte or 2-byte string. |
| - __ bind(&flat_string); |
| + // Dispatch on the encoding: ASCII or two-byte. |
| + Label ascii_string; |
| STATIC_ASSERT(kAsciiStringTag != 0); |
| __ tst(result, Operand(kStringEncodingMask)); |
| __ b(ne, &ascii_string); |
| - // 2-byte string. |
| - // Load the 2-byte character code into the result register. |
| - STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| - if (instr->index()->IsConstantOperand()) { |
| - __ ldrh(result, |
| - FieldMemOperand(string, |
| - SeqTwoByteString::kHeaderSize + 2 * const_index)); |
| - } else { |
| - __ add(scratch, |
| - string, |
| - Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| - __ ldrh(result, MemOperand(scratch, index, LSL, 1)); |
| - } |
| + // Two-byte string. |
| + // Load the two-byte character code into the result register. |
| + Label done; |
| + __ add(result, |
| + string, |
| + Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| + __ ldrh(result, MemOperand(result, index, LSL, 1)); |
| __ jmp(&done); |
| // ASCII string. |
| // Load the byte into the result register. |
| __ bind(&ascii_string); |
| - if (instr->index()->IsConstantOperand()) { |
| - __ ldrb(result, FieldMemOperand(string, |
|
antonm
2011/08/25 12:04:36
why const operand optimization is gone away?
Yes,
Yang
2011/08/25 13:40:03
I discussed this with Vitaly and also benchmarked
|
| - SeqAsciiString::kHeaderSize + const_index)); |
| - } else { |
| - __ add(scratch, |
| - string, |
| - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| - __ ldrb(result, MemOperand(scratch, index)); |
| - } |
| + __ add(result, |
| + string, |
| + Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| + __ ldrb(result, MemOperand(result, index)); |
| + |
| __ bind(&done); |
| __ bind(deferred->exit()); |
| } |