| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 3932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3943 | 3943 |
| 3944 // Generates the Math.sqrt method - currently just calls runtime. | 3944 // Generates the Math.sqrt method - currently just calls runtime. |
| 3945 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { | 3945 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
| 3946 ASSERT(args->length() == 1); | 3946 ASSERT(args->length() == 1); |
| 3947 Load(args->at(0)); | 3947 Load(args->at(0)); |
| 3948 frame_->CallRuntime(Runtime::kMath_sqrt, 1); | 3948 frame_->CallRuntime(Runtime::kMath_sqrt, 1); |
| 3949 frame_->EmitPush(r0); | 3949 frame_->EmitPush(r0); |
| 3950 } | 3950 } |
| 3951 | 3951 |
| 3952 | 3952 |
| 3953 // This should generate code that performs a charCodeAt() call or returns | 3953 // This generates code that performs a charCodeAt() call or returns |
| 3954 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3954 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 3955 // It is not yet implemented on ARM, so it always goes to the slow case. | 3955 // It can handle flat, 8 and 16 bit characters and cons strings where the |
| 3956 // answer is found in the left hand branch of the cons. The slow case will |
| 3957 // flatten the string, which will ensure that the answer is in the left hand |
| 3958 // side the next time around. |
| 3956 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3959 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 3957 VirtualFrame::SpilledScope spilled_scope(frame_); | 3960 VirtualFrame::SpilledScope spilled_scope(frame_); |
| 3958 ASSERT(args->length() == 2); | 3961 ASSERT(args->length() == 2); |
| 3959 Comment(masm_, "[ GenerateFastCharCodeAt"); | 3962 Comment(masm_, "[ GenerateFastCharCodeAt"); |
| 3960 | 3963 |
| 3961 LoadAndSpill(args->at(0)); | 3964 LoadAndSpill(args->at(0)); |
| 3962 LoadAndSpill(args->at(1)); | 3965 LoadAndSpill(args->at(1)); |
| 3963 frame_->EmitPop(r0); // Index. | 3966 frame_->EmitPop(r1); // Index. |
| 3964 frame_->EmitPop(r1); // String. | 3967 frame_->EmitPop(r2); // String. |
| 3965 | 3968 |
| 3966 Label slow, end, not_a_flat_string, ascii_string, try_again_with_new_string; | 3969 Label slow_case; |
| 3970 Label exit; |
| 3971 StringHelper::GenerateFastCharCodeAt(masm_, |
| 3972 r2, |
| 3973 r1, |
| 3974 r3, |
| 3975 r0, |
| 3976 &slow_case, |
| 3977 &slow_case, |
| 3978 &slow_case, |
| 3979 &slow_case); |
| 3980 __ jmp(&exit); |
| 3967 | 3981 |
| 3968 __ tst(r1, Operand(kSmiTagMask)); | 3982 __ bind(&slow_case); |
| 3969 __ b(eq, &slow); // The 'string' was a Smi. | 3983 // Move the undefined value into the result register, which will |
| 3970 | 3984 // trigger the slow case. |
| 3971 ASSERT(kSmiTag == 0); | |
| 3972 __ tst(r0, Operand(kSmiTagMask | 0x80000000u)); | |
| 3973 __ b(ne, &slow); // The index was negative or not a Smi. | |
| 3974 | |
| 3975 __ bind(&try_again_with_new_string); | |
| 3976 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE); | |
| 3977 __ b(ge, &slow); | |
| 3978 | |
| 3979 // Now r2 has the string type. | |
| 3980 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset)); | |
| 3981 // Now r3 has the length of the string. Compare with the index. | |
| 3982 __ cmp(r3, Operand(r0, LSR, kSmiTagSize)); | |
| 3983 __ b(le, &slow); | |
| 3984 | |
| 3985 // Here we know the index is in range. Check that string is sequential. | |
| 3986 ASSERT_EQ(0, kSeqStringTag); | |
| 3987 __ tst(r2, Operand(kStringRepresentationMask)); | |
| 3988 __ b(ne, ¬_a_flat_string); | |
| 3989 | |
| 3990 // Check whether it is an ASCII string. | |
| 3991 ASSERT_EQ(0, kTwoByteStringTag); | |
| 3992 __ tst(r2, Operand(kStringEncodingMask)); | |
| 3993 __ b(ne, &ascii_string); | |
| 3994 | |
| 3995 // 2-byte string. We can add without shifting since the Smi tag size is the | |
| 3996 // log2 of the number of bytes in a two-byte character. | |
| 3997 ASSERT_EQ(1, kSmiTagSize); | |
| 3998 ASSERT_EQ(0, kSmiShiftSize); | |
| 3999 __ add(r1, r1, Operand(r0)); | |
| 4000 __ ldrh(r0, FieldMemOperand(r1, SeqTwoByteString::kHeaderSize)); | |
| 4001 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | |
| 4002 __ jmp(&end); | |
| 4003 | |
| 4004 __ bind(&ascii_string); | |
| 4005 __ add(r1, r1, Operand(r0, LSR, kSmiTagSize)); | |
| 4006 __ ldrb(r0, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); | |
| 4007 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | |
| 4008 __ jmp(&end); | |
| 4009 | |
| 4010 __ bind(¬_a_flat_string); | |
| 4011 __ and_(r2, r2, Operand(kStringRepresentationMask)); | |
| 4012 __ cmp(r2, Operand(kConsStringTag)); | |
| 4013 __ b(ne, &slow); | |
| 4014 | |
| 4015 // ConsString. | |
| 4016 // Check that the right hand side is the empty string (ie if this is really a | |
| 4017 // flat string in a cons string). If that is not the case we would rather go | |
| 4018 // to the runtime system now, to flatten the string. | |
| 4019 __ ldr(r2, FieldMemOperand(r1, ConsString::kSecondOffset)); | |
| 4020 __ LoadRoot(r3, Heap::kEmptyStringRootIndex); | |
| 4021 __ cmp(r2, Operand(r3)); | |
| 4022 __ b(ne, &slow); | |
| 4023 | |
| 4024 // Get the first of the two strings. | |
| 4025 __ ldr(r1, FieldMemOperand(r1, ConsString::kFirstOffset)); | |
| 4026 __ jmp(&try_again_with_new_string); | |
| 4027 | |
| 4028 __ bind(&slow); | |
| 4029 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 3985 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 4030 | 3986 |
| 4031 __ bind(&end); | 3987 __ bind(&exit); |
| 4032 frame_->EmitPush(r0); | 3988 frame_->EmitPush(r0); |
| 4033 } | 3989 } |
| 4034 | 3990 |
| 4035 | 3991 |
| 4036 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { | 3992 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { |
| 4037 Comment(masm_, "[ GenerateCharFromCode"); | 3993 Comment(masm_, "[ GenerateCharFromCode"); |
| 4038 ASSERT(args->length() == 1); | 3994 ASSERT(args->length() == 1); |
| 4039 | 3995 |
| 3996 Register code = r1; |
| 3997 Register scratch = ip; |
| 3998 Register result = r0; |
| 3999 |
| 4040 LoadAndSpill(args->at(0)); | 4000 LoadAndSpill(args->at(0)); |
| 4041 frame_->EmitPop(r0); | 4001 frame_->EmitPop(code); |
| 4042 | 4002 |
| 4043 JumpTarget slow_case; | 4003 StringHelper::GenerateCharFromCode(masm_, |
| 4044 JumpTarget exit; | 4004 code, |
| 4045 | 4005 scratch, |
| 4046 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 4006 result, |
| 4047 ASSERT(kSmiTag == 0); | 4007 CALL_FUNCTION); |
| 4048 ASSERT(kSmiShiftSize == 0); | 4008 frame_->EmitPush(result); |
| 4049 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); | |
| 4050 __ tst(r0, Operand(kSmiTagMask | | |
| 4051 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); | |
| 4052 slow_case.Branch(nz); | |
| 4053 | |
| 4054 ASSERT(kSmiTag == 0); | |
| 4055 __ mov(r1, Operand(Factory::single_character_string_cache())); | |
| 4056 __ add(r1, r1, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); | |
| 4057 __ ldr(r1, MemOperand(r1, FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 4058 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | |
| 4059 __ cmp(r1, ip); | |
| 4060 slow_case.Branch(eq); | |
| 4061 | |
| 4062 frame_->EmitPush(r1); | |
| 4063 exit.Jump(); | |
| 4064 | |
| 4065 slow_case.Bind(); | |
| 4066 frame_->EmitPush(r0); | |
| 4067 frame_->CallRuntime(Runtime::kCharFromCode, 1); | |
| 4068 frame_->EmitPush(r0); | |
| 4069 | |
| 4070 exit.Bind(); | |
| 4071 } | 4009 } |
| 4072 | 4010 |
| 4073 | 4011 |
| 4074 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 4012 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 4075 VirtualFrame::SpilledScope spilled_scope(frame_); | 4013 VirtualFrame::SpilledScope spilled_scope(frame_); |
| 4076 ASSERT(args->length() == 1); | 4014 ASSERT(args->length() == 1); |
| 4077 LoadAndSpill(args->at(0)); | 4015 LoadAndSpill(args->at(0)); |
| 4078 JumpTarget answer; | 4016 JumpTarget answer; |
| 4079 // We need the CC bits to come out as not_equal in the case where the | 4017 // We need the CC bits to come out as not_equal in the case where the |
| 4080 // object is a smi. This can't be done with the usual test opcode so | 4018 // object is a smi. This can't be done with the usual test opcode so |
| (...skipping 4662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8743 // stubs the never NaN NaN condition is only taken into account if the | 8681 // stubs the never NaN NaN condition is only taken into account if the |
| 8744 // condition is equals. | 8682 // condition is equals. |
| 8745 ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 13)); | 8683 ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 13)); |
| 8746 return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) | 8684 return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) |
| 8747 | StrictField::encode(strict_) | 8685 | StrictField::encode(strict_) |
| 8748 | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) | 8686 | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) |
| 8749 | IncludeNumberCompareField::encode(include_number_compare_); | 8687 | IncludeNumberCompareField::encode(include_number_compare_); |
| 8750 } | 8688 } |
| 8751 | 8689 |
| 8752 | 8690 |
| 8753 void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, | 8691 void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, |
| 8754 Register dest, | 8692 Register object, |
| 8755 Register src, | 8693 Register index, |
| 8756 Register count, | 8694 Register scratch, |
| 8757 Register scratch, | 8695 Register result, |
| 8758 bool ascii) { | 8696 Label* receiver_not_string, |
| 8697 Label* index_not_smi, |
| 8698 Label* index_out_of_range, |
| 8699 Label* slow_case) { |
| 8700 Label not_a_flat_string; |
| 8701 Label try_again_with_new_string; |
| 8702 Label ascii_string; |
| 8703 Label got_char_code; |
| 8704 |
| 8705 // If the receiver is a smi trigger the non-string case. |
| 8706 __ BranchOnSmi(object, receiver_not_string); |
| 8707 |
| 8708 // Fetch the instance type of the receiver into result register. |
| 8709 __ ldr(result, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 8710 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| 8711 // If the receiver is not a string trigger the non-string case. |
| 8712 __ tst(result, Operand(kIsNotStringMask)); |
| 8713 __ b(ne, receiver_not_string); |
| 8714 |
| 8715 // If the index is non-smi trigger the non-smi case. |
| 8716 __ BranchOnNotSmi(index, index_not_smi); |
| 8717 |
| 8718 // Check for index out of range. |
| 8719 __ ldr(scratch, FieldMemOperand(object, String::kLengthOffset)); |
| 8720 // Now scratch has the length of the string. Compare with the index. |
| 8721 __ cmp(scratch, Operand(index, LSR, kSmiTagSize)); |
| 8722 __ b(ls, index_out_of_range); |
| 8723 |
| 8724 __ bind(&try_again_with_new_string); |
| 8725 // ----------- S t a t e ------------- |
| 8726 // -- object : string to access |
| 8727 // -- result : instance type of the string |
| 8728 // -- scratch : non-negative index < length |
| 8729 // ----------------------------------- |
| 8730 |
| 8731 // We need special handling for non-flat strings. |
| 8732 ASSERT_EQ(0, kSeqStringTag); |
| 8733 __ tst(result, Operand(kStringRepresentationMask)); |
| 8734 __ b(ne, ¬_a_flat_string); |
| 8735 |
| 8736 // Check for 1-byte or 2-byte string. |
| 8737 ASSERT_EQ(0, kTwoByteStringTag); |
| 8738 __ tst(result, Operand(kStringEncodingMask)); |
| 8739 __ b(ne, &ascii_string); |
| 8740 |
| 8741 // 2-byte string. We can add without shifting since the Smi tag size is the |
| 8742 // log2 of the number of bytes in a two-byte character. |
| 8743 ASSERT_EQ(1, kSmiTagSize); |
| 8744 ASSERT_EQ(0, kSmiShiftSize); |
| 8745 __ add(scratch, object, Operand(index)); |
| 8746 __ ldrh(result, FieldMemOperand(scratch, SeqTwoByteString::kHeaderSize)); |
| 8747 __ jmp(&got_char_code); |
| 8748 |
| 8749 // Handle non-flat strings. |
| 8750 __ bind(¬_a_flat_string); |
| 8751 __ and_(result, result, Operand(kStringRepresentationMask)); |
| 8752 __ cmp(result, Operand(kConsStringTag)); |
| 8753 __ b(ne, slow_case); |
| 8754 |
| 8755 // ConsString. |
| 8756 // Check whether the right hand side is the empty string (i.e. if |
| 8757 // this is really a flat string in a cons string). If that is not |
| 8758 // the case we would rather go to the runtime system now to flatten |
| 8759 // the string. |
| 8760 __ ldr(result, FieldMemOperand(object, ConsString::kSecondOffset)); |
| 8761 __ LoadRoot(scratch, Heap::kEmptyStringRootIndex); |
| 8762 __ cmp(result, Operand(scratch)); |
| 8763 __ b(ne, slow_case); |
| 8764 |
| 8765 // Get the first of the two strings and load its instance type. |
| 8766 __ ldr(object, FieldMemOperand(object, ConsString::kFirstOffset)); |
| 8767 __ ldr(result, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 8768 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| 8769 __ jmp(&try_again_with_new_string); |
| 8770 |
| 8771 // ASCII string. |
| 8772 __ bind(&ascii_string); |
| 8773 __ add(scratch, object, Operand(index, LSR, kSmiTagSize)); |
| 8774 __ ldrb(result, FieldMemOperand(scratch, SeqAsciiString::kHeaderSize)); |
| 8775 |
| 8776 __ bind(&got_char_code); |
| 8777 __ mov(result, Operand(result, LSL, kSmiTagSize)); |
| 8778 } |
| 8779 |
| 8780 |
| 8781 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, |
| 8782 Register code, |
| 8783 Register scratch, |
| 8784 Register result, |
| 8785 InvokeFlag flag) { |
| 8786 ASSERT(!code.is(result)); |
| 8787 |
| 8788 Label slow_case; |
| 8789 Label exit; |
| 8790 |
| 8791 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 8792 ASSERT(kSmiTag == 0); |
| 8793 ASSERT(kSmiShiftSize == 0); |
| 8794 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
| 8795 __ tst(code, Operand(kSmiTagMask | |
| 8796 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
| 8797 __ b(nz, &slow_case); |
| 8798 |
| 8799 ASSERT(kSmiTag == 0); |
| 8800 __ mov(result, Operand(Factory::single_character_string_cache())); |
| 8801 __ add(result, result, Operand(code, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 8802 __ ldr(result, MemOperand(result, FixedArray::kHeaderSize - kHeapObjectTag)); |
| 8803 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); |
| 8804 __ cmp(result, scratch); |
| 8805 __ b(eq, &slow_case); |
| 8806 __ b(&exit); |
| 8807 |
| 8808 __ bind(&slow_case); |
| 8809 if (flag == CALL_FUNCTION) { |
| 8810 __ push(code); |
| 8811 __ CallRuntime(Runtime::kCharFromCode, 1); |
| 8812 if (!result.is(r0)) { |
| 8813 __ mov(result, r0); |
| 8814 } |
| 8815 } else { |
| 8816 ASSERT(flag == JUMP_FUNCTION); |
| 8817 ASSERT(result.is(r0)); |
| 8818 __ push(code); |
| 8819 __ TailCallRuntime(Runtime::kCharFromCode, 1, 1); |
| 8820 } |
| 8821 |
| 8822 __ bind(&exit); |
| 8823 if (flag == JUMP_FUNCTION) { |
| 8824 ASSERT(result.is(r0)); |
| 8825 __ Ret(); |
| 8826 } |
| 8827 } |
| 8828 |
| 8829 |
| 8830 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
| 8831 Register dest, |
| 8832 Register src, |
| 8833 Register count, |
| 8834 Register scratch, |
| 8835 bool ascii) { |
| 8759 Label loop; | 8836 Label loop; |
| 8760 Label done; | 8837 Label done; |
| 8761 // This loop just copies one character at a time, as it is only used for very | 8838 // This loop just copies one character at a time, as it is only used for very |
| 8762 // short strings. | 8839 // short strings. |
| 8763 if (!ascii) { | 8840 if (!ascii) { |
| 8764 __ add(count, count, Operand(count), SetCC); | 8841 __ add(count, count, Operand(count), SetCC); |
| 8765 } else { | 8842 } else { |
| 8766 __ cmp(count, Operand(0)); | 8843 __ cmp(count, Operand(0)); |
| 8767 } | 8844 } |
| 8768 __ b(eq, &done); | 8845 __ b(eq, &done); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 8779 __ bind(&done); | 8856 __ bind(&done); |
| 8780 } | 8857 } |
| 8781 | 8858 |
| 8782 | 8859 |
| 8783 enum CopyCharactersFlags { | 8860 enum CopyCharactersFlags { |
| 8784 COPY_ASCII = 1, | 8861 COPY_ASCII = 1, |
| 8785 DEST_ALWAYS_ALIGNED = 2 | 8862 DEST_ALWAYS_ALIGNED = 2 |
| 8786 }; | 8863 }; |
| 8787 | 8864 |
| 8788 | 8865 |
| 8789 void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm, | 8866 void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, |
| 8790 Register dest, | 8867 Register dest, |
| 8791 Register src, | 8868 Register src, |
| 8792 Register count, | 8869 Register count, |
| 8793 Register scratch1, | 8870 Register scratch1, |
| 8794 Register scratch2, | 8871 Register scratch2, |
| 8795 Register scratch3, | 8872 Register scratch3, |
| 8796 Register scratch4, | 8873 Register scratch4, |
| 8797 Register scratch5, | 8874 Register scratch5, |
| 8798 int flags) { | 8875 int flags) { |
| 8799 bool ascii = (flags & COPY_ASCII) != 0; | 8876 bool ascii = (flags & COPY_ASCII) != 0; |
| 8800 bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0; | 8877 bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0; |
| 8801 | 8878 |
| 8802 if (dest_always_aligned && FLAG_debug_code) { | 8879 if (dest_always_aligned && FLAG_debug_code) { |
| 8803 // Check that destination is actually word aligned if the flag says | 8880 // Check that destination is actually word aligned if the flag says |
| 8804 // that it is. | 8881 // that it is. |
| 8805 __ tst(dest, Operand(kPointerAlignmentMask)); | 8882 __ tst(dest, Operand(kPointerAlignmentMask)); |
| 8806 __ Check(eq, "Destination of copy not aligned."); | 8883 __ Check(eq, "Destination of copy not aligned."); |
| 8807 } | 8884 } |
| 8808 | 8885 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8922 __ cmp(dest, Operand(limit)); | 8999 __ cmp(dest, Operand(limit)); |
| 8923 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); | 9000 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); |
| 8924 __ b(ge, &done); | 9001 __ b(ge, &done); |
| 8925 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); | 9002 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); |
| 8926 __ b(&byte_loop); | 9003 __ b(&byte_loop); |
| 8927 | 9004 |
| 8928 __ bind(&done); | 9005 __ bind(&done); |
| 8929 } | 9006 } |
| 8930 | 9007 |
| 8931 | 9008 |
| 8932 void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, | 9009 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
| 8933 Register c1, | 9010 Register c1, |
| 8934 Register c2, | 9011 Register c2, |
| 8935 Register scratch1, | 9012 Register scratch1, |
| 8936 Register scratch2, | 9013 Register scratch2, |
| 8937 Register scratch3, | 9014 Register scratch3, |
| 8938 Register scratch4, | 9015 Register scratch4, |
| 8939 Register scratch5, | 9016 Register scratch5, |
| 8940 Label* not_found) { | 9017 Label* not_found) { |
| 8941 // Register scratch3 is the general scratch register in this function. | 9018 // Register scratch3 is the general scratch register in this function. |
| 8942 Register scratch = scratch3; | 9019 Register scratch = scratch3; |
| 8943 | 9020 |
| 8944 // Make sure that both characters are not digits as such strings has a | 9021 // Make sure that both characters are not digits as such strings has a |
| 8945 // different hash algorithm. Don't try to look for these in the symbol table. | 9022 // different hash algorithm. Don't try to look for these in the symbol table. |
| 8946 Label not_array_index; | 9023 Label not_array_index; |
| 8947 __ sub(scratch, c1, Operand(static_cast<int>('0'))); | 9024 __ sub(scratch, c1, Operand(static_cast<int>('0'))); |
| 8948 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); | 9025 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); |
| 8949 __ b(hi, ¬_array_index); | 9026 __ b(hi, ¬_array_index); |
| 8950 __ sub(scratch, c2, Operand(static_cast<int>('0'))); | 9027 __ sub(scratch, c2, Operand(static_cast<int>('0'))); |
| 8951 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); | 9028 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); |
| 8952 | 9029 |
| 8953 // If check failed combine both characters into single halfword. | 9030 // If check failed combine both characters into single halfword. |
| 8954 // This is required by the contract of the method: code at the | 9031 // This is required by the contract of the method: code at the |
| 8955 // not_found branch expects this combination in c1 register | 9032 // not_found branch expects this combination in c1 register |
| 8956 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls); | 9033 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls); |
| 8957 __ b(ls, not_found); | 9034 __ b(ls, not_found); |
| 8958 | 9035 |
| 8959 __ bind(¬_array_index); | 9036 __ bind(¬_array_index); |
| 8960 // Calculate the two character string hash. | 9037 // Calculate the two character string hash. |
| 8961 Register hash = scratch1; | 9038 Register hash = scratch1; |
| 8962 GenerateHashInit(masm, hash, c1); | 9039 StringHelper::GenerateHashInit(masm, hash, c1); |
| 8963 GenerateHashAddCharacter(masm, hash, c2); | 9040 StringHelper::GenerateHashAddCharacter(masm, hash, c2); |
| 8964 GenerateHashGetHash(masm, hash); | 9041 StringHelper::GenerateHashGetHash(masm, hash); |
| 8965 | 9042 |
| 8966 // Collect the two characters in a register. | 9043 // Collect the two characters in a register. |
| 8967 Register chars = c1; | 9044 Register chars = c1; |
| 8968 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte)); | 9045 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte)); |
| 8969 | 9046 |
| 8970 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | 9047 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 8971 // hash: hash of two character string. | 9048 // hash: hash of two character string. |
| 8972 | 9049 |
| 8973 // Load symbol table | 9050 // Load symbol table |
| 8974 // Load address of first element of the symbol table. | 9051 // Load address of first element of the symbol table. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9048 // No matching 2 character string found by probing. | 9125 // No matching 2 character string found by probing. |
| 9049 __ jmp(not_found); | 9126 __ jmp(not_found); |
| 9050 | 9127 |
| 9051 // Scratch register contains result when we fall through to here. | 9128 // Scratch register contains result when we fall through to here. |
| 9052 Register result = scratch; | 9129 Register result = scratch; |
| 9053 __ bind(&found_in_symbol_table); | 9130 __ bind(&found_in_symbol_table); |
| 9054 __ Move(r0, result); | 9131 __ Move(r0, result); |
| 9055 } | 9132 } |
| 9056 | 9133 |
| 9057 | 9134 |
| 9058 void StringStubBase::GenerateHashInit(MacroAssembler* masm, | 9135 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
| 9059 Register hash, | 9136 Register hash, |
| 9060 Register character) { | 9137 Register character) { |
| 9061 // hash = character + (character << 10); | 9138 // hash = character + (character << 10); |
| 9062 __ add(hash, character, Operand(character, LSL, 10)); | 9139 __ add(hash, character, Operand(character, LSL, 10)); |
| 9063 // hash ^= hash >> 6; | 9140 // hash ^= hash >> 6; |
| 9064 __ eor(hash, hash, Operand(hash, ASR, 6)); | 9141 __ eor(hash, hash, Operand(hash, ASR, 6)); |
| 9065 } | 9142 } |
| 9066 | 9143 |
| 9067 | 9144 |
| 9068 void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, | 9145 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, |
| 9069 Register hash, | 9146 Register hash, |
| 9070 Register character) { | 9147 Register character) { |
| 9071 // hash += character; | 9148 // hash += character; |
| 9072 __ add(hash, hash, Operand(character)); | 9149 __ add(hash, hash, Operand(character)); |
| 9073 // hash += hash << 10; | 9150 // hash += hash << 10; |
| 9074 __ add(hash, hash, Operand(hash, LSL, 10)); | 9151 __ add(hash, hash, Operand(hash, LSL, 10)); |
| 9075 // hash ^= hash >> 6; | 9152 // hash ^= hash >> 6; |
| 9076 __ eor(hash, hash, Operand(hash, ASR, 6)); | 9153 __ eor(hash, hash, Operand(hash, ASR, 6)); |
| 9077 } | 9154 } |
| 9078 | 9155 |
| 9079 | 9156 |
| 9080 void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, | 9157 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, |
| 9081 Register hash) { | 9158 Register hash) { |
| 9082 // hash += hash << 3; | 9159 // hash += hash << 3; |
| 9083 __ add(hash, hash, Operand(hash, LSL, 3)); | 9160 __ add(hash, hash, Operand(hash, LSL, 3)); |
| 9084 // hash ^= hash >> 11; | 9161 // hash ^= hash >> 11; |
| 9085 __ eor(hash, hash, Operand(hash, ASR, 11)); | 9162 __ eor(hash, hash, Operand(hash, ASR, 11)); |
| 9086 // hash += hash << 15; | 9163 // hash += hash << 15; |
| 9087 __ add(hash, hash, Operand(hash, LSL, 15), SetCC); | 9164 __ add(hash, hash, Operand(hash, LSL, 15), SetCC); |
| 9088 | 9165 |
| 9089 // if (hash == 0) hash = 27; | 9166 // if (hash == 0) hash = 27; |
| 9090 __ mov(hash, Operand(27), LeaveCC, nz); | 9167 __ mov(hash, Operand(27), LeaveCC, nz); |
| 9091 } | 9168 } |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9198 __ b(gt, &result_longer_than_two); | 9275 __ b(gt, &result_longer_than_two); |
| 9199 | 9276 |
| 9200 // Sub string of length 2 requested. | 9277 // Sub string of length 2 requested. |
| 9201 // Get the two characters forming the sub string. | 9278 // Get the two characters forming the sub string. |
| 9202 __ add(r5, r5, Operand(r3)); | 9279 __ add(r5, r5, Operand(r3)); |
| 9203 __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); | 9280 __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); |
| 9204 __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1)); | 9281 __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1)); |
| 9205 | 9282 |
| 9206 // Try to lookup two character string in symbol table. | 9283 // Try to lookup two character string in symbol table. |
| 9207 Label make_two_character_string; | 9284 Label make_two_character_string; |
| 9208 GenerateTwoCharacterSymbolTableProbe(masm, r3, r4, r1, r5, r6, r7, r9, | 9285 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
| 9209 &make_two_character_string); | 9286 masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string); |
| 9210 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 9287 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| 9211 __ add(sp, sp, Operand(3 * kPointerSize)); | 9288 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 9212 __ Ret(); | 9289 __ Ret(); |
| 9213 | 9290 |
| 9214 // r2: result string length. | 9291 // r2: result string length. |
| 9215 // r3: two characters combined into halfword in little endian byte order. | 9292 // r3: two characters combined into halfword in little endian byte order. |
| 9216 __ bind(&make_two_character_string); | 9293 __ bind(&make_two_character_string); |
| 9217 __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); | 9294 __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); |
| 9218 __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); | 9295 __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 9219 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 9296 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 9233 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9310 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 9234 // Locate 'from' character of string. | 9311 // Locate 'from' character of string. |
| 9235 __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9312 __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 9236 __ add(r5, r5, Operand(r6, ASR, 1)); | 9313 __ add(r5, r5, Operand(r6, ASR, 1)); |
| 9237 | 9314 |
| 9238 // r0: result string. | 9315 // r0: result string. |
| 9239 // r1: first character of result string. | 9316 // r1: first character of result string. |
| 9240 // r2: result string length. | 9317 // r2: result string length. |
| 9241 // r5: first character of sub string to copy. | 9318 // r5: first character of sub string to copy. |
| 9242 ASSERT_EQ(0, SeqAsciiString::kHeaderSize & kObjectAlignmentMask); | 9319 ASSERT_EQ(0, SeqAsciiString::kHeaderSize & kObjectAlignmentMask); |
| 9243 GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, | 9320 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
| 9244 COPY_ASCII | DEST_ALWAYS_ALIGNED); | 9321 COPY_ASCII | DEST_ALWAYS_ALIGNED); |
| 9245 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 9322 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| 9246 __ add(sp, sp, Operand(3 * kPointerSize)); | 9323 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 9247 __ Ret(); | 9324 __ Ret(); |
| 9248 | 9325 |
| 9249 __ bind(&non_ascii_flat); | 9326 __ bind(&non_ascii_flat); |
| 9250 // r2: result string length. | 9327 // r2: result string length. |
| 9251 // r5: string. | 9328 // r5: string. |
| 9252 // r6: from offset (smi) | 9329 // r6: from offset (smi) |
| 9253 // Check for flat two byte string. | 9330 // Check for flat two byte string. |
| 9254 | 9331 |
| 9255 // Allocate the result. | 9332 // Allocate the result. |
| 9256 __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime); | 9333 __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime); |
| 9257 | 9334 |
| 9258 // r0: result string. | 9335 // r0: result string. |
| 9259 // r2: result string length. | 9336 // r2: result string length. |
| 9260 // r5: string. | 9337 // r5: string. |
| 9261 // Locate first character of result. | 9338 // Locate first character of result. |
| 9262 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 9339 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 9263 // Locate 'from' character of string. | 9340 // Locate 'from' character of string. |
| 9264 __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 9341 __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 9265 // As "from" is a smi it is 2 times the value which matches the size of a two | 9342 // As "from" is a smi it is 2 times the value which matches the size of a two |
| 9266 // byte character. | 9343 // byte character. |
| 9267 __ add(r5, r5, Operand(r6)); | 9344 __ add(r5, r5, Operand(r6)); |
| 9268 | 9345 |
| 9269 // r0: result string. | 9346 // r0: result string. |
| 9270 // r1: first character of result. | 9347 // r1: first character of result. |
| 9271 // r2: result length. | 9348 // r2: result length. |
| 9272 // r5: first character of string to copy. | 9349 // r5: first character of string to copy. |
| 9273 ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask); | 9350 ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask); |
| 9274 GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, | 9351 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
| 9275 DEST_ALWAYS_ALIGNED); | 9352 DEST_ALWAYS_ALIGNED); |
| 9276 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 9353 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| 9277 __ add(sp, sp, Operand(3 * kPointerSize)); | 9354 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 9278 __ Ret(); | 9355 __ Ret(); |
| 9279 | 9356 |
| 9280 // Just jump to runtime to create the sub string. | 9357 // Just jump to runtime to create the sub string. |
| 9281 __ bind(&runtime); | 9358 __ bind(&runtime); |
| 9282 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 9359 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 9283 } | 9360 } |
| 9284 | 9361 |
| 9285 | 9362 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9449 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, | 9526 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, |
| 9450 &string_add_runtime); | 9527 &string_add_runtime); |
| 9451 | 9528 |
| 9452 // Get the two characters forming the sub string. | 9529 // Get the two characters forming the sub string. |
| 9453 __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); | 9530 __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 9454 __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); | 9531 __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); |
| 9455 | 9532 |
| 9456 // Try to lookup two character string in symbol table. If it is not found | 9533 // Try to lookup two character string in symbol table. If it is not found |
| 9457 // just allocate a new one. | 9534 // just allocate a new one. |
| 9458 Label make_two_character_string; | 9535 Label make_two_character_string; |
| 9459 GenerateTwoCharacterSymbolTableProbe(masm, r2, r3, r6, r7, r4, r5, r9, | 9536 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
| 9460 &make_two_character_string); | 9537 masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string); |
| 9461 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); | 9538 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
| 9462 __ add(sp, sp, Operand(2 * kPointerSize)); | 9539 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 9463 __ Ret(); | 9540 __ Ret(); |
| 9464 | 9541 |
| 9465 __ bind(&make_two_character_string); | 9542 __ bind(&make_two_character_string); |
| 9466 // Resulting string has length 2 and first chars of two strings | 9543 // Resulting string has length 2 and first chars of two strings |
| 9467 // are combined into single halfword in r2 register. | 9544 // are combined into single halfword in r2 register. |
| 9468 // So we can fill resulting string without two loops by a single | 9545 // So we can fill resulting string without two loops by a single |
| 9469 // halfword store instruction (which assumes that processor is | 9546 // halfword store instruction (which assumes that processor is |
| 9470 // in a little endian mode) | 9547 // in a little endian mode) |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9559 // Locate first character of result. | 9636 // Locate first character of result. |
| 9560 __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9637 __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 9561 // Locate first character of first argument. | 9638 // Locate first character of first argument. |
| 9562 __ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9639 __ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 9563 // r0: first character of first string. | 9640 // r0: first character of first string. |
| 9564 // r1: second string. | 9641 // r1: second string. |
| 9565 // r2: length of first string. | 9642 // r2: length of first string. |
| 9566 // r3: length of second string. | 9643 // r3: length of second string. |
| 9567 // r6: first character of result. | 9644 // r6: first character of result. |
| 9568 // r7: result string. | 9645 // r7: result string. |
| 9569 GenerateCopyCharacters(masm, r6, r0, r2, r4, true); | 9646 StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, true); |
| 9570 | 9647 |
| 9571 // Load second argument and locate first character. | 9648 // Load second argument and locate first character. |
| 9572 __ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 9649 __ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 9573 // r1: first character of second string. | 9650 // r1: first character of second string. |
| 9574 // r3: length of second string. | 9651 // r3: length of second string. |
| 9575 // r6: next character of result. | 9652 // r6: next character of result. |
| 9576 // r7: result string. | 9653 // r7: result string. |
| 9577 GenerateCopyCharacters(masm, r6, r1, r3, r4, true); | 9654 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true); |
| 9578 __ mov(r0, Operand(r7)); | 9655 __ mov(r0, Operand(r7)); |
| 9579 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); | 9656 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
| 9580 __ add(sp, sp, Operand(2 * kPointerSize)); | 9657 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 9581 __ Ret(); | 9658 __ Ret(); |
| 9582 | 9659 |
| 9583 __ bind(&non_ascii_string_add_flat_result); | 9660 __ bind(&non_ascii_string_add_flat_result); |
| 9584 // Both strings are sequential two byte strings. | 9661 // Both strings are sequential two byte strings. |
| 9585 // r0: first string. | 9662 // r0: first string. |
| 9586 // r1: second string. | 9663 // r1: second string. |
| 9587 // r2: length of first string. | 9664 // r2: length of first string. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 9598 __ add(r6, r7, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 9675 __ add(r6, r7, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 9599 // Locate first character of first argument. | 9676 // Locate first character of first argument. |
| 9600 __ add(r0, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 9677 __ add(r0, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 9601 | 9678 |
| 9602 // r0: first character of first string. | 9679 // r0: first character of first string. |
| 9603 // r1: second string. | 9680 // r1: second string. |
| 9604 // r2: length of first string. | 9681 // r2: length of first string. |
| 9605 // r3: length of second string. | 9682 // r3: length of second string. |
| 9606 // r6: first character of result. | 9683 // r6: first character of result. |
| 9607 // r7: result string. | 9684 // r7: result string. |
| 9608 GenerateCopyCharacters(masm, r6, r0, r2, r4, false); | 9685 StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, false); |
| 9609 | 9686 |
| 9610 // Locate first character of second argument. | 9687 // Locate first character of second argument. |
| 9611 __ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 9688 __ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 9612 | 9689 |
| 9613 // r1: first character of second string. | 9690 // r1: first character of second string. |
| 9614 // r3: length of second string. | 9691 // r3: length of second string. |
| 9615 // r6: next character of result (after copy of first string). | 9692 // r6: next character of result (after copy of first string). |
| 9616 // r7: result string. | 9693 // r7: result string. |
| 9617 GenerateCopyCharacters(masm, r6, r1, r3, r4, false); | 9694 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false); |
| 9618 | 9695 |
| 9619 __ mov(r0, Operand(r7)); | 9696 __ mov(r0, Operand(r7)); |
| 9620 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); | 9697 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
| 9621 __ add(sp, sp, Operand(2 * kPointerSize)); | 9698 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 9622 __ Ret(); | 9699 __ Ret(); |
| 9623 | 9700 |
| 9624 // Just jump to runtime to add the two strings. | 9701 // Just jump to runtime to add the two strings. |
| 9625 __ bind(&string_add_runtime); | 9702 __ bind(&string_add_runtime); |
| 9626 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 9703 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 9627 } | 9704 } |
| 9628 | 9705 |
| 9629 | 9706 |
| 9630 #undef __ | 9707 #undef __ |
| 9631 | 9708 |
| 9632 } } // namespace v8::internal | 9709 } } // namespace v8::internal |
| OLD | NEW |