Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 4526) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -3863,43 +3863,11 @@ |
Comment(masm_, "[ GenerateFastCharCodeAt"); |
ASSERT(args->length() == 2); |
- Label slow_case; |
- Label end; |
- Label not_a_flat_string; |
- Label try_again_with_new_string; |
- Label ascii_string; |
- Label got_char_code; |
- |
Load(args->at(0)); |
Load(args->at(1)); |
Result index = frame_->Pop(); |
Result object = frame_->Pop(); |
- // Get register rcx to use as shift amount later. |
- Result shift_amount; |
- if (object.is_register() && object.reg().is(rcx)) { |
- Result fresh = allocator_->Allocate(); |
- shift_amount = object; |
- object = fresh; |
- __ movq(object.reg(), rcx); |
- } |
- if (index.is_register() && index.reg().is(rcx)) { |
- Result fresh = allocator_->Allocate(); |
- shift_amount = index; |
- index = fresh; |
- __ movq(index.reg(), rcx); |
- } |
- // There could be references to ecx in the frame. Allocating will |
- // spill them, otherwise spill explicitly. |
- if (shift_amount.is_valid()) { |
- frame_->Spill(rcx); |
- } else { |
- shift_amount = allocator()->Allocate(rcx); |
- } |
- ASSERT(shift_amount.is_register()); |
- ASSERT(shift_amount.reg().is(rcx)); |
- ASSERT(allocator_->count(rcx) == 1); |
- |
// We will mutate the index register and possibly the object register. |
// The case where they are somehow the same register is handled |
// because we only mutate them in the case where the receiver is a |
@@ -3909,89 +3877,34 @@ |
frame_->Spill(object.reg()); |
frame_->Spill(index.reg()); |
- // We need a single extra temporary register. |
- Result temp = allocator()->Allocate(); |
- ASSERT(temp.is_valid()); |
+ // We need two extra registers. |
+ Result result = allocator()->Allocate(); |
+ ASSERT(result.is_valid()); |
+ Result scratch = allocator()->Allocate(); |
+ ASSERT(scratch.is_valid()); |
// There is no virtual frame effect from here up to the final result |
// push. |
+ Label slow_case; |
+ Label exit; |
+ StringHelper::GenerateFastCharCodeAt(masm_, |
+ object.reg(), |
+ index.reg(), |
+ scratch.reg(), |
+ result.reg(), |
+ &slow_case, |
+ &slow_case, |
+ &slow_case, |
+ &slow_case); |
+ __ jmp(&exit); |
- // If the receiver is a smi trigger the slow case. |
- __ JumpIfSmi(object.reg(), &slow_case); |
- |
- // If the index is negative or non-smi trigger the slow case. |
- __ JumpIfNotPositiveSmi(index.reg(), &slow_case); |
- |
- // Untag the index. |
- __ SmiToInteger32(index.reg(), index.reg()); |
- |
- __ bind(&try_again_with_new_string); |
- // Fetch the instance type of the receiver into rcx. |
- __ movq(rcx, FieldOperand(object.reg(), HeapObject::kMapOffset)); |
- __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); |
- // If the receiver is not a string trigger the slow case. |
- __ testb(rcx, Immediate(kIsNotStringMask)); |
- __ j(not_zero, &slow_case); |
- |
- // Check for index out of range. |
- __ cmpl(index.reg(), FieldOperand(object.reg(), String::kLengthOffset)); |
- __ j(greater_equal, &slow_case); |
- // Reload the instance type (into the temp register this time).. |
- __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); |
- __ movzxbl(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
- |
- // We need special handling for non-flat strings. |
- ASSERT_EQ(0, kSeqStringTag); |
- __ testb(temp.reg(), Immediate(kStringRepresentationMask)); |
- __ j(not_zero, ¬_a_flat_string); |
- // Check for 1-byte or 2-byte string. |
- ASSERT_EQ(0, kTwoByteStringTag); |
- __ testb(temp.reg(), Immediate(kStringEncodingMask)); |
- __ j(not_zero, &ascii_string); |
- |
- // 2-byte string. |
- // Load the 2-byte character code into the temp register. |
- __ movzxwl(temp.reg(), FieldOperand(object.reg(), |
- index.reg(), |
- times_2, |
- SeqTwoByteString::kHeaderSize)); |
- __ jmp(&got_char_code); |
- |
- // ASCII string. |
- __ bind(&ascii_string); |
- // Load the byte into the temp register. |
- __ movzxbl(temp.reg(), FieldOperand(object.reg(), |
- index.reg(), |
- times_1, |
- SeqAsciiString::kHeaderSize)); |
- __ bind(&got_char_code); |
- __ Integer32ToSmi(temp.reg(), temp.reg()); |
- __ jmp(&end); |
- |
- // Handle non-flat strings. |
- __ bind(¬_a_flat_string); |
- __ and_(temp.reg(), Immediate(kStringRepresentationMask)); |
- __ cmpb(temp.reg(), Immediate(kConsStringTag)); |
- __ j(not_equal, &slow_case); |
- |
- // 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. |
- __ movq(temp.reg(), FieldOperand(object.reg(), ConsString::kSecondOffset)); |
- __ CompareRoot(temp.reg(), Heap::kEmptyStringRootIndex); |
- __ j(not_equal, &slow_case); |
- // Get the first of the two strings. |
- __ movq(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset)); |
- __ jmp(&try_again_with_new_string); |
- |
__ bind(&slow_case); |
// Move the undefined value into the result register, which will |
// trigger the slow case. |
- __ LoadRoot(temp.reg(), Heap::kUndefinedValueRootIndex); |
+ __ LoadRoot(result.reg(), Heap::kUndefinedValueRootIndex); |
- __ bind(&end); |
- frame_->Push(&temp); |
+ __ bind(&exit); |
+ frame_->Push(&result); |
} |
@@ -4000,41 +3913,25 @@ |
ASSERT(args->length() == 1); |
Load(args->at(0)); |
+ |
Result code = frame_->Pop(); |
code.ToRegister(); |
ASSERT(code.is_valid()); |
- Result temp = allocator()->Allocate(); |
- ASSERT(temp.is_valid()); |
+ // StringHelper::GenerateCharFromCode may do a runtime call. |
+ frame_->SpillAll(); |
- JumpTarget slow_case; |
- JumpTarget exit; |
+ Result result = allocator()->Allocate(); |
+ ASSERT(result.is_valid()); |
+ Result scratch = allocator()->Allocate(); |
+ ASSERT(scratch.is_valid()); |
- // Fast case of Heap::LookupSingleCharacterStringFromCode. |
- Condition is_smi = __ CheckSmi(code.reg()); |
- slow_case.Branch(NegateCondition(is_smi), &code, not_taken); |
- |
- __ SmiToInteger32(kScratchRegister, code.reg()); |
- __ cmpl(kScratchRegister, Immediate(String::kMaxAsciiCharCode)); |
- slow_case.Branch(above, &code, not_taken); |
- |
- __ Move(temp.reg(), Factory::single_character_string_cache()); |
- __ movq(temp.reg(), FieldOperand(temp.reg(), |
- kScratchRegister, times_pointer_size, |
- FixedArray::kHeaderSize)); |
- __ CompareRoot(temp.reg(), Heap::kUndefinedValueRootIndex); |
- slow_case.Branch(equal, &code, not_taken); |
- code.Unuse(); |
- |
- frame_->Push(&temp); |
- exit.Jump(); |
- |
- slow_case.Bind(&code); |
- frame_->Push(&code); |
- Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1); |
+ StringHelper::GenerateCharFromCode(masm_, |
+ code.reg(), |
+ result.reg(), |
+ scratch.reg(), |
+ CALL_FUNCTION); |
frame_->Push(&result); |
- |
- exit.Bind(); |
} |
@@ -9797,6 +9694,146 @@ |
} |
+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. |
+ __ JumpIfSmi(object, receiver_not_string); |
+ |
+ // Fetch the instance type of the receiver into result register. |
+ __ movq(result, FieldOperand(object, HeapObject::kMapOffset)); |
+ __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
+ // If the receiver is not a string trigger the non-string case. |
+ __ testb(result, Immediate(kIsNotStringMask)); |
+ __ j(not_zero, receiver_not_string); |
+ |
+ // If the index is non-smi trigger the non-smi case. |
+ __ JumpIfNotSmi(index, index_not_smi); |
+ |
+ // Put untagged index into scratch register. |
+ __ SmiToInteger32(scratch, index); |
+ |
+ // Check for index out of range. |
+ __ cmpl(scratch, FieldOperand(object, String::kLengthOffset)); |
+ __ j(above_equal, 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); |
+ __ testb(result, Immediate(kStringRepresentationMask)); |
+ __ j(not_zero, ¬_a_flat_string); |
+ |
+ // Check for 1-byte or 2-byte string. |
+ ASSERT_EQ(0, kTwoByteStringTag); |
+ __ testb(result, Immediate(kStringEncodingMask)); |
+ __ j(not_zero, &ascii_string); |
+ |
+ // 2-byte string. |
+ // Load the 2-byte character code into the result register. |
+ __ movzxwl(result, FieldOperand(object, |
+ scratch, |
+ times_2, |
+ SeqTwoByteString::kHeaderSize)); |
+ __ jmp(&got_char_code); |
+ |
+ // Handle non-flat strings. |
+ __ bind(¬_a_flat_string); |
+ __ and_(result, Immediate(kStringRepresentationMask)); |
+ __ cmpb(result, Immediate(kConsStringTag)); |
+ __ j(not_equal, slow_case); |
+ |
+ // 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. |
+ __ movq(result, FieldOperand(object, ConsString::kSecondOffset)); |
+ __ CompareRoot(result, Heap::kEmptyStringRootIndex); |
+ __ j(not_equal, slow_case); |
+ // Get the first of the two strings and load its instance type. |
+ __ movq(object, FieldOperand(object, ConsString::kFirstOffset)); |
+ __ movq(result, FieldOperand(object, HeapObject::kMapOffset)); |
+ __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
+ __ jmp(&try_again_with_new_string); |
+ |
+ // ASCII string. |
+ __ bind(&ascii_string); |
+ // Load the byte into the result register. |
+ __ movzxbl(result, FieldOperand(object, |
+ scratch, |
+ times_1, |
+ SeqAsciiString::kHeaderSize)); |
+ __ bind(&got_char_code); |
+ __ Integer32ToSmi(result, result); |
+} |
+ |
+ |
+void StringHelper::GenerateCharFromCode(MacroAssembler* masm, |
+ Register code, |
+ Register result, |
+ Register scratch, |
+ InvokeFlag flag) { |
+ ASSERT(!code.is(result)); |
+ |
+ Label slow_case; |
+ Label exit; |
+ |
+ // Fast case of Heap::LookupSingleCharacterStringFromCode. |
+ __ JumpIfNotSmi(code, &slow_case); |
+ __ SmiToInteger32(scratch, code); |
+ __ cmpl(scratch, Immediate(String::kMaxAsciiCharCode)); |
+ __ j(above, &slow_case); |
+ |
+ __ Move(result, Factory::single_character_string_cache()); |
+ __ movq(result, FieldOperand(result, |
+ scratch, |
+ times_pointer_size, |
+ FixedArray::kHeaderSize)); |
+ |
+ __ CompareRoot(result, Heap::kUndefinedValueRootIndex); |
+ __ j(equal, &slow_case); |
+ __ jmp(&exit); |
+ |
+ __ bind(&slow_case); |
+ if (flag == CALL_FUNCTION) { |
+ __ push(code); |
+ __ CallRuntime(Runtime::kCharFromCode, 1); |
+ if (!result.is(rax)) { |
+ __ movq(result, rax); |
+ } |
+ } else { |
+ ASSERT(flag == JUMP_FUNCTION); |
+ ASSERT(result.is(rax)); |
+ __ pop(rax); // Save return address. |
+ __ push(code); |
+ __ push(rax); // Restore return address. |
+ __ TailCallRuntime(Runtime::kCharFromCode, 1, 1); |
+ } |
+ |
+ __ bind(&exit); |
+ if (flag == JUMP_FUNCTION) { |
+ ASSERT(result.is(rax)); |
+ __ ret(0); |
+ } |
+} |
+ |
+ |
void StringAddStub::Generate(MacroAssembler* masm) { |
Label string_add_runtime; |
@@ -9877,8 +9914,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, make_flat_ascii_string; |
- GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, r14, r12, rdi, r15, |
- &make_two_character_string); |
+ StringHelper::GenerateTwoCharacterSymbolTableProbe( |
+ masm, rbx, rcx, r14, r12, rdi, r15, &make_two_character_string); |
__ IncrementCounter(&Counters::string_add_native, 1); |
__ ret(2 * kPointerSize); |
@@ -9969,7 +10006,7 @@ |
// rcx: first character of result |
// rdx: second string |
// rdi: length of first argument |
- GenerateCopyCharacters(masm, rcx, rax, rdi, true); |
+ StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, true); |
// Locate first character of second argument. |
__ movl(rdi, FieldOperand(rdx, String::kLengthOffset)); |
__ addq(rdx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
@@ -9977,7 +10014,7 @@ |
// rcx: next character of result |
// rdx: first char of second argument |
// rdi: length of second argument |
- GenerateCopyCharacters(masm, rcx, rdx, rdi, true); |
+ StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, true); |
__ movq(rax, rbx); |
__ IncrementCounter(&Counters::string_add_native, 1); |
__ ret(2 * kPointerSize); |
@@ -10006,7 +10043,7 @@ |
// rcx: first character of result |
// rdx: second argument |
// rdi: length of first argument |
- GenerateCopyCharacters(masm, rcx, rax, rdi, false); |
+ StringHelper::GenerateCopyCharacters(masm, rcx, rax, rdi, false); |
// Locate first character of second argument. |
__ movl(rdi, FieldOperand(rdx, String::kLengthOffset)); |
__ addq(rdx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
@@ -10014,7 +10051,7 @@ |
// rcx: next character of result |
// rdx: first char of second argument |
// rdi: length of second argument |
- GenerateCopyCharacters(masm, rcx, rdx, rdi, false); |
+ StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false); |
__ movq(rax, rbx); |
__ IncrementCounter(&Counters::string_add_native, 1); |
__ ret(2 * kPointerSize); |
@@ -10025,11 +10062,11 @@ |
} |
-void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, |
- Register dest, |
- Register src, |
- Register count, |
- bool ascii) { |
+void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
+ Register dest, |
+ Register src, |
+ Register count, |
+ bool ascii) { |
Label loop; |
__ bind(&loop); |
// This loop just copies one character at a time, as it is only used for very |
@@ -10050,11 +10087,11 @@ |
} |
-void StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm, |
- Register dest, |
- Register src, |
- Register count, |
- bool ascii) { |
+void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |
+ Register dest, |
+ Register src, |
+ Register count, |
+ bool ascii) { |
// Copy characters using rep movs of doublewords. Align destination on 4 byte |
// boundary before starting rep movs. Copy remaining characters after running |
// rep movs. |
@@ -10105,14 +10142,14 @@ |
__ bind(&done); |
} |
-void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
- Register c1, |
- Register c2, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Register scratch4, |
- Label* not_found) { |
+void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
+ Register c1, |
+ Register c2, |
+ Register scratch1, |
+ Register scratch2, |
+ Register scratch3, |
+ Register scratch4, |
+ Label* not_found) { |
// Register scratch3 is the general scratch register in this function. |
Register scratch = scratch3; |
@@ -10223,10 +10260,10 @@ |
} |
-void StringStubBase::GenerateHashInit(MacroAssembler* masm, |
- Register hash, |
- Register character, |
- Register scratch) { |
+void StringHelper::GenerateHashInit(MacroAssembler* masm, |
+ Register hash, |
+ Register character, |
+ Register scratch) { |
// hash = character + (character << 10); |
__ movl(hash, character); |
__ shll(hash, Immediate(10)); |
@@ -10238,10 +10275,10 @@ |
} |
-void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, |
- Register hash, |
- Register character, |
- Register scratch) { |
+void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, |
+ Register hash, |
+ Register character, |
+ Register scratch) { |
// hash += character; |
__ addl(hash, character); |
// hash += hash << 10; |
@@ -10255,9 +10292,9 @@ |
} |
-void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, |
- Register hash, |
- Register scratch) { |
+void StringHelper::GenerateHashGetHash(MacroAssembler* masm, |
+ Register hash, |
+ Register scratch) { |
// hash += hash << 3; |
__ movl(scratch, hash); |
__ shll(scratch, Immediate(3)); |
@@ -10334,8 +10371,8 @@ |
// Try to lookup two character string in symbol table. |
Label make_two_character_string; |
- GenerateTwoCharacterSymbolTableProbe(masm, rbx, rcx, rax, rdx, rdi, r14, |
- &make_two_character_string); |
+ StringHelper::GenerateTwoCharacterSymbolTableProbe( |
+ masm, rbx, rcx, rax, rdx, rdi, r14, &make_two_character_string); |
__ ret(3 * kPointerSize); |
__ bind(&make_two_character_string); |
@@ -10376,7 +10413,7 @@ |
// rdx: original value of rsi |
// rdi: first character of result |
// rsi: character of sub string start |
- GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); |
+ StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); |
__ movq(rsi, rdx); // Restore rsi. |
__ IncrementCounter(&Counters::sub_string_native, 1); |
__ ret(kArgumentsSize); |
@@ -10411,7 +10448,7 @@ |
// rdx: original value of rsi |
// rdi: first character of result |
// rsi: character of sub string start |
- GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); |
+ StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); |
__ movq(rsi, rdx); // Restore esi. |
__ IncrementCounter(&Counters::sub_string_native, 1); |
__ ret(kArgumentsSize); |