Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 4542) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -3950,9 +3950,12 @@ |
} |
-// This should generate code that performs a charCodeAt() call or returns |
+// This generates code that performs a charCodeAt() call or returns |
// undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
-// It is not yet implemented on ARM, so it always goes to the slow case. |
+// It can handle flat, 8 and 16 bit characters and cons strings where the |
+// answer is found in the left hand branch of the cons. The slow case will |
+// flatten the string, which will ensure that the answer is in the left hand |
+// side the next time around. |
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
VirtualFrame::SpilledScope spilled_scope(frame_); |
ASSERT(args->length() == 2); |
@@ -3960,75 +3963,28 @@ |
LoadAndSpill(args->at(0)); |
LoadAndSpill(args->at(1)); |
- frame_->EmitPop(r0); // Index. |
- frame_->EmitPop(r1); // String. |
+ frame_->EmitPop(r1); // Index. |
+ frame_->EmitPop(r2); // String. |
- Label slow, end, not_a_flat_string, ascii_string, try_again_with_new_string; |
+ Label slow_case; |
+ Label exit; |
+ StringHelper::GenerateFastCharCodeAt(masm_, |
+ r2, |
+ r1, |
+ r3, |
+ r0, |
+ &slow_case, |
+ &slow_case, |
+ &slow_case, |
+ &slow_case); |
+ __ jmp(&exit); |
- __ tst(r1, Operand(kSmiTagMask)); |
- __ b(eq, &slow); // The 'string' was a Smi. |
- |
- ASSERT(kSmiTag == 0); |
- __ tst(r0, Operand(kSmiTagMask | 0x80000000u)); |
- __ b(ne, &slow); // The index was negative or not a Smi. |
- |
- __ bind(&try_again_with_new_string); |
- __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE); |
- __ b(ge, &slow); |
- |
- // Now r2 has the string type. |
- __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset)); |
- // Now r3 has the length of the string. Compare with the index. |
- __ cmp(r3, Operand(r0, LSR, kSmiTagSize)); |
- __ b(le, &slow); |
- |
- // Here we know the index is in range. Check that string is sequential. |
- ASSERT_EQ(0, kSeqStringTag); |
- __ tst(r2, Operand(kStringRepresentationMask)); |
- __ b(ne, ¬_a_flat_string); |
- |
- // Check whether it is an ASCII string. |
- ASSERT_EQ(0, kTwoByteStringTag); |
- __ tst(r2, Operand(kStringEncodingMask)); |
- __ b(ne, &ascii_string); |
- |
- // 2-byte string. We can add without shifting since the Smi tag size is the |
- // log2 of the number of bytes in a two-byte character. |
- ASSERT_EQ(1, kSmiTagSize); |
- ASSERT_EQ(0, kSmiShiftSize); |
- __ add(r1, r1, Operand(r0)); |
- __ ldrh(r0, FieldMemOperand(r1, SeqTwoByteString::kHeaderSize)); |
- __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
- __ jmp(&end); |
- |
- __ bind(&ascii_string); |
- __ add(r1, r1, Operand(r0, LSR, kSmiTagSize)); |
- __ ldrb(r0, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); |
- __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
- __ jmp(&end); |
- |
- __ bind(¬_a_flat_string); |
- __ and_(r2, r2, Operand(kStringRepresentationMask)); |
- __ cmp(r2, Operand(kConsStringTag)); |
- __ b(ne, &slow); |
- |
- // ConsString. |
- // Check that the right hand side is the empty string (ie 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(r2, FieldMemOperand(r1, ConsString::kSecondOffset)); |
- __ LoadRoot(r3, Heap::kEmptyStringRootIndex); |
- __ cmp(r2, Operand(r3)); |
- __ b(ne, &slow); |
- |
- // Get the first of the two strings. |
- __ ldr(r1, FieldMemOperand(r1, ConsString::kFirstOffset)); |
- __ jmp(&try_again_with_new_string); |
- |
- __ bind(&slow); |
+ __ bind(&slow_case); |
+ // Move the undefined value into the result register, which will |
+ // trigger the slow case. |
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
- __ bind(&end); |
+ __ bind(&exit); |
frame_->EmitPush(r0); |
} |
@@ -4037,37 +3993,19 @@ |
Comment(masm_, "[ GenerateCharFromCode"); |
ASSERT(args->length() == 1); |
+ Register code = r1; |
+ Register scratch = ip; |
+ Register result = r0; |
+ |
LoadAndSpill(args->at(0)); |
- frame_->EmitPop(r0); |
+ frame_->EmitPop(code); |
- JumpTarget slow_case; |
- JumpTarget exit; |
- |
- // Fast case of Heap::LookupSingleCharacterStringFromCode. |
- ASSERT(kSmiTag == 0); |
- ASSERT(kSmiShiftSize == 0); |
- ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
- __ tst(r0, Operand(kSmiTagMask | |
- ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
- slow_case.Branch(nz); |
- |
- ASSERT(kSmiTag == 0); |
- __ mov(r1, Operand(Factory::single_character_string_cache())); |
- __ add(r1, r1, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
- __ ldr(r1, MemOperand(r1, FixedArray::kHeaderSize - kHeapObjectTag)); |
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
- __ cmp(r1, ip); |
- slow_case.Branch(eq); |
- |
- frame_->EmitPush(r1); |
- exit.Jump(); |
- |
- slow_case.Bind(); |
- frame_->EmitPush(r0); |
- frame_->CallRuntime(Runtime::kCharFromCode, 1); |
- frame_->EmitPush(r0); |
- |
- exit.Bind(); |
+ StringHelper::GenerateCharFromCode(masm_, |
+ code, |
+ scratch, |
+ result, |
+ CALL_FUNCTION); |
+ frame_->EmitPush(result); |
} |
@@ -8750,12 +8688,151 @@ |
} |
-void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, |
- Register dest, |
- Register src, |
- Register count, |
- Register scratch, |
- bool ascii) { |
+void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, |
+ Register object, |
+ Register index, |
+ Register scratch, |
+ Register result, |
+ Label* receiver_not_string, |
+ Label* index_not_smi, |
+ Label* index_out_of_range, |
+ Label* slow_case) { |
+ Label not_a_flat_string; |
+ Label try_again_with_new_string; |
+ Label ascii_string; |
+ Label got_char_code; |
+ |
+ // If the receiver is a smi trigger the non-string case. |
+ __ BranchOnSmi(object, receiver_not_string); |
+ |
+ // Fetch the instance type of the receiver into result register. |
+ __ ldr(result, FieldMemOperand(object, HeapObject::kMapOffset)); |
+ __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
+ // If the receiver is not a string trigger the non-string case. |
+ __ tst(result, Operand(kIsNotStringMask)); |
+ __ b(ne, receiver_not_string); |
+ |
+ // If the index is non-smi trigger the non-smi case. |
+ __ BranchOnNotSmi(index, index_not_smi); |
+ |
+ // Check for index out of range. |
+ __ ldr(scratch, FieldMemOperand(object, String::kLengthOffset)); |
+ // Now scratch has the length of the string. Compare with the index. |
+ __ cmp(scratch, Operand(index, LSR, kSmiTagSize)); |
+ __ b(ls, index_out_of_range); |
+ |
+ __ bind(&try_again_with_new_string); |
+ // ----------- S t a t e ------------- |
+ // -- object : string to access |
+ // -- result : instance type of the string |
+ // -- scratch : non-negative index < length |
+ // ----------------------------------- |
+ |
+ // We need special handling for non-flat strings. |
+ ASSERT_EQ(0, kSeqStringTag); |
+ __ tst(result, Operand(kStringRepresentationMask)); |
+ __ b(ne, ¬_a_flat_string); |
+ |
+ // Check for 1-byte or 2-byte string. |
+ ASSERT_EQ(0, kTwoByteStringTag); |
+ __ tst(result, Operand(kStringEncodingMask)); |
+ __ b(ne, &ascii_string); |
+ |
+ // 2-byte string. We can add without shifting since the Smi tag size is the |
+ // log2 of the number of bytes in a two-byte character. |
+ ASSERT_EQ(1, kSmiTagSize); |
+ ASSERT_EQ(0, kSmiShiftSize); |
+ __ add(scratch, object, Operand(index)); |
+ __ ldrh(result, FieldMemOperand(scratch, SeqTwoByteString::kHeaderSize)); |
+ __ jmp(&got_char_code); |
+ |
+ // Handle non-flat strings. |
+ __ bind(¬_a_flat_string); |
+ __ and_(result, result, Operand(kStringRepresentationMask)); |
+ __ cmp(result, Operand(kConsStringTag)); |
+ __ b(ne, slow_case); |
+ |
+ // ConsString. |
+ // 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(result, FieldMemOperand(object, ConsString::kSecondOffset)); |
+ __ LoadRoot(scratch, Heap::kEmptyStringRootIndex); |
+ __ cmp(result, Operand(scratch)); |
+ __ b(ne, slow_case); |
+ |
+ // Get the first of the two strings and load its instance type. |
+ __ ldr(object, FieldMemOperand(object, ConsString::kFirstOffset)); |
+ __ ldr(result, FieldMemOperand(object, HeapObject::kMapOffset)); |
+ __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
+ __ jmp(&try_again_with_new_string); |
+ |
+ // ASCII string. |
+ __ bind(&ascii_string); |
+ __ add(scratch, object, Operand(index, LSR, kSmiTagSize)); |
+ __ ldrb(result, FieldMemOperand(scratch, SeqAsciiString::kHeaderSize)); |
+ |
+ __ bind(&got_char_code); |
+ __ mov(result, Operand(result, LSL, kSmiTagSize)); |
+} |
+ |
+ |
+void StringHelper::GenerateCharFromCode(MacroAssembler* masm, |
+ Register code, |
+ Register scratch, |
+ Register result, |
+ InvokeFlag flag) { |
+ ASSERT(!code.is(result)); |
+ |
+ Label slow_case; |
+ Label exit; |
+ |
+ // Fast case of Heap::LookupSingleCharacterStringFromCode. |
+ ASSERT(kSmiTag == 0); |
+ ASSERT(kSmiShiftSize == 0); |
+ ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
+ __ tst(code, Operand(kSmiTagMask | |
+ ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
+ __ b(nz, &slow_case); |
+ |
+ ASSERT(kSmiTag == 0); |
+ __ mov(result, Operand(Factory::single_character_string_cache())); |
+ __ add(result, result, Operand(code, LSL, kPointerSizeLog2 - kSmiTagSize)); |
+ __ ldr(result, MemOperand(result, FixedArray::kHeaderSize - kHeapObjectTag)); |
+ __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); |
+ __ cmp(result, scratch); |
+ __ b(eq, &slow_case); |
+ __ b(&exit); |
+ |
+ __ bind(&slow_case); |
+ if (flag == CALL_FUNCTION) { |
+ __ push(code); |
+ __ CallRuntime(Runtime::kCharFromCode, 1); |
+ if (!result.is(r0)) { |
+ __ mov(result, r0); |
+ } |
+ } else { |
+ ASSERT(flag == JUMP_FUNCTION); |
+ ASSERT(result.is(r0)); |
+ __ push(code); |
+ __ TailCallRuntime(Runtime::kCharFromCode, 1, 1); |
+ } |
+ |
+ __ bind(&exit); |
+ if (flag == JUMP_FUNCTION) { |
+ ASSERT(result.is(r0)); |
+ __ Ret(); |
+ } |
+} |
+ |
+ |
+void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
+ Register dest, |
+ Register src, |
+ Register count, |
+ Register scratch, |
+ bool ascii) { |
Label loop; |
Label done; |
// This loop just copies one character at a time, as it is only used for very |
@@ -8786,16 +8863,16 @@ |
}; |
-void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm, |
- Register dest, |
- Register src, |
- Register count, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Register scratch4, |
- Register scratch5, |
- int flags) { |
+void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, |
+ Register dest, |
+ Register src, |
+ Register count, |
+ Register scratch1, |
+ Register scratch2, |
+ Register scratch3, |
+ Register scratch4, |
+ Register scratch5, |
+ int flags) { |
bool ascii = (flags & COPY_ASCII) != 0; |
bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0; |
@@ -8929,15 +9006,15 @@ |
} |
-void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
- Register c1, |
- Register c2, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Register scratch4, |
- Register scratch5, |
- Label* not_found) { |
+void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
+ Register c1, |
+ Register c2, |
+ Register scratch1, |
+ Register scratch2, |
+ Register scratch3, |
+ Register scratch4, |
+ Register scratch5, |
+ Label* not_found) { |
// Register scratch3 is the general scratch register in this function. |
Register scratch = scratch3; |
@@ -8959,9 +9036,9 @@ |
__ bind(¬_array_index); |
// Calculate the two character string hash. |
Register hash = scratch1; |
- GenerateHashInit(masm, hash, c1); |
- GenerateHashAddCharacter(masm, hash, c2); |
- GenerateHashGetHash(masm, hash); |
+ StringHelper::GenerateHashInit(masm, hash, c1); |
+ StringHelper::GenerateHashAddCharacter(masm, hash, c2); |
+ StringHelper::GenerateHashGetHash(masm, hash); |
// Collect the two characters in a register. |
Register chars = c1; |
@@ -9055,9 +9132,9 @@ |
} |
-void StringStubBase::GenerateHashInit(MacroAssembler* masm, |
- Register hash, |
- Register character) { |
+void StringHelper::GenerateHashInit(MacroAssembler* masm, |
+ Register hash, |
+ Register character) { |
// hash = character + (character << 10); |
__ add(hash, character, Operand(character, LSL, 10)); |
// hash ^= hash >> 6; |
@@ -9065,9 +9142,9 @@ |
} |
-void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, |
- Register hash, |
- Register character) { |
+void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, |
+ Register hash, |
+ Register character) { |
// hash += character; |
__ add(hash, hash, Operand(character)); |
// hash += hash << 10; |
@@ -9077,8 +9154,8 @@ |
} |
-void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, |
- Register hash) { |
+void StringHelper::GenerateHashGetHash(MacroAssembler* masm, |
+ Register hash) { |
// hash += hash << 3; |
__ add(hash, hash, Operand(hash, LSL, 3)); |
// hash ^= hash >> 11; |
@@ -9205,8 +9282,8 @@ |
// Try to lookup two character string in symbol table. |
Label make_two_character_string; |
- GenerateTwoCharacterSymbolTableProbe(masm, r3, r4, r1, r5, r6, r7, r9, |
- &make_two_character_string); |
+ StringHelper::GenerateTwoCharacterSymbolTableProbe( |
+ masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string); |
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
__ add(sp, sp, Operand(3 * kPointerSize)); |
__ Ret(); |
@@ -9240,8 +9317,8 @@ |
// r2: result string length. |
// r5: first character of sub string to copy. |
ASSERT_EQ(0, SeqAsciiString::kHeaderSize & kObjectAlignmentMask); |
- GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
- COPY_ASCII | DEST_ALWAYS_ALIGNED); |
+ StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
+ COPY_ASCII | DEST_ALWAYS_ALIGNED); |
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
__ add(sp, sp, Operand(3 * kPointerSize)); |
__ Ret(); |
@@ -9271,8 +9348,8 @@ |
// r2: result length. |
// r5: first character of string to copy. |
ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask); |
- GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
- DEST_ALWAYS_ALIGNED); |
+ StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
+ DEST_ALWAYS_ALIGNED); |
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
__ add(sp, sp, Operand(3 * kPointerSize)); |
__ Ret(); |
@@ -9456,8 +9533,8 @@ |
// Try to lookup two character string in symbol table. If it is not found |
// just allocate a new one. |
Label make_two_character_string; |
- GenerateTwoCharacterSymbolTableProbe(masm, r2, r3, r6, r7, r4, r5, r9, |
- &make_two_character_string); |
+ StringHelper::GenerateTwoCharacterSymbolTableProbe( |
+ masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string); |
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
__ add(sp, sp, Operand(2 * kPointerSize)); |
__ Ret(); |
@@ -9566,7 +9643,7 @@ |
// r3: length of second string. |
// r6: first character of result. |
// r7: result string. |
- GenerateCopyCharacters(masm, r6, r0, r2, r4, true); |
+ StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, true); |
// Load second argument and locate first character. |
__ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
@@ -9574,7 +9651,7 @@ |
// r3: length of second string. |
// r6: next character of result. |
// r7: result string. |
- GenerateCopyCharacters(masm, r6, r1, r3, r4, true); |
+ StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true); |
__ mov(r0, Operand(r7)); |
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
__ add(sp, sp, Operand(2 * kPointerSize)); |
@@ -9605,7 +9682,7 @@ |
// r3: length of second string. |
// r6: first character of result. |
// r7: result string. |
- GenerateCopyCharacters(masm, r6, r0, r2, r4, false); |
+ StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, false); |
// Locate first character of second argument. |
__ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
@@ -9614,7 +9691,7 @@ |
// r3: length of second string. |
// r6: next character of result (after copy of first string). |
// r7: result string. |
- GenerateCopyCharacters(masm, r6, r1, r3, r4, false); |
+ StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false); |
__ mov(r0, Operand(r7)); |
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |