Port string keyed load IC improvements (r4444) to ARM.

Review URL: http://codereview.chromium.org/1769014

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4573 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5affd79e
...@@ -3763,9 +3763,12 @@ void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { ...@@ -3763,9 +3763,12 @@ void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
} }
// 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. // 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) { void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope(frame_); VirtualFrame::SpilledScope spilled_scope(frame_);
ASSERT(args->length() == 2); ASSERT(args->length() == 2);
...@@ -3773,75 +3776,28 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { ...@@ -3773,75 +3776,28 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
LoadAndSpill(args->at(0)); LoadAndSpill(args->at(0));
LoadAndSpill(args->at(1)); LoadAndSpill(args->at(1));
frame_->EmitPop(r0); // Index. frame_->EmitPop(r1); // Index.
frame_->EmitPop(r1); // String. frame_->EmitPop(r2); // String.
Label slow, end, not_a_flat_string, ascii_string, try_again_with_new_string; Label slow_case;
Label exit;
__ tst(r1, Operand(kSmiTagMask)); StringHelper::GenerateFastCharCodeAt(masm_,
__ b(eq, &slow); // The 'string' was a Smi. r2,
r1,
ASSERT(kSmiTag == 0); r3,
__ tst(r0, Operand(kSmiTagMask | 0x80000000u)); r0,
__ b(ne, &slow); // The index was negative or not a Smi. &slow_case,
&slow_case,
__ bind(&try_again_with_new_string); &slow_case,
__ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE); &slow_case);
__ b(ge, &slow); __ jmp(&exit);
// 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, &not_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(&not_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); __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
__ bind(&end); __ bind(&exit);
frame_->EmitPush(r0); frame_->EmitPush(r0);
} }
...@@ -3850,37 +3806,19 @@ void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { ...@@ -3850,37 +3806,19 @@ void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
Comment(masm_, "[ GenerateCharFromCode"); Comment(masm_, "[ GenerateCharFromCode");
ASSERT(args->length() == 1); ASSERT(args->length() == 1);
LoadAndSpill(args->at(0)); Register code = r1;
frame_->EmitPop(r0); Register scratch = ip;
Register result = r0;
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(); LoadAndSpill(args->at(0));
frame_->EmitPush(r0); frame_->EmitPop(code);
frame_->CallRuntime(Runtime::kCharFromCode, 1);
frame_->EmitPush(r0);
exit.Bind(); StringHelper::GenerateCharFromCode(masm_,
code,
scratch,
result,
CALL_FUNCTION);
frame_->EmitPush(result);
} }
...@@ -8576,7 +8514,146 @@ int CompareStub::MinorKey() { ...@@ -8576,7 +8514,146 @@ int CompareStub::MinorKey() {
} }
void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, 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, &not_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(&not_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 dest,
Register src, Register src,
Register count, Register count,
...@@ -8612,7 +8689,7 @@ enum CopyCharactersFlags { ...@@ -8612,7 +8689,7 @@ enum CopyCharactersFlags {
}; };
void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm, void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
Register dest, Register dest,
Register src, Register src,
Register count, Register count,
...@@ -8755,7 +8832,7 @@ void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm, ...@@ -8755,7 +8832,7 @@ void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm,
} }
void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register c1, Register c1,
Register c2, Register c2,
Register scratch1, Register scratch1,
...@@ -8785,9 +8862,9 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, ...@@ -8785,9 +8862,9 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
__ bind(&not_array_index); __ bind(&not_array_index);
// Calculate the two character string hash. // Calculate the two character string hash.
Register hash = scratch1; Register hash = scratch1;
GenerateHashInit(masm, hash, c1); StringHelper::GenerateHashInit(masm, hash, c1);
GenerateHashAddCharacter(masm, hash, c2); StringHelper::GenerateHashAddCharacter(masm, hash, c2);
GenerateHashGetHash(masm, hash); StringHelper::GenerateHashGetHash(masm, hash);
// Collect the two characters in a register. // Collect the two characters in a register.
Register chars = c1; Register chars = c1;
...@@ -8881,7 +8958,7 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, ...@@ -8881,7 +8958,7 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
} }
void StringStubBase::GenerateHashInit(MacroAssembler* masm, void StringHelper::GenerateHashInit(MacroAssembler* masm,
Register hash, Register hash,
Register character) { Register character) {
// hash = character + (character << 10); // hash = character + (character << 10);
...@@ -8891,7 +8968,7 @@ void StringStubBase::GenerateHashInit(MacroAssembler* masm, ...@@ -8891,7 +8968,7 @@ void StringStubBase::GenerateHashInit(MacroAssembler* masm,
} }
void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
Register hash, Register hash,
Register character) { Register character) {
// hash += character; // hash += character;
...@@ -8903,7 +8980,7 @@ void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, ...@@ -8903,7 +8980,7 @@ void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm,
} }
void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
Register hash) { Register hash) {
// hash += hash << 3; // hash += hash << 3;
__ add(hash, hash, Operand(hash, LSL, 3)); __ add(hash, hash, Operand(hash, LSL, 3));
...@@ -9031,8 +9108,8 @@ void SubStringStub::Generate(MacroAssembler* masm) { ...@@ -9031,8 +9108,8 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Try to lookup two character string in symbol table. // Try to lookup two character string in symbol table.
Label make_two_character_string; Label make_two_character_string;
GenerateTwoCharacterSymbolTableProbe(masm, r3, r4, r1, r5, r6, r7, r9, StringHelper::GenerateTwoCharacterSymbolTableProbe(
&make_two_character_string); masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string);
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize)); __ add(sp, sp, Operand(3 * kPointerSize));
__ Ret(); __ Ret();
...@@ -9066,7 +9143,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { ...@@ -9066,7 +9143,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// r2: result string length. // r2: result string length.
// r5: first character of sub string to copy. // r5: first character of sub string to copy.
ASSERT_EQ(0, SeqAsciiString::kHeaderSize & kObjectAlignmentMask); ASSERT_EQ(0, SeqAsciiString::kHeaderSize & kObjectAlignmentMask);
GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
COPY_ASCII | DEST_ALWAYS_ALIGNED); COPY_ASCII | DEST_ALWAYS_ALIGNED);
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize)); __ add(sp, sp, Operand(3 * kPointerSize));
...@@ -9097,7 +9174,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { ...@@ -9097,7 +9174,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// r2: result length. // r2: result length.
// r5: first character of string to copy. // r5: first character of string to copy.
ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask); ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask);
GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
DEST_ALWAYS_ALIGNED); DEST_ALWAYS_ALIGNED);
__ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize)); __ add(sp, sp, Operand(3 * kPointerSize));
...@@ -9282,8 +9359,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { ...@@ -9282,8 +9359,8 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// Try to lookup two character string in symbol table. If it is not found // Try to lookup two character string in symbol table. If it is not found
// just allocate a new one. // just allocate a new one.
Label make_two_character_string; Label make_two_character_string;
GenerateTwoCharacterSymbolTableProbe(masm, r2, r3, r6, r7, r4, r5, r9, StringHelper::GenerateTwoCharacterSymbolTableProbe(
&make_two_character_string); masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string);
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3); __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize)); __ add(sp, sp, Operand(2 * kPointerSize));
__ Ret(); __ Ret();
...@@ -9392,7 +9469,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { ...@@ -9392,7 +9469,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r3: length of second string. // r3: length of second string.
// r6: first character of result. // r6: first character of result.
// r7: result string. // 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. // Load second argument and locate first character.
__ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); __ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
...@@ -9400,7 +9477,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { ...@@ -9400,7 +9477,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r3: length of second string. // r3: length of second string.
// r6: next character of result. // r6: next character of result.
// r7: result string. // r7: result string.
GenerateCopyCharacters(masm, r6, r1, r3, r4, true); StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true);
__ mov(r0, Operand(r7)); __ mov(r0, Operand(r7));
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3); __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize)); __ add(sp, sp, Operand(2 * kPointerSize));
...@@ -9431,7 +9508,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { ...@@ -9431,7 +9508,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r3: length of second string. // r3: length of second string.
// r6: first character of result. // r6: first character of result.
// r7: result string. // r7: result string.
GenerateCopyCharacters(masm, r6, r0, r2, r4, false); StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, false);
// Locate first character of second argument. // Locate first character of second argument.
__ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); __ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
...@@ -9440,7 +9517,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { ...@@ -9440,7 +9517,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// r3: length of second string. // r3: length of second string.
// r6: next character of result (after copy of first string). // r6: next character of result (after copy of first string).
// r7: result string. // r7: result string.
GenerateCopyCharacters(masm, r6, r1, r3, r4, false); StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false);
__ mov(r0, Operand(r7)); __ mov(r0, Operand(r7));
__ IncrementCounter(&Counters::string_add_native, 1, r2, r3); __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
......
...@@ -665,14 +665,46 @@ class GenericBinaryOpStub : public CodeStub { ...@@ -665,14 +665,46 @@ class GenericBinaryOpStub : public CodeStub {
}; };
class StringStubBase: public CodeStub { class StringHelper : public AllStatic {
public: public:
// Generates fast code for getting a char code out of a string
// object at the given index. May bail out for four reasons (in the
// listed order):
// * Receiver is not a string (receiver_not_string label).
// * Index is not a smi (index_not_smi label).
// * Index is out of range (index_out_of_range).
// * Some other reason (slow_case label). In this case it's
// guaranteed that the above conditions are not violated,
// e.g. it's safe to assume the receiver is a string and the
// index is a non-negative smi < length.
// When successful, object, index, and scratch are clobbered.
// Otherwise, scratch and result are clobbered.
static void 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);
// Generates code for creating a one-char string from the given char
// code. May do a runtime call, so any register can be clobbered
// and, if the given invoke flag specifies a call, an internal frame
// is required. In tail call mode the result must be r0 register.
static void GenerateCharFromCode(MacroAssembler* masm,
Register code,
Register scratch,
Register result,
InvokeFlag flag);
// Generate code for copying characters using a simple loop. This should only // Generate code for copying characters using a simple loop. This should only
// be used in places where the number of characters is small and the // be used in places where the number of characters is small and the
// additional setup and checking in GenerateCopyCharactersLong adds too much // additional setup and checking in GenerateCopyCharactersLong adds too much
// overhead. Copying of overlapping regions is not supported. // overhead. Copying of overlapping regions is not supported.
// Dest register ends at the position after the last character written. // Dest register ends at the position after the last character written.
void GenerateCopyCharacters(MacroAssembler* masm, static void GenerateCopyCharacters(MacroAssembler* masm,
Register dest, Register dest,
Register src, Register src,
Register count, Register count,
...@@ -683,7 +715,7 @@ class StringStubBase: public CodeStub { ...@@ -683,7 +715,7 @@ class StringStubBase: public CodeStub {
// is allowed to spend extra time setting up conditions to make copying // is allowed to spend extra time setting up conditions to make copying
// faster. Copying of overlapping regions is not supported. // faster. Copying of overlapping regions is not supported.
// Dest register ends at the position after the last character written. // Dest register ends at the position after the last character written.
void GenerateCopyCharactersLong(MacroAssembler* masm, static void GenerateCopyCharactersLong(MacroAssembler* masm,
Register dest, Register dest,
Register src, Register src,
Register count, Register count,
...@@ -702,7 +734,7 @@ class StringStubBase: public CodeStub { ...@@ -702,7 +734,7 @@ class StringStubBase: public CodeStub {
// Contents of both c1 and c2 registers are modified. At the exit c1 is // Contents of both c1 and c2 registers are modified. At the exit c1 is
// guaranteed to contain halfword with low and high bytes equal to // guaranteed to contain halfword with low and high bytes equal to
// initial contents of c1 and c2 respectively. // initial contents of c1 and c2 respectively.
void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register c1, Register c1,
Register c2, Register c2,
Register scratch1, Register scratch1,
...@@ -713,16 +745,19 @@ class StringStubBase: public CodeStub { ...@@ -713,16 +745,19 @@ class StringStubBase: public CodeStub {
Label* not_found); Label* not_found);
// Generate string hash. // Generate string hash.
void GenerateHashInit(MacroAssembler* masm, static void GenerateHashInit(MacroAssembler* masm,
Register hash, Register hash,
Register character); Register character);
void GenerateHashAddCharacter(MacroAssembler* masm, static void GenerateHashAddCharacter(MacroAssembler* masm,
Register hash, Register hash,
Register character); Register character);
void GenerateHashGetHash(MacroAssembler* masm, static void GenerateHashGetHash(MacroAssembler* masm,
Register hash); Register hash);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
}; };
...@@ -733,7 +768,7 @@ enum StringAddFlags { ...@@ -733,7 +768,7 @@ enum StringAddFlags {
}; };
class StringAddStub: public StringStubBase { class StringAddStub: public CodeStub {
public: public:
explicit StringAddStub(StringAddFlags flags) { explicit StringAddStub(StringAddFlags flags) {
string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
...@@ -750,7 +785,7 @@ class StringAddStub: public StringStubBase { ...@@ -750,7 +785,7 @@ class StringAddStub: public StringStubBase {
}; };
class SubStringStub: public StringStubBase { class SubStringStub: public CodeStub {
public: public:
SubStringStub() {} SubStringStub() {}
......
...@@ -800,28 +800,67 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { ...@@ -800,28 +800,67 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
// -- sp[0] : key // -- sp[0] : key
// -- sp[4] : receiver // -- sp[4] : receiver
// ----------------------------------- // -----------------------------------
Label miss;
Label miss, index_ok; Label index_not_smi;
Label index_out_of_range;
Label slow_char_code;
Label got_char_code;
// Get the key and receiver object from the stack. // Get the key and receiver object from the stack.
__ ldm(ia, sp, r0.bit() | r1.bit()); __ ldm(ia, sp, r0.bit() | r1.bit());
// Check that the receiver isn't a smi. Register object = r1;
__ BranchOnSmi(r1, &miss); Register index = r0;
Register code = r2;
// Check that the receiver is a string. Register scratch = r3;
Condition is_string = masm->IsObjectStringType(r1, r2);
__ b(NegateCondition(is_string), &miss);
// Check if key is a smi or a heap number. StringHelper::GenerateFastCharCodeAt(masm,
__ BranchOnSmi(r0, &index_ok); object,
__ CheckMap(r0, r2, Factory::heap_number_map(), &miss, false); index,
scratch,
code,
&miss, // When not a string.
&index_not_smi,
&index_out_of_range,
&slow_char_code);
// If we didn't bail out, code register contains smi tagged char
// code.
__ bind(&got_char_code);
StringHelper::GenerateCharFromCode(masm, code, scratch, r0, JUMP_FUNCTION);
#ifdef DEBUG
__ Abort("Unexpected fall-through from char from code tail call");
#endif
// Check if key is a heap number.
__ bind(&index_not_smi);
__ CheckMap(index, scratch, Factory::heap_number_map(), &miss, true);
// Push receiver and key on the stack (now that we know they are a
// string and a number), and call runtime.
__ bind(&slow_char_code);
__ EnterInternalFrame();
__ Push(object, index);
__ CallRuntime(Runtime::kStringCharCodeAt, 2);
ASSERT(!code.is(r0));
__ mov(code, r0);
__ LeaveInternalFrame();
__ bind(&index_ok); // Check if the runtime call returned NaN char code. If yes, return
// Duplicate receiver and key since they are expected on the stack after // undefined. Otherwise, we can continue.
// the KeyedLoadIC call. if (FLAG_debug_code) {
__ Push(r1, r0); __ BranchOnSmi(code, &got_char_code);
__ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_JS); __ ldr(scratch, FieldMemOperand(code, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(scratch, ip);
__ Assert(eq, "StringCharCodeAt must return smi or heap number");
}
__ LoadRoot(scratch, Heap::kNanValueRootIndex);
__ cmp(code, scratch);
__ b(ne, &got_char_code);
__ bind(&index_out_of_range);
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
__ Ret();
__ bind(&miss); __ bind(&miss);
GenerateGeneric(masm); GenerateGeneric(masm);
......
...@@ -164,8 +164,7 @@ enum BuiltinExtraArguments { ...@@ -164,8 +164,7 @@ enum BuiltinExtraArguments {
V(STRING_ADD_LEFT, 1) \ V(STRING_ADD_LEFT, 1) \
V(STRING_ADD_RIGHT, 1) \ V(STRING_ADD_RIGHT, 1) \
V(APPLY_PREPARE, 1) \ V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1) \ V(APPLY_OVERFLOW, 1)
V(STRING_CHAR_AT, 1)
class ObjectVisitor; class ObjectVisitor;
......
...@@ -471,17 +471,6 @@ function TO_STRING() { ...@@ -471,17 +471,6 @@ function TO_STRING() {
} }
// Specialized version of String.charAt. It assumes string as
// the receiver type and that the index is a number.
function STRING_CHAR_AT(pos) {
var char_code = %_FastCharCodeAt(this, pos);
if (!%_IsSmi(char_code)) {
return %StringCharAt(this, pos);
}
return %_CharFromCode(char_code);
}
/* ------------------------------------- /* -------------------------------------
- - - C o n v e r s i o n s - - - - - - C o n v e r s i o n s - - -
------------------------------------- -------------------------------------
......
...@@ -913,6 +913,7 @@ class StringHelper : public AllStatic { ...@@ -913,6 +913,7 @@ class StringHelper : public AllStatic {
static void GenerateHashGetHash(MacroAssembler* masm, static void GenerateHashGetHash(MacroAssembler* masm,
Register hash, Register hash,
Register scratch); Register scratch);
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment