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. |
+ __ 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, |
- 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()); |
} |