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,12 +8514,151 @@ int CompareStub::MinorKey() { ...@@ -8576,12 +8514,151 @@ int CompareStub::MinorKey() {
} }
void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm,
Register dest, Register object,
Register src, Register index,
Register count, Register scratch,
Register scratch, Register result,
bool ascii) { 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 src,
Register count,
Register scratch,
bool ascii) {
Label loop; Label loop;
Label done; Label done;
// This loop just copies one character at a time, as it is only used for very // This loop just copies one character at a time, as it is only used for very
...@@ -8612,16 +8689,16 @@ enum CopyCharactersFlags { ...@@ -8612,16 +8689,16 @@ enum CopyCharactersFlags {
}; };
void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm, void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
Register dest, Register dest,
Register src, Register src,
Register count, Register count,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Register scratch3, Register scratch3,
Register scratch4, Register scratch4,
Register scratch5, Register scratch5,
int flags) { int flags) {
bool ascii = (flags & COPY_ASCII) != 0; bool ascii = (flags & COPY_ASCII) != 0;
bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0; bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0;
...@@ -8755,15 +8832,15 @@ void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm, ...@@ -8755,15 +8832,15 @@ 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,
Register scratch2, Register scratch2,
Register scratch3, Register scratch3,
Register scratch4, Register scratch4,
Register scratch5, Register scratch5,
Label* not_found) { Label* not_found) {
// Register scratch3 is the general scratch register in this function. // Register scratch3 is the general scratch register in this function.
Register scratch = scratch3; Register scratch = scratch3;
...@@ -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,9 +8958,9 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, ...@@ -8881,9 +8958,9 @@ 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);
__ add(hash, character, Operand(character, LSL, 10)); __ add(hash, character, Operand(character, LSL, 10));
// hash ^= hash >> 6; // hash ^= hash >> 6;
...@@ -8891,9 +8968,9 @@ void StringStubBase::GenerateHashInit(MacroAssembler* masm, ...@@ -8891,9 +8968,9 @@ 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;
__ add(hash, hash, Operand(character)); __ add(hash, hash, Operand(character));
// hash += hash << 10; // hash += hash << 10;
...@@ -8903,8 +8980,8 @@ void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, ...@@ -8903,8 +8980,8 @@ 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));
// hash ^= hash >> 11; // hash ^= hash >> 11;
...@@ -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,8 +9143,8 @@ void SubStringStub::Generate(MacroAssembler* masm) { ...@@ -9066,8 +9143,8 @@ 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));
__ Ret(); __ Ret();
...@@ -9097,8 +9174,8 @@ void SubStringStub::Generate(MacroAssembler* masm) { ...@@ -9097,8 +9174,8 @@ 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));
__ Ret(); __ Ret();
...@@ -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,34 +665,66 @@ class GenericBinaryOpStub : public CodeStub { ...@@ -665,34 +665,66 @@ 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,
Register scratch, Register scratch,
bool ascii); bool ascii);
// Generate code for copying a large number of characters. This function // Generate code for copying a large number of characters. This function
// 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,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Register scratch3, Register scratch3,
Register scratch4, Register scratch4,
Register scratch5, Register scratch5,
int flags); int flags);
// Probe the symbol table for a two character string. If the string is // Probe the symbol table for a two character string. If the string is
...@@ -702,27 +734,30 @@ class StringStubBase: public CodeStub { ...@@ -702,27 +734,30 @@ 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,
Register scratch2, Register scratch2,
Register scratch3, Register scratch3,
Register scratch4, Register scratch4,
Register scratch5, Register scratch5,
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);
static void GenerateHashAddCharacter(MacroAssembler* masm,
Register hash,
Register character);
void GenerateHashAddCharacter(MacroAssembler* masm, static void GenerateHashGetHash(MacroAssembler* masm,
Register hash, Register hash);
Register character);
void GenerateHashGetHash(MacroAssembler* masm, private:
Register hash); 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 - - -
------------------------------------- -------------------------------------
......
...@@ -873,19 +873,19 @@ class StringHelper : public AllStatic { ...@@ -873,19 +873,19 @@ class StringHelper : public AllStatic {
// additional setup and checking in GenerateCopyCharactersREP adds too much // additional setup and checking in GenerateCopyCharactersREP adds too much
// overhead. Copying of overlapping regions is not supported. // overhead. Copying of overlapping regions is not supported.
static void GenerateCopyCharacters(MacroAssembler* masm, static void GenerateCopyCharacters(MacroAssembler* masm,
Register dest, Register dest,
Register src, Register src,
Register count, Register count,
bool ascii); bool ascii);
// Generate code for copying characters using the rep movs instruction. // Generate code for copying characters using the rep movs instruction.
// Copies rcx characters from rsi to rdi. Copying of overlapping regions is // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
// not supported. // not supported.
static void GenerateCopyCharactersREP(MacroAssembler* masm, static void GenerateCopyCharactersREP(MacroAssembler* masm,
Register dest, // Must be rdi. Register dest, // Must be rdi.
Register src, // Must be rsi. Register src, // Must be rsi.
Register count, // Must be rcx. Register count, // Must be rcx.
bool ascii); bool ascii);
// Probe the symbol table for a two character string. If the string is // Probe the symbol table for a two character string. If the string is
...@@ -893,26 +893,27 @@ class StringHelper : public AllStatic { ...@@ -893,26 +893,27 @@ class StringHelper : public AllStatic {
// does not guarantee that the string is not in the symbol table. If the // does not guarantee that the string is not in the symbol table. If the
// string is found the code falls through with the string in register rax. // string is found the code falls through with the string in register rax.
static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
Register c1, Register c1,
Register c2, Register c2,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Register scratch3, Register scratch3,
Register scratch4, Register scratch4,
Label* not_found); Label* not_found);
// Generate string hash. // Generate string hash.
static void GenerateHashInit(MacroAssembler* masm, static void GenerateHashInit(MacroAssembler* masm,
Register hash, Register hash,
Register character, Register character,
Register scratch); Register scratch);
static void GenerateHashAddCharacter(MacroAssembler* masm, static void GenerateHashAddCharacter(MacroAssembler* masm,
Register hash, Register hash,
Register character, Register character,
Register scratch); Register scratch);
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