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
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.
-
- // 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);
+ 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);
__ 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);
}
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());
-
- JumpTarget slow_case;
- JumpTarget exit;
-
- // 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();
+ // StringHelper::GenerateCharFromCode may do a runtime call.
+ frame_->SpillAll();
- frame_->Push(&temp);
- exit.Jump();
+ Result result = allocator()->Allocate();
+ ASSERT(result.is_valid());
+ Result scratch = allocator()->Allocate();
+ ASSERT(scratch.is_valid());
- 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();
}
}
+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;
// 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);
// 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));
// 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);
// 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));
// 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);
}
-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
}
-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.
__ 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;
}
-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));
}
-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;
}
-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));
// 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);
// 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);
// 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);