From e504873d2a6ccb9a9fcdf2cdf8d4db82d7c5085e Mon Sep 17 00:00:00 2001 From: "vitalyr@chromium.org" Date: Tue, 20 Apr 2010 08:27:48 +0000 Subject: [PATCH] Inline fast cases in string keyed load IC. String keyed load used to call STRING_CHAR_AT builtin that performs two steps (get a char code, construct a one-char string from the code), both of which have fast cases implemented as inline runtime functions. In this chage most of the code from these functions is extracted to a set of common generator functions in StringStubBase and the fast cases are grouped together in the IC code. Review URL: http://codereview.chromium.org/1539039 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4444 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/globals.h | 3 + src/ia32/codegen-ia32.cc | 406 +++++++++++++++++++++++++---------------------- src/ia32/codegen-ia32.h | 100 ++++++++---- src/ia32/ic-ia32.cc | 61 ++++--- 4 files changed, 328 insertions(+), 242 deletions(-) diff --git a/src/globals.h b/src/globals.h index 410cb3f..e3ef958 100644 --- a/src/globals.h +++ b/src/globals.h @@ -147,6 +147,9 @@ const int kPointerSizeLog2 = 2; const intptr_t kIntptrSignBit = 0x80000000; #endif +// Mask for the sign bit in a smi. +const intptr_t kSmiSignMask = kIntptrSignBit; + const int kObjectAlignmentBits = kPointerSizeLog2; const intptr_t kObjectAlignment = 1 << kObjectAlignmentBits; const intptr_t kObjectAlignmentMask = kObjectAlignment - 1; diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 9512886..5ab7a53 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 | 0x80000000)); + __ test(operand->reg(), Immediate(kSmiTagMask | kSmiSignMask)); deferred->Branch(not_zero); if (int_value < 0) int_value = -int_value; if (int_value == 1) { @@ -5901,7 +5901,7 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList* args) { Result value = frame_->Pop(); value.ToRegister(); ASSERT(value.is_valid()); - __ test(value.reg(), Immediate(kSmiTagMask | 0x80000000)); + __ test(value.reg(), Immediate(kSmiTagMask | kSmiSignMask)); value.Unuse(); destination()->Split(zero); } @@ -5917,43 +5917,11 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList* 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 @@ -5963,93 +5931,33 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList* args) { 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. - 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); + Label slow_case; + Label exit; + StringHelper::GenerateFastCharCodeAt(masm_, + object.reg(), + index.reg(), + scratch.reg(), + result.reg(), + &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. - __ Set(temp.reg(), Immediate(Factory::undefined_value())); + __ Set(result.reg(), Immediate(Factory::undefined_value())); - __ bind(&end); - frame_->Push(&temp); + __ bind(&exit); + frame_->Push(&result); } @@ -6058,46 +5966,22 @@ void CodeGenerator::GenerateCharFromCode(ZoneList* args) { 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. - 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(); + // StringHelper::GenerateCharFromCode may do a runtime call. + frame_->SpillAll(); - frame_->Push(&temp); - exit.Jump(); + Result result = allocator()->Allocate(); + ASSERT(result.is_valid()); - slow_case.Bind(&code); - frame_->Push(&code); - Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1); + StringHelper::GenerateCharFromCode(masm_, + code.reg(), + result.reg(), + CALL_FUNCTION); frame_->Push(&result); - - exit.Bind(); } @@ -8522,7 +8406,7 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) { } // Check that the key is a non-negative smi. - __ test(key.reg(), Immediate(kSmiTagMask | 0x80000000)); + __ test(key.reg(), Immediate(kSmiTagMask | kSmiSignMask)); deferred->Branch(not_zero); // Check that the receiver is not a smi. @@ -12154,6 +12038,154 @@ 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; @@ -12220,8 +12252,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; - GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, - &make_two_character_string); + StringHelper::GenerateTwoCharacterSymbolTableProbe( + masm, ebx, ecx, eax, edx, edi, &make_two_character_string); __ IncrementCounter(&Counters::string_add_native, 1); __ ret(2 * kPointerSize); @@ -12313,7 +12345,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { // ecx: first character of result // edx: first char of first argument // edi: length of first argument - GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); + StringHelper::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)); @@ -12322,7 +12354,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { // ecx: next character of result // edx: first char of second argument // edi: length of second argument - GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); + StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); __ IncrementCounter(&Counters::string_add_native, 1); __ ret(2 * kPointerSize); @@ -12352,7 +12384,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { // ecx: first character of result // edx: first char of first argument // edi: length of first argument - GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); + StringHelper::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)); @@ -12361,7 +12393,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { // ecx: next character of result // edx: first char of second argument // edi: length of second argument - GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); + StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); __ IncrementCounter(&Counters::string_add_native, 1); __ ret(2 * kPointerSize); @@ -12371,12 +12403,12 @@ void StringAddStub::Generate(MacroAssembler* masm) { } -void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii) { +void StringHelper::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 @@ -12397,12 +12429,12 @@ void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, } -void StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii) { +void StringHelper::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. @@ -12457,13 +12489,13 @@ void StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm, } -void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Label* not_found) { +void StringHelper::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; @@ -12577,10 +12609,10 @@ void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, } -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); __ mov(hash, character); __ shl(hash, 10); @@ -12592,10 +12624,10 @@ void StringStubBase::GenerateHashInit(MacroAssembler* masm, } -void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, - Register hash, - Register character, - Register scratch) { +void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, + Register hash, + Register character, + Register scratch) { // hash += character; __ add(hash, Operand(character)); // hash += hash << 10; @@ -12609,9 +12641,9 @@ void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, } -void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, - Register hash, - Register scratch) { +void StringHelper::GenerateHashGetHash(MacroAssembler* masm, + Register hash, + Register scratch) { // hash += hash << 3; __ mov(scratch, hash); __ shl(scratch, 3); @@ -12685,8 +12717,8 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Try to lookup two character string in symbol table. Label make_two_character_string; - GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, - &make_two_character_string); + StringHelper::GenerateTwoCharacterSymbolTableProbe( + masm, ebx, ecx, eax, edx, edi, &make_two_character_string); __ ret(3 * kPointerSize); __ bind(&make_two_character_string); @@ -12725,7 +12757,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // edx: original value of esi // edi: first character of result // esi: character of sub string start - GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); + StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); __ mov(esi, edx); // Restore esi. __ IncrementCounter(&Counters::sub_string_native, 1); __ ret(3 * kPointerSize); @@ -12764,7 +12796,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // edx: original value of esi // edi: first character of result // esi: character of sub string start - GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); + StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); __ mov(esi, edx); // Restore esi. __ IncrementCounter(&Counters::sub_string_native, 1); __ ret(3 * kPointerSize); diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h index c7cad14..b3db0c4 100644 --- a/src/ia32/codegen-ia32.h +++ b/src/ia32/codegen-ia32.h @@ -883,53 +883,85 @@ class GenericBinaryOpStub: public CodeStub { }; -class StringStubBase: public CodeStub { +class StringHelper : public AllStatic { public: + // Generates fast code for getting a char code out of a string + // object at the given index. May bail out for three reasons (in the + // listed order): + // * Receiver is not a string (receiver_not_string label). + // * Index is not a positive smi (index_not_positive_smi label). + // * 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 positive smi. + // 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_positive_smi, + 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 eax register. + static void GenerateCharFromCode(MacroAssembler* masm, + Register code, + Register result, + InvokeFlag flag); + // 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 // additional setup and checking in GenerateCopyCharactersREP adds too much // overhead. Copying of overlapping regions is not supported. - void GenerateCopyCharacters(MacroAssembler* masm, - Register dest, - Register src, - Register count, - Register scratch, - bool ascii); + static void GenerateCopyCharacters(MacroAssembler* masm, + Register dest, + Register src, + Register count, + Register scratch, + bool ascii); // Generate code for copying characters using the rep movs instruction. // Copies ecx characters from esi to edi. Copying of overlapping regions is // not supported. - void GenerateCopyCharactersREP(MacroAssembler* masm, - Register dest, // Must be edi. - Register src, // Must be esi. - Register count, // Must be ecx. - Register scratch, // Neither of the above. - bool ascii); + static void GenerateCopyCharactersREP(MacroAssembler* masm, + Register dest, // Must be edi. + Register src, // Must be esi. + Register count, // Must be ecx. + Register scratch, // Neither of above. + bool ascii); // Probe the symbol table for a two character string. If the string is // not found by probing a jump to the label not_found is performed. This jump // 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 eax. - void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, - Register c1, - Register c2, - Register scratch1, - Register scratch2, - Register scratch3, - Label* not_found); + static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, + Register c1, + Register c2, + Register scratch1, + Register scratch2, + Register scratch3, + Label* not_found); // Generate string hash. - void GenerateHashInit(MacroAssembler* masm, - Register hash, - Register character, - Register scratch); - void GenerateHashAddCharacter(MacroAssembler* masm, - Register hash, - Register character, - Register scratch); - void GenerateHashGetHash(MacroAssembler* masm, - Register hash, - Register scratch); + static void GenerateHashInit(MacroAssembler* masm, + Register hash, + Register character, + Register scratch); + static void GenerateHashAddCharacter(MacroAssembler* masm, + Register hash, + Register character, + Register scratch); + static void GenerateHashGetHash(MacroAssembler* masm, + Register hash, + Register scratch); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); }; @@ -940,7 +972,7 @@ enum StringAddFlags { }; -class StringAddStub: public StringStubBase { +class StringAddStub: public CodeStub { public: explicit StringAddStub(StringAddFlags flags) { string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); @@ -957,7 +989,7 @@ class StringAddStub: public StringStubBase { }; -class SubStringStub: public StringStubBase { +class SubStringStub: public CodeStub { public: SubStringStub() {} @@ -969,7 +1001,7 @@ class SubStringStub: public StringStubBase { }; -class StringCompareStub: public StringStubBase { +class StringCompareStub: public CodeStub { public: explicit StringCompareStub() { } diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index cf521a2..f07018a 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -491,39 +491,58 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { void KeyedLoadIC::GenerateString(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key + // -- eax : key (index) // -- edx : receiver // -- esp[0] : return address // ----------------------------------- - Label miss, index_ok; - - // Pop return address. - // Performing the load early is better in the common case. - __ pop(ebx); + Label miss; + Label not_positive_smi; + Label slow_char_code; + Label got_char_code; - __ test(edx, Immediate(kSmiTagMask)); - __ j(zero, &miss); - __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); - __ test(ecx, Immediate(kIsNotStringMask)); - __ j(not_zero, &miss); + Register receiver = edx; + Register index = eax; + Register code = ebx; + Register scratch = ecx; + + StringHelper::GenerateFastCharCodeAt(masm, + receiver, + index, + scratch, + code, + &miss, // When not a string. + ¬_positive_smi, + &slow_char_code); + // If we didn't bail out, code register contains smi tagged char + // code. + __ bind(&got_char_code); + StringHelper::GenerateCharFromCode(masm, code, eax, JUMP_FUNCTION); +#ifdef DEBUG + __ Abort("Unexpected fall-through from char from code tail call"); +#endif // Check if key is a smi or a heap number. - __ test(eax, Immediate(kSmiTagMask)); - __ j(zero, &index_ok); + __ bind(¬_positive_smi); + ASSERT(kSmiTag == 0); + __ test(index, Immediate(kSmiTagMask)); + __ j(zero, &slow_char_code); __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); __ cmp(ecx, Factory::heap_number_map()); __ j(not_equal, &miss); - __ bind(&index_ok); - // Push receiver and key on the stack, and make a tail call. - __ push(edx); // receiver - __ push(eax); // key - __ push(ebx); // return address - __ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION); + // 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(receiver); + __ push(index); + __ CallRuntime(Runtime::kStringCharCodeAt, 1); + ASSERT(!code.is(eax)); + __ mov(code, eax); + __ LeaveInternalFrame(); + __ jmp(&got_char_code); __ bind(&miss); - __ push(ebx); GenerateMiss(masm); } -- 2.7.4