Index: src/ia32/codegen-ia32.cc |
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc |
index 5ab7a531f325679e5285d045aadaa570625b56e4..9512886a58e26d75eca7f6d01239e71f4b906d91 100644 |
--- a/src/ia32/codegen-ia32.cc |
+++ b/src/ia32/codegen-ia32.cc |
@@ -2348,7 +2348,7 @@ Result CodeGenerator::ConstantSmiBinaryOperation( |
smi_value, |
overwrite_mode); |
// Check for negative or non-Smi left hand side. |
- __ test(operand->reg(), Immediate(kSmiTagMask | kSmiSignMask)); |
+ __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); |
deferred->Branch(not_zero); |
if (int_value < 0) int_value = -int_value; |
if (int_value == 1) { |
@@ -5901,7 +5901,7 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
Result value = frame_->Pop(); |
value.ToRegister(); |
ASSERT(value.is_valid()); |
- __ test(value.reg(), Immediate(kSmiTagMask | kSmiSignMask)); |
+ __ test(value.reg(), Immediate(kSmiTagMask | 0x80000000)); |
value.Unuse(); |
destination()->Split(zero); |
} |
@@ -5917,11 +5917,43 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
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 ecx to use as shift amount later. |
+ Result shift_amount; |
+ if (object.is_register() && object.reg().is(ecx)) { |
+ Result fresh = allocator_->Allocate(); |
+ shift_amount = object; |
+ object = fresh; |
+ __ mov(object.reg(), ecx); |
+ } |
+ if (index.is_register() && index.reg().is(ecx)) { |
+ Result fresh = allocator_->Allocate(); |
+ shift_amount = index; |
+ index = fresh; |
+ __ mov(index.reg(), ecx); |
+ } |
+ // There could be references to ecx in the frame. Allocating will |
+ // spill them, otherwise spill explicitly. |
+ if (shift_amount.is_valid()) { |
+ frame_->Spill(ecx); |
+ } else { |
+ shift_amount = allocator()->Allocate(ecx); |
+ } |
+ ASSERT(shift_amount.is_register()); |
+ ASSERT(shift_amount.reg().is(ecx)); |
+ ASSERT(allocator_->count(ecx) == 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 |
@@ -5931,33 +5963,93 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
frame_->Spill(object.reg()); |
frame_->Spill(index.reg()); |
- // We need two extra registers. |
- Result result = allocator()->Allocate(); |
- ASSERT(result.is_valid()); |
- Result scratch = allocator()->Allocate(); |
- ASSERT(scratch.is_valid()); |
+ // We need a single extra temporary register. |
+ Result temp = allocator()->Allocate(); |
+ ASSERT(temp.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); |
- __ jmp(&exit); |
+ |
+ // If the receiver is a smi trigger the slow case. |
+ ASSERT(kSmiTag == 0); |
+ __ test(object.reg(), Immediate(kSmiTagMask)); |
+ __ j(zero, &slow_case); |
+ |
+ // If the index is negative or non-smi trigger the slow case. |
+ ASSERT(kSmiTag == 0); |
+ __ test(index.reg(), Immediate(kSmiTagMask | 0x80000000)); |
+ __ j(not_zero, &slow_case); |
+ // Untag the index. |
+ __ SmiUntag(index.reg()); |
+ |
+ __ bind(&try_again_with_new_string); |
+ // Fetch the instance type of the receiver into ecx. |
+ __ mov(ecx, FieldOperand(object.reg(), HeapObject::kMapOffset)); |
+ __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
+ // If the receiver is not a string trigger the slow case. |
+ __ test(ecx, Immediate(kIsNotStringMask)); |
+ __ j(not_zero, &slow_case); |
+ |
+ // Fetch the length field into the temporary register. |
+ __ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset)); |
+ // Check for index out of range. |
+ __ cmp(index.reg(), Operand(temp.reg())); |
+ __ j(greater_equal, &slow_case); |
+ // Reload the instance type (into the temp register this time).. |
+ __ mov(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); |
+ __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
+ |
+ // We need special handling for non-flat strings. |
+ ASSERT(kSeqStringTag == 0); |
+ __ test(temp.reg(), Immediate(kStringRepresentationMask)); |
+ __ j(not_zero, ¬_a_flat_string); |
+ // Check for 1-byte or 2-byte string. |
+ __ test(temp.reg(), Immediate(kStringEncodingMask)); |
+ __ j(not_zero, &ascii_string); |
+ |
+ // 2-byte string. |
+ // Load the 2-byte character code into the temp register. |
+ __ movzx_w(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. |
+ __ movzx_b(temp.reg(), FieldOperand(object.reg(), |
+ index.reg(), |
+ times_1, |
+ SeqAsciiString::kHeaderSize)); |
+ __ bind(&got_char_code); |
+ __ SmiTag(temp.reg()); |
+ __ jmp(&end); |
+ |
+ // Handle non-flat strings. |
+ __ bind(¬_a_flat_string); |
+ __ and_(temp.reg(), kStringRepresentationMask); |
+ __ cmp(temp.reg(), 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. |
+ __ mov(temp.reg(), FieldOperand(object.reg(), ConsString::kSecondOffset)); |
+ __ cmp(Operand(temp.reg()), Factory::empty_string()); |
+ __ j(not_equal, &slow_case); |
+ // Get the first of the two strings. |
+ __ mov(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. |
- __ Set(result.reg(), Immediate(Factory::undefined_value())); |
+ __ Set(temp.reg(), Immediate(Factory::undefined_value())); |
- __ bind(&exit); |
- frame_->Push(&result); |
+ __ bind(&end); |
+ frame_->Push(&temp); |
} |
@@ -5966,22 +6058,46 @@ void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { |
ASSERT(args->length() == 1); |
Load(args->at(0)); |
- |
Result code = frame_->Pop(); |
code.ToRegister(); |
ASSERT(code.is_valid()); |
- // StringHelper::GenerateCharFromCode may do a runtime call. |
- frame_->SpillAll(); |
+ Result temp = allocator()->Allocate(); |
+ ASSERT(temp.is_valid()); |
+ |
+ JumpTarget slow_case; |
+ JumpTarget exit; |
+ |
+ // Fast case of Heap::LookupSingleCharacterStringFromCode. |
+ ASSERT(kSmiTag == 0); |
+ ASSERT(kSmiShiftSize == 0); |
+ ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
+ __ test(code.reg(), |
+ Immediate(kSmiTagMask | |
+ ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
+ slow_case.Branch(not_zero, &code, not_taken); |
+ |
+ __ Set(temp.reg(), Immediate(Factory::single_character_string_cache())); |
+ ASSERT(kSmiTag == 0); |
+ ASSERT(kSmiTagSize == 1); |
+ ASSERT(kSmiShiftSize == 0); |
+ // At this point code register contains smi tagged ascii char code. |
+ __ mov(temp.reg(), FieldOperand(temp.reg(), |
+ code.reg(), times_half_pointer_size, |
+ FixedArray::kHeaderSize)); |
+ __ cmp(temp.reg(), Factory::undefined_value()); |
+ slow_case.Branch(equal, &code, not_taken); |
+ code.Unuse(); |
- Result result = allocator()->Allocate(); |
- ASSERT(result.is_valid()); |
+ frame_->Push(&temp); |
+ exit.Jump(); |
- StringHelper::GenerateCharFromCode(masm_, |
- code.reg(), |
- result.reg(), |
- CALL_FUNCTION); |
+ slow_case.Bind(&code); |
+ frame_->Push(&code); |
+ Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1); |
frame_->Push(&result); |
+ |
+ exit.Bind(); |
} |
@@ -8406,7 +8522,7 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) { |
} |
// Check that the key is a non-negative smi. |
- __ test(key.reg(), Immediate(kSmiTagMask | kSmiSignMask)); |
+ __ test(key.reg(), Immediate(kSmiTagMask | 0x80000000)); |
deferred->Branch(not_zero); |
// Check that the receiver is not a smi. |
@@ -12038,154 +12154,6 @@ const char* CompareStub::GetName() { |
} |
-void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, |
- Register object, |
- Register index, |
- Register scratch, |
- Register result, |
- Label* receiver_not_string, |
- Label* index_not_positive_smi, |
- 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. |
- ASSERT(kSmiTag == 0); |
- __ test(object, Immediate(kSmiTagMask)); |
- __ j(zero, receiver_not_string); |
- |
- // Fetch the instance type of the receiver into result register. |
- __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); |
- __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
- // If the receiver is not a string trigger the non-string case. |
- __ test(result, Immediate(kIsNotStringMask)); |
- __ j(not_zero, receiver_not_string); |
- |
- // If the index is negative or non-smi trigger the non-positive-smi |
- // case. |
- ASSERT(kSmiTag == 0); |
- __ test(index, Immediate(kSmiTagMask | kSmiSignMask)); |
- __ j(not_zero, index_not_positive_smi); |
- |
- // Put untagged index into scratch register. |
- __ mov(scratch, index); |
- __ SmiUntag(scratch); |
- |
- // Check for index out of range. |
- __ cmp(scratch, FieldOperand(object, String::kLengthOffset)); |
- __ j(greater_equal, slow_case); |
- |
- __ bind(&try_again_with_new_string); |
- // ----------- S t a t e ------------- |
- // -- object : string to access |
- // -- result : instance type of the string |
- // -- scratch : positive smi index < length |
- // ----------------------------------- |
- |
- // We need special handling for non-flat strings. |
- ASSERT(kSeqStringTag == 0); |
- __ test(result, Immediate(kStringRepresentationMask)); |
- __ j(not_zero, ¬_a_flat_string); |
- |
- // Check for 1-byte or 2-byte string. |
- ASSERT(kAsciiStringTag != 0); |
- __ test(result, Immediate(kStringEncodingMask)); |
- __ j(not_zero, &ascii_string); |
- |
- // 2-byte string. |
- // Load the 2-byte character code into the temp register. |
- __ movzx_w(result, FieldOperand(object, |
- scratch, times_2, |
- SeqTwoByteString::kHeaderSize)); |
- __ jmp(&got_char_code); |
- |
- // Handle non-flat strings. |
- __ bind(¬_a_flat_string); |
- __ and_(result, kStringRepresentationMask); |
- __ cmp(result, kConsStringTag); |
- __ j(not_equal, 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. |
- __ mov(result, FieldOperand(object, ConsString::kSecondOffset)); |
- __ cmp(Operand(result), Factory::empty_string()); |
- __ j(not_equal, slow_case); |
- // Get the first of the two strings and load its instance type. |
- __ mov(object, FieldOperand(object, ConsString::kFirstOffset)); |
- __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); |
- __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
- __ jmp(&try_again_with_new_string); |
- |
- // ASCII string. |
- __ bind(&ascii_string); |
- // Load the byte into the temp register. |
- __ movzx_b(result, FieldOperand(object, |
- scratch, times_1, |
- SeqAsciiString::kHeaderSize)); |
- __ bind(&got_char_code); |
- __ SmiTag(result); |
-} |
- |
- |
-void StringHelper::GenerateCharFromCode(MacroAssembler* masm, |
- Register code, |
- 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)); |
- __ test(code, |
- Immediate(kSmiTagMask | |
- ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
- __ j(not_zero, &slow_case, not_taken); |
- |
- __ Set(result, Immediate(Factory::single_character_string_cache())); |
- ASSERT(kSmiTag == 0); |
- ASSERT(kSmiTagSize == 1); |
- ASSERT(kSmiShiftSize == 0); |
- // At this point code register contains smi tagged ascii char code. |
- __ mov(result, FieldOperand(result, |
- code, times_half_pointer_size, |
- FixedArray::kHeaderSize)); |
- __ cmp(result, Factory::undefined_value()); |
- __ j(equal, &slow_case, not_taken); |
- __ jmp(&exit); |
- |
- __ bind(&slow_case); |
- if (flag == CALL_FUNCTION) { |
- __ push(code); |
- __ CallRuntime(Runtime::kCharFromCode, 1); |
- if (!result.is(eax)) { |
- __ mov(result, eax); |
- } |
- } else { |
- ASSERT(flag == JUMP_FUNCTION); |
- ASSERT(result.is(eax)); |
- __ pop(eax); // Save return address. |
- __ push(code); |
- __ push(eax); // Restore return address. |
- __ TailCallRuntime(Runtime::kCharFromCode, 1, 1); |
- } |
- |
- __ bind(&exit); |
- if (flag == JUMP_FUNCTION) { |
- ASSERT(result.is(eax)); |
- __ ret(0); |
- } |
-} |
- |
- |
void StringAddStub::Generate(MacroAssembler* masm) { |
Label string_add_runtime; |
@@ -12252,8 +12220,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// 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; |
- StringHelper::GenerateTwoCharacterSymbolTableProbe( |
- masm, ebx, ecx, eax, edx, edi, &make_two_character_string); |
+ GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, |
+ &make_two_character_string); |
__ IncrementCounter(&Counters::string_add_native, 1); |
__ ret(2 * kPointerSize); |
@@ -12345,7 +12313,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// ecx: first character of result |
// edx: first char of first argument |
// edi: length of first argument |
- StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
+ GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
// Load second argument and locate first character. |
__ mov(edx, Operand(esp, 1 * kPointerSize)); |
__ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
@@ -12354,7 +12322,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// ecx: next character of result |
// edx: first char of second argument |
// edi: length of second argument |
- StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
+ GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
__ IncrementCounter(&Counters::string_add_native, 1); |
__ ret(2 * kPointerSize); |
@@ -12384,7 +12352,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// ecx: first character of result |
// edx: first char of first argument |
// edi: length of first argument |
- StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
+ GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
// Load second argument and locate first character. |
__ mov(edx, Operand(esp, 1 * kPointerSize)); |
__ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
@@ -12393,7 +12361,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
// ecx: next character of result |
// edx: first char of second argument |
// edi: length of second argument |
- StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
+ GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
__ IncrementCounter(&Counters::string_add_native, 1); |
__ ret(2 * kPointerSize); |
@@ -12403,12 +12371,12 @@ void StringAddStub::Generate(MacroAssembler* masm) { |
} |
-void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
- Register dest, |
- Register src, |
- Register count, |
- Register scratch, |
- bool ascii) { |
+void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, |
+ Register dest, |
+ Register src, |
+ Register count, |
+ Register scratch, |
+ bool ascii) { |
Label loop; |
__ bind(&loop); |
// This loop just copies one character at a time, as it is only used for very |
@@ -12429,12 +12397,12 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
} |
-void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |
- Register dest, |
- Register src, |
- Register count, |
- Register scratch, |
- bool ascii) { |
+void StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm, |
+ Register dest, |
+ Register src, |
+ Register count, |
+ Register scratch, |
+ 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. |
@@ -12489,13 +12457,13 @@ void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |
} |
-void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
- Register c1, |
- Register c2, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Label* not_found) { |
+void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
+ Register c1, |
+ Register c2, |
+ Register scratch1, |
+ Register scratch2, |
+ Register scratch3, |
+ Label* not_found) { |
// Register scratch3 is the general scratch register in this function. |
Register scratch = scratch3; |
@@ -12609,10 +12577,10 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
} |
-void StringHelper::GenerateHashInit(MacroAssembler* masm, |
- Register hash, |
- Register character, |
- Register scratch) { |
+void StringStubBase::GenerateHashInit(MacroAssembler* masm, |
+ Register hash, |
+ Register character, |
+ Register scratch) { |
// hash = character + (character << 10); |
__ mov(hash, character); |
__ shl(hash, 10); |
@@ -12624,10 +12592,10 @@ void StringHelper::GenerateHashInit(MacroAssembler* masm, |
} |
-void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, |
- Register hash, |
- Register character, |
- Register scratch) { |
+void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, |
+ Register hash, |
+ Register character, |
+ Register scratch) { |
// hash += character; |
__ add(hash, Operand(character)); |
// hash += hash << 10; |
@@ -12641,9 +12609,9 @@ void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, |
} |
-void StringHelper::GenerateHashGetHash(MacroAssembler* masm, |
- Register hash, |
- Register scratch) { |
+void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, |
+ Register hash, |
+ Register scratch) { |
// hash += hash << 3; |
__ mov(scratch, hash); |
__ shl(scratch, 3); |
@@ -12717,8 +12685,8 @@ void SubStringStub::Generate(MacroAssembler* masm) { |
// Try to lookup two character string in symbol table. |
Label make_two_character_string; |
- StringHelper::GenerateTwoCharacterSymbolTableProbe( |
- masm, ebx, ecx, eax, edx, edi, &make_two_character_string); |
+ GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, |
+ &make_two_character_string); |
__ ret(3 * kPointerSize); |
__ bind(&make_two_character_string); |
@@ -12757,7 +12725,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { |
// edx: original value of esi |
// edi: first character of result |
// esi: character of sub string start |
- StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); |
+ GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); |
__ mov(esi, edx); // Restore esi. |
__ IncrementCounter(&Counters::sub_string_native, 1); |
__ ret(3 * kPointerSize); |
@@ -12796,7 +12764,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { |
// edx: original value of esi |
// edi: first character of result |
// esi: character of sub string start |
- StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); |
+ GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); |
__ mov(esi, edx); // Restore esi. |
__ IncrementCounter(&Counters::sub_string_native, 1); |
__ ret(3 * kPointerSize); |