| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 } | 194 } |
| 195 | 195 |
| 196 | 196 |
| 197 static void InitializeArrayConstructorDescriptor( | 197 static void InitializeArrayConstructorDescriptor( |
| 198 Isolate* isolate, | 198 Isolate* isolate, |
| 199 CodeStubInterfaceDescriptor* descriptor, | 199 CodeStubInterfaceDescriptor* descriptor, |
| 200 int constant_stack_parameter_count) { | 200 int constant_stack_parameter_count) { |
| 201 // register state | 201 // register state |
| 202 // a0 -- number of arguments | 202 // a0 -- number of arguments |
| 203 // a1 -- function | 203 // a1 -- function |
| 204 // a2 -- type info cell with elements kind | 204 // a2 -- allocation site with elements kind |
| 205 static Register registers_variable_args[] = { a1, a2, a0 }; | 205 static Register registers_variable_args[] = { a1, a2, a0 }; |
| 206 static Register registers_no_args[] = { a1, a2 }; | 206 static Register registers_no_args[] = { a1, a2 }; |
| 207 | 207 |
| 208 if (constant_stack_parameter_count == 0) { | 208 if (constant_stack_parameter_count == 0) { |
| 209 descriptor->register_param_count_ = 2; | 209 descriptor->register_param_count_ = 2; |
| 210 descriptor->register_params_ = registers_no_args; | 210 descriptor->register_params_ = registers_no_args; |
| 211 } else { | 211 } else { |
| 212 // stack param count needs (constructor pointer, and single argument) | 212 // stack param count needs (constructor pointer, and single argument) |
| 213 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS; | 213 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS; |
| 214 descriptor->stack_parameter_count_ = a0; | 214 descriptor->stack_parameter_count_ = a0; |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 Isolate* isolate, | 344 Isolate* isolate, |
| 345 CodeStubInterfaceDescriptor* descriptor) { | 345 CodeStubInterfaceDescriptor* descriptor) { |
| 346 static Register registers[] = { a2, a1, a0 }; | 346 static Register registers[] = { a2, a1, a0 }; |
| 347 descriptor->register_param_count_ = 3; | 347 descriptor->register_param_count_ = 3; |
| 348 descriptor->register_params_ = registers; | 348 descriptor->register_params_ = registers; |
| 349 descriptor->deoptimization_handler_ = | 349 descriptor->deoptimization_handler_ = |
| 350 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); | 350 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); |
| 351 } | 351 } |
| 352 | 352 |
| 353 | 353 |
| 354 void NewStringAddStub::InitializeInterfaceDescriptor( | 354 void StringAddStub::InitializeInterfaceDescriptor( |
| 355 Isolate* isolate, | 355 Isolate* isolate, |
| 356 CodeStubInterfaceDescriptor* descriptor) { | 356 CodeStubInterfaceDescriptor* descriptor) { |
| 357 static Register registers[] = { a1, a0 }; | 357 static Register registers[] = { a1, a0 }; |
| 358 descriptor->register_param_count_ = 2; | 358 descriptor->register_param_count_ = 2; |
| 359 descriptor->register_params_ = registers; | 359 descriptor->register_params_ = registers; |
| 360 descriptor->deoptimization_handler_ = | 360 descriptor->deoptimization_handler_ = |
| 361 Runtime::FunctionForId(Runtime::kStringAdd)->entry; | 361 Runtime::FunctionForId(Runtime::kStringAdd)->entry; |
| 362 } | 362 } |
| 363 | 363 |
| 364 | 364 |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 // Load double input. | 676 // Load double input. |
| 677 __ ldc1(double_scratch, MemOperand(input_reg, double_offset)); | 677 __ ldc1(double_scratch, MemOperand(input_reg, double_offset)); |
| 678 | 678 |
| 679 // Clear cumulative exception flags and save the FCSR. | 679 // Clear cumulative exception flags and save the FCSR. |
| 680 __ cfc1(scratch2, FCSR); | 680 __ cfc1(scratch2, FCSR); |
| 681 __ ctc1(zero_reg, FCSR); | 681 __ ctc1(zero_reg, FCSR); |
| 682 | 682 |
| 683 // Try a conversion to a signed integer. | 683 // Try a conversion to a signed integer. |
| 684 __ Trunc_w_d(double_scratch, double_scratch); | 684 __ Trunc_w_d(double_scratch, double_scratch); |
| 685 // Move the converted value into the result register. | 685 // Move the converted value into the result register. |
| 686 __ mfc1(result_reg, double_scratch); | 686 __ mfc1(scratch3, double_scratch); |
| 687 | 687 |
| 688 // Retrieve and restore the FCSR. | 688 // Retrieve and restore the FCSR. |
| 689 __ cfc1(scratch, FCSR); | 689 __ cfc1(scratch, FCSR); |
| 690 __ ctc1(scratch2, FCSR); | 690 __ ctc1(scratch2, FCSR); |
| 691 | 691 |
| 692 // Check for overflow and NaNs. | 692 // Check for overflow and NaNs. |
| 693 __ And( | 693 __ And( |
| 694 scratch, scratch, | 694 scratch, scratch, |
| 695 kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | 695 kFCSROverflowFlagMask | kFCSRUnderflowFlagMask |
| 696 | kFCSRInvalidOpFlagMask); | 696 | kFCSRInvalidOpFlagMask); |
| 697 // If we had no exceptions we are done. | 697 // If we had no exceptions then set result_reg and we are done. |
| 698 __ Branch(&done, eq, scratch, Operand(zero_reg)); | 698 Label error; |
| 699 __ Branch(&error, ne, scratch, Operand(zero_reg)); |
| 700 __ Move(result_reg, scratch3); |
| 701 __ Branch(&done); |
| 702 __ bind(&error); |
| 699 } | 703 } |
| 700 | 704 |
| 701 // Load the double value and perform a manual truncation. | 705 // Load the double value and perform a manual truncation. |
| 702 Register input_high = scratch2; | 706 Register input_high = scratch2; |
| 703 Register input_low = scratch3; | 707 Register input_low = scratch3; |
| 704 | 708 |
| 705 __ lw(input_low, MemOperand(input_reg, double_offset)); | 709 __ lw(input_low, MemOperand(input_reg, double_offset)); |
| 706 __ lw(input_high, MemOperand(input_reg, double_offset + kIntSize)); | 710 __ lw(input_high, MemOperand(input_reg, double_offset + kIntSize)); |
| 707 | 711 |
| 708 Label normal_exponent, restore_sign; | 712 Label normal_exponent, restore_sign; |
| (...skipping 2905 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3614 __ CallRuntime(Runtime::kCharFromCode, 1); | 3618 __ CallRuntime(Runtime::kCharFromCode, 1); |
| 3615 __ Move(result_, v0); | 3619 __ Move(result_, v0); |
| 3616 | 3620 |
| 3617 call_helper.AfterCall(masm); | 3621 call_helper.AfterCall(masm); |
| 3618 __ Branch(&exit_); | 3622 __ Branch(&exit_); |
| 3619 | 3623 |
| 3620 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 3624 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
| 3621 } | 3625 } |
| 3622 | 3626 |
| 3623 | 3627 |
| 3624 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | |
| 3625 Register dest, | |
| 3626 Register src, | |
| 3627 Register count, | |
| 3628 Register scratch, | |
| 3629 bool ascii) { | |
| 3630 Label loop; | |
| 3631 Label done; | |
| 3632 // This loop just copies one character at a time, as it is only used for | |
| 3633 // very short strings. | |
| 3634 if (!ascii) { | |
| 3635 __ addu(count, count, count); | |
| 3636 } | |
| 3637 __ Branch(&done, eq, count, Operand(zero_reg)); | |
| 3638 __ addu(count, dest, count); // Count now points to the last dest byte. | |
| 3639 | |
| 3640 __ bind(&loop); | |
| 3641 __ lbu(scratch, MemOperand(src)); | |
| 3642 __ addiu(src, src, 1); | |
| 3643 __ sb(scratch, MemOperand(dest)); | |
| 3644 __ addiu(dest, dest, 1); | |
| 3645 __ Branch(&loop, lt, dest, Operand(count)); | |
| 3646 | |
| 3647 __ bind(&done); | |
| 3648 } | |
| 3649 | |
| 3650 | |
| 3651 enum CopyCharactersFlags { | 3628 enum CopyCharactersFlags { |
| 3652 COPY_ASCII = 1, | 3629 COPY_ASCII = 1, |
| 3653 DEST_ALWAYS_ALIGNED = 2 | 3630 DEST_ALWAYS_ALIGNED = 2 |
| 3654 }; | 3631 }; |
| 3655 | 3632 |
| 3656 | 3633 |
| 3657 void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, | 3634 void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, |
| 3658 Register dest, | 3635 Register dest, |
| 3659 Register src, | 3636 Register src, |
| 3660 Register count, | 3637 Register count, |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3759 __ lbu(scratch1, MemOperand(src)); | 3736 __ lbu(scratch1, MemOperand(src)); |
| 3760 __ addiu(src, src, 1); | 3737 __ addiu(src, src, 1); |
| 3761 __ sb(scratch1, MemOperand(dest)); | 3738 __ sb(scratch1, MemOperand(dest)); |
| 3762 __ addiu(dest, dest, 1); | 3739 __ addiu(dest, dest, 1); |
| 3763 __ Branch(&byte_loop); | 3740 __ Branch(&byte_loop); |
| 3764 | 3741 |
| 3765 __ bind(&done); | 3742 __ bind(&done); |
| 3766 } | 3743 } |
| 3767 | 3744 |
| 3768 | 3745 |
| 3769 void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, | |
| 3770 Register c1, | |
| 3771 Register c2, | |
| 3772 Register scratch1, | |
| 3773 Register scratch2, | |
| 3774 Register scratch3, | |
| 3775 Register scratch4, | |
| 3776 Register scratch5, | |
| 3777 Label* not_found) { | |
| 3778 // Register scratch3 is the general scratch register in this function. | |
| 3779 Register scratch = scratch3; | |
| 3780 | |
| 3781 // Make sure that both characters are not digits as such strings has a | |
| 3782 // different hash algorithm. Don't try to look for these in the string table. | |
| 3783 Label not_array_index; | |
| 3784 __ Subu(scratch, c1, Operand(static_cast<int>('0'))); | |
| 3785 __ Branch(¬_array_index, | |
| 3786 Ugreater, | |
| 3787 scratch, | |
| 3788 Operand(static_cast<int>('9' - '0'))); | |
| 3789 __ Subu(scratch, c2, Operand(static_cast<int>('0'))); | |
| 3790 | |
| 3791 // If check failed combine both characters into single halfword. | |
| 3792 // This is required by the contract of the method: code at the | |
| 3793 // not_found branch expects this combination in c1 register. | |
| 3794 Label tmp; | |
| 3795 __ sll(scratch1, c2, kBitsPerByte); | |
| 3796 __ Branch(&tmp, Ugreater, scratch, Operand(static_cast<int>('9' - '0'))); | |
| 3797 __ Or(c1, c1, scratch1); | |
| 3798 __ bind(&tmp); | |
| 3799 __ Branch( | |
| 3800 not_found, Uless_equal, scratch, Operand(static_cast<int>('9' - '0'))); | |
| 3801 | |
| 3802 __ bind(¬_array_index); | |
| 3803 // Calculate the two character string hash. | |
| 3804 Register hash = scratch1; | |
| 3805 StringHelper::GenerateHashInit(masm, hash, c1); | |
| 3806 StringHelper::GenerateHashAddCharacter(masm, hash, c2); | |
| 3807 StringHelper::GenerateHashGetHash(masm, hash); | |
| 3808 | |
| 3809 // Collect the two characters in a register. | |
| 3810 Register chars = c1; | |
| 3811 __ sll(scratch, c2, kBitsPerByte); | |
| 3812 __ Or(chars, chars, scratch); | |
| 3813 | |
| 3814 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
| 3815 // hash: hash of two character string. | |
| 3816 | |
| 3817 // Load string table. | |
| 3818 // Load address of first element of the string table. | |
| 3819 Register string_table = c2; | |
| 3820 __ LoadRoot(string_table, Heap::kStringTableRootIndex); | |
| 3821 | |
| 3822 Register undefined = scratch4; | |
| 3823 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); | |
| 3824 | |
| 3825 // Calculate capacity mask from the string table capacity. | |
| 3826 Register mask = scratch2; | |
| 3827 __ lw(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset)); | |
| 3828 __ sra(mask, mask, 1); | |
| 3829 __ Addu(mask, mask, -1); | |
| 3830 | |
| 3831 // Calculate untagged address of the first element of the string table. | |
| 3832 Register first_string_table_element = string_table; | |
| 3833 __ Addu(first_string_table_element, string_table, | |
| 3834 Operand(StringTable::kElementsStartOffset - kHeapObjectTag)); | |
| 3835 | |
| 3836 // Registers. | |
| 3837 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
| 3838 // hash: hash of two character string | |
| 3839 // mask: capacity mask | |
| 3840 // first_string_table_element: address of the first element of | |
| 3841 // the string table | |
| 3842 // undefined: the undefined object | |
| 3843 // scratch: - | |
| 3844 | |
| 3845 // Perform a number of probes in the string table. | |
| 3846 const int kProbes = 4; | |
| 3847 Label found_in_string_table; | |
| 3848 Label next_probe[kProbes]; | |
| 3849 Register candidate = scratch5; // Scratch register contains candidate. | |
| 3850 for (int i = 0; i < kProbes; i++) { | |
| 3851 // Calculate entry in string table. | |
| 3852 if (i > 0) { | |
| 3853 __ Addu(candidate, hash, Operand(StringTable::GetProbeOffset(i))); | |
| 3854 } else { | |
| 3855 __ mov(candidate, hash); | |
| 3856 } | |
| 3857 | |
| 3858 __ And(candidate, candidate, Operand(mask)); | |
| 3859 | |
| 3860 // Load the entry from the symble table. | |
| 3861 STATIC_ASSERT(StringTable::kEntrySize == 1); | |
| 3862 __ sll(scratch, candidate, kPointerSizeLog2); | |
| 3863 __ Addu(scratch, scratch, first_string_table_element); | |
| 3864 __ lw(candidate, MemOperand(scratch)); | |
| 3865 | |
| 3866 // If entry is undefined no string with this hash can be found. | |
| 3867 Label is_string; | |
| 3868 __ GetObjectType(candidate, scratch, scratch); | |
| 3869 __ Branch(&is_string, ne, scratch, Operand(ODDBALL_TYPE)); | |
| 3870 | |
| 3871 __ Branch(not_found, eq, undefined, Operand(candidate)); | |
| 3872 // Must be the hole (deleted entry). | |
| 3873 if (FLAG_debug_code) { | |
| 3874 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); | |
| 3875 __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole, | |
| 3876 scratch, Operand(candidate)); | |
| 3877 } | |
| 3878 __ jmp(&next_probe[i]); | |
| 3879 | |
| 3880 __ bind(&is_string); | |
| 3881 | |
| 3882 // Check that the candidate is a non-external ASCII string. The instance | |
| 3883 // type is still in the scratch register from the CompareObjectType | |
| 3884 // operation. | |
| 3885 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]); | |
| 3886 | |
| 3887 // If length is not 2 the string is not a candidate. | |
| 3888 __ lw(scratch, FieldMemOperand(candidate, String::kLengthOffset)); | |
| 3889 __ Branch(&next_probe[i], ne, scratch, Operand(Smi::FromInt(2))); | |
| 3890 | |
| 3891 // Check if the two characters match. | |
| 3892 // Assumes that word load is little endian. | |
| 3893 __ lhu(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize)); | |
| 3894 __ Branch(&found_in_string_table, eq, chars, Operand(scratch)); | |
| 3895 __ bind(&next_probe[i]); | |
| 3896 } | |
| 3897 | |
| 3898 // No matching 2 character string found by probing. | |
| 3899 __ jmp(not_found); | |
| 3900 | |
| 3901 // Scratch register contains result when we fall through to here. | |
| 3902 Register result = candidate; | |
| 3903 __ bind(&found_in_string_table); | |
| 3904 __ mov(v0, result); | |
| 3905 } | |
| 3906 | |
| 3907 | |
| 3908 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 3746 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
| 3909 Register hash, | 3747 Register hash, |
| 3910 Register character) { | 3748 Register character) { |
| 3911 // hash = seed + character + ((seed + character) << 10); | 3749 // hash = seed + character + ((seed + character) << 10); |
| 3912 __ LoadRoot(hash, Heap::kHashSeedRootIndex); | 3750 __ LoadRoot(hash, Heap::kHashSeedRootIndex); |
| 3913 // Untag smi seed and add the character. | 3751 // Untag smi seed and add the character. |
| 3914 __ SmiUntag(hash); | 3752 __ SmiUntag(hash); |
| 3915 __ addu(hash, hash, character); | 3753 __ addu(hash, hash, character); |
| 3916 __ sll(at, hash, 10); | 3754 __ sll(at, hash, 10); |
| 3917 __ addu(hash, hash, at); | 3755 __ addu(hash, hash, at); |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4325 // Compare flat ASCII strings natively. Remove arguments from stack first. | 4163 // Compare flat ASCII strings natively. Remove arguments from stack first. |
| 4326 __ IncrementCounter(counters->string_compare_native(), 1, a2, a3); | 4164 __ IncrementCounter(counters->string_compare_native(), 1, a2, a3); |
| 4327 __ Addu(sp, sp, Operand(2 * kPointerSize)); | 4165 __ Addu(sp, sp, Operand(2 * kPointerSize)); |
| 4328 GenerateCompareFlatAsciiStrings(masm, a1, a0, a2, a3, t0, t1); | 4166 GenerateCompareFlatAsciiStrings(masm, a1, a0, a2, a3, t0, t1); |
| 4329 | 4167 |
| 4330 __ bind(&runtime); | 4168 __ bind(&runtime); |
| 4331 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 4169 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 4332 } | 4170 } |
| 4333 | 4171 |
| 4334 | 4172 |
| 4173 void ArrayPushStub::Generate(MacroAssembler* masm) { |
| 4174 Register receiver = a0; |
| 4175 Register scratch = a1; |
| 4176 |
| 4177 int argc = arguments_count(); |
| 4178 |
| 4179 if (argc == 0) { |
| 4180 // Nothing to do, just return the length. |
| 4181 __ lw(v0, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 4182 __ DropAndRet(argc + 1); |
| 4183 return; |
| 4184 } |
| 4185 |
| 4186 Isolate* isolate = masm->isolate(); |
| 4187 |
| 4188 if (argc != 1) { |
| 4189 __ TailCallExternalReference( |
| 4190 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 4191 return; |
| 4192 } |
| 4193 |
| 4194 Label call_builtin, attempt_to_grow_elements, with_write_barrier; |
| 4195 |
| 4196 Register elements = t2; |
| 4197 Register end_elements = t1; |
| 4198 // Get the elements array of the object. |
| 4199 __ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); |
| 4200 |
| 4201 if (IsFastSmiOrObjectElementsKind(elements_kind())) { |
| 4202 // Check that the elements are in fast mode and writable. |
| 4203 __ CheckMap(elements, |
| 4204 scratch, |
| 4205 Heap::kFixedArrayMapRootIndex, |
| 4206 &call_builtin, |
| 4207 DONT_DO_SMI_CHECK); |
| 4208 } |
| 4209 |
| 4210 // Get the array's length into scratch and calculate new length. |
| 4211 __ lw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 4212 __ Addu(scratch, scratch, Operand(Smi::FromInt(argc))); |
| 4213 |
| 4214 // Get the elements' length. |
| 4215 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 4216 |
| 4217 const int kEndElementsOffset = |
| 4218 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize; |
| 4219 |
| 4220 if (IsFastSmiOrObjectElementsKind(elements_kind())) { |
| 4221 // Check if we could survive without allocation. |
| 4222 __ Branch(&attempt_to_grow_elements, gt, scratch, Operand(t0)); |
| 4223 |
| 4224 // Check if value is a smi. |
| 4225 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize)); |
| 4226 __ JumpIfNotSmi(t0, &with_write_barrier); |
| 4227 |
| 4228 // Store the value. |
| 4229 // We may need a register containing the address end_elements below, |
| 4230 // so write back the value in end_elements. |
| 4231 __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize); |
| 4232 __ Addu(end_elements, elements, end_elements); |
| 4233 __ Addu(end_elements, end_elements, kEndElementsOffset); |
| 4234 __ sw(t0, MemOperand(end_elements)); |
| 4235 } else { |
| 4236 // Check if we could survive without allocation. |
| 4237 __ Branch(&call_builtin, gt, scratch, Operand(t0)); |
| 4238 |
| 4239 __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize)); |
| 4240 __ StoreNumberToDoubleElements(t0, scratch, elements, a3, t1, a2, |
| 4241 &call_builtin, argc * kDoubleSize); |
| 4242 } |
| 4243 |
| 4244 // Save new length. |
| 4245 __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 4246 __ mov(v0, scratch); |
| 4247 __ DropAndRet(argc + 1); |
| 4248 |
| 4249 if (IsFastDoubleElementsKind(elements_kind())) { |
| 4250 __ bind(&call_builtin); |
| 4251 __ TailCallExternalReference( |
| 4252 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 4253 return; |
| 4254 } |
| 4255 |
| 4256 __ bind(&with_write_barrier); |
| 4257 |
| 4258 if (IsFastSmiElementsKind(elements_kind())) { |
| 4259 if (FLAG_trace_elements_transitions) __ jmp(&call_builtin); |
| 4260 |
| 4261 __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset)); |
| 4262 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); |
| 4263 __ Branch(&call_builtin, eq, t3, Operand(at)); |
| 4264 |
| 4265 ElementsKind target_kind = IsHoleyElementsKind(elements_kind()) |
| 4266 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; |
| 4267 __ lw(a3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); |
| 4268 __ lw(a3, FieldMemOperand(a3, GlobalObject::kNativeContextOffset)); |
| 4269 __ lw(a3, ContextOperand(a3, Context::JS_ARRAY_MAPS_INDEX)); |
| 4270 const int header_size = FixedArrayBase::kHeaderSize; |
| 4271 // Verify that the object can be transitioned in place. |
| 4272 const int origin_offset = header_size + elements_kind() * kPointerSize; |
| 4273 __ lw(a2, FieldMemOperand(receiver, origin_offset)); |
| 4274 __ lw(at, FieldMemOperand(a3, HeapObject::kMapOffset)); |
| 4275 __ Branch(&call_builtin, ne, a2, Operand(at)); |
| 4276 |
| 4277 |
| 4278 const int target_offset = header_size + target_kind * kPointerSize; |
| 4279 __ lw(a3, FieldMemOperand(a3, target_offset)); |
| 4280 __ mov(a2, receiver); |
| 4281 ElementsTransitionGenerator::GenerateMapChangeElementsTransition( |
| 4282 masm, DONT_TRACK_ALLOCATION_SITE, NULL); |
| 4283 } |
| 4284 |
| 4285 // Save new length. |
| 4286 __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 4287 |
| 4288 // Store the value. |
| 4289 // We may need a register containing the address end_elements below, so write |
| 4290 // back the value in end_elements. |
| 4291 __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize); |
| 4292 __ Addu(end_elements, elements, end_elements); |
| 4293 __ Addu(end_elements, end_elements, kEndElementsOffset); |
| 4294 __ sw(t0, MemOperand(end_elements)); |
| 4295 |
| 4296 __ RecordWrite(elements, |
| 4297 end_elements, |
| 4298 t0, |
| 4299 kRAHasNotBeenSaved, |
| 4300 kDontSaveFPRegs, |
| 4301 EMIT_REMEMBERED_SET, |
| 4302 OMIT_SMI_CHECK); |
| 4303 __ mov(v0, scratch); |
| 4304 __ DropAndRet(argc + 1); |
| 4305 |
| 4306 __ bind(&attempt_to_grow_elements); |
| 4307 // scratch: array's length + 1. |
| 4308 |
| 4309 if (!FLAG_inline_new) { |
| 4310 __ bind(&call_builtin); |
| 4311 __ TailCallExternalReference( |
| 4312 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 4313 return; |
| 4314 } |
| 4315 |
| 4316 __ lw(a2, MemOperand(sp, (argc - 1) * kPointerSize)); |
| 4317 // Growing elements that are SMI-only requires special handling in case the |
| 4318 // new element is non-Smi. For now, delegate to the builtin. |
| 4319 if (IsFastSmiElementsKind(elements_kind())) { |
| 4320 __ JumpIfNotSmi(a2, &call_builtin); |
| 4321 } |
| 4322 |
| 4323 // We could be lucky and the elements array could be at the top of new-space. |
| 4324 // In this case we can just grow it in place by moving the allocation pointer |
| 4325 // up. |
| 4326 ExternalReference new_space_allocation_top = |
| 4327 ExternalReference::new_space_allocation_top_address(isolate); |
| 4328 ExternalReference new_space_allocation_limit = |
| 4329 ExternalReference::new_space_allocation_limit_address(isolate); |
| 4330 |
| 4331 const int kAllocationDelta = 4; |
| 4332 ASSERT(kAllocationDelta >= argc); |
| 4333 // Load top and check if it is the end of elements. |
| 4334 __ sll(end_elements, scratch, kPointerSizeLog2 - kSmiTagSize); |
| 4335 __ Addu(end_elements, elements, end_elements); |
| 4336 __ Addu(end_elements, end_elements, Operand(kEndElementsOffset)); |
| 4337 __ li(t0, Operand(new_space_allocation_top)); |
| 4338 __ lw(a3, MemOperand(t0)); |
| 4339 __ Branch(&call_builtin, ne, a3, Operand(end_elements)); |
| 4340 |
| 4341 __ li(t3, Operand(new_space_allocation_limit)); |
| 4342 __ lw(t3, MemOperand(t3)); |
| 4343 __ Addu(a3, a3, Operand(kAllocationDelta * kPointerSize)); |
| 4344 __ Branch(&call_builtin, hi, a3, Operand(t3)); |
| 4345 |
| 4346 // We fit and could grow elements. |
| 4347 // Update new_space_allocation_top. |
| 4348 __ sw(a3, MemOperand(t0)); |
| 4349 // Push the argument. |
| 4350 __ sw(a2, MemOperand(end_elements)); |
| 4351 // Fill the rest with holes. |
| 4352 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex); |
| 4353 for (int i = 1; i < kAllocationDelta; i++) { |
| 4354 __ sw(a3, MemOperand(end_elements, i * kPointerSize)); |
| 4355 } |
| 4356 |
| 4357 // Update elements' and array's sizes. |
| 4358 __ sw(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 4359 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 4360 __ Addu(t0, t0, Operand(Smi::FromInt(kAllocationDelta))); |
| 4361 __ sw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 4362 |
| 4363 // Elements are in new space, so write barrier is not required. |
| 4364 __ mov(v0, scratch); |
| 4365 __ DropAndRet(argc + 1); |
| 4366 |
| 4367 __ bind(&call_builtin); |
| 4368 __ TailCallExternalReference( |
| 4369 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 4370 } |
| 4371 |
| 4372 |
| 4335 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { | 4373 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { |
| 4336 // ----------- S t a t e ------------- | 4374 // ----------- S t a t e ------------- |
| 4337 // -- a1 : left | 4375 // -- a1 : left |
| 4338 // -- a0 : right | 4376 // -- a0 : right |
| 4339 // -- ra : return address | 4377 // -- ra : return address |
| 4340 // ----------------------------------- | 4378 // ----------------------------------- |
| 4341 Isolate* isolate = masm->isolate(); | 4379 Isolate* isolate = masm->isolate(); |
| 4342 | 4380 |
| 4343 // Load a2 with the allocation site. We stick an undefined dummy value here | 4381 // Load a2 with the allocation site. We stick an undefined dummy value here |
| 4344 // and replace it with the real allocation site later when we instantiate this | 4382 // and replace it with the real allocation site later when we instantiate this |
| 4345 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate(). | 4383 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate(). |
| 4346 __ li(a2, handle(isolate->heap()->undefined_value())); | 4384 __ li(a2, handle(isolate->heap()->undefined_value())); |
| 4347 | 4385 |
| 4348 // Make sure that we actually patched the allocation site. | 4386 // Make sure that we actually patched the allocation site. |
| 4349 if (FLAG_debug_code) { | 4387 if (FLAG_debug_code) { |
| 4350 __ And(at, a2, Operand(kSmiTagMask)); | 4388 __ And(at, a2, Operand(kSmiTagMask)); |
| 4351 __ Assert(ne, kExpectedAllocationSite, at, Operand(zero_reg)); | 4389 __ Assert(ne, kExpectedAllocationSite, at, Operand(zero_reg)); |
| 4352 __ lw(t0, FieldMemOperand(a2, HeapObject::kMapOffset)); | 4390 __ lw(t0, FieldMemOperand(a2, HeapObject::kMapOffset)); |
| 4353 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); | 4391 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); |
| 4354 __ Assert(eq, kExpectedAllocationSite, t0, Operand(at)); | 4392 __ Assert(eq, kExpectedAllocationSite, t0, Operand(at)); |
| 4355 } | 4393 } |
| 4356 | 4394 |
| 4357 // Tail call into the stub that handles binary operations with allocation | 4395 // Tail call into the stub that handles binary operations with allocation |
| 4358 // sites. | 4396 // sites. |
| 4359 BinaryOpWithAllocationSiteStub stub(state_); | 4397 BinaryOpWithAllocationSiteStub stub(state_); |
| 4360 __ TailCallStub(&stub); | 4398 __ TailCallStub(&stub); |
| 4361 } | 4399 } |
| 4362 | 4400 |
| 4363 | 4401 |
| 4364 void StringAddStub::Generate(MacroAssembler* masm) { | |
| 4365 Label call_runtime, call_builtin; | |
| 4366 Builtins::JavaScript builtin_id = Builtins::ADD; | |
| 4367 | |
| 4368 Counters* counters = masm->isolate()->counters(); | |
| 4369 | |
| 4370 // Stack on entry: | |
| 4371 // sp[0]: second argument (right). | |
| 4372 // sp[4]: first argument (left). | |
| 4373 | |
| 4374 // Load the two arguments. | |
| 4375 __ lw(a0, MemOperand(sp, 1 * kPointerSize)); // First argument. | |
| 4376 __ lw(a1, MemOperand(sp, 0 * kPointerSize)); // Second argument. | |
| 4377 | |
| 4378 // Make sure that both arguments are strings if not known in advance. | |
| 4379 // Otherwise, at least one of the arguments is definitely a string, | |
| 4380 // and we convert the one that is not known to be a string. | |
| 4381 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { | |
| 4382 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); | |
| 4383 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); | |
| 4384 __ JumpIfEitherSmi(a0, a1, &call_runtime); | |
| 4385 // Load instance types. | |
| 4386 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | |
| 4387 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | |
| 4388 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | |
| 4389 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | |
| 4390 STATIC_ASSERT(kStringTag == 0); | |
| 4391 // If either is not a string, go to runtime. | |
| 4392 __ Or(t4, t0, Operand(t1)); | |
| 4393 __ And(t4, t4, Operand(kIsNotStringMask)); | |
| 4394 __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); | |
| 4395 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { | |
| 4396 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); | |
| 4397 GenerateConvertArgument( | |
| 4398 masm, 1 * kPointerSize, a0, a2, a3, t0, t1, &call_builtin); | |
| 4399 builtin_id = Builtins::STRING_ADD_RIGHT; | |
| 4400 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { | |
| 4401 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); | |
| 4402 GenerateConvertArgument( | |
| 4403 masm, 0 * kPointerSize, a1, a2, a3, t0, t1, &call_builtin); | |
| 4404 builtin_id = Builtins::STRING_ADD_LEFT; | |
| 4405 } | |
| 4406 | |
| 4407 // Both arguments are strings. | |
| 4408 // a0: first string | |
| 4409 // a1: second string | |
| 4410 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4411 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4412 { | |
| 4413 Label strings_not_empty; | |
| 4414 // Check if either of the strings are empty. In that case return the other. | |
| 4415 // These tests use zero-length check on string-length whch is an Smi. | |
| 4416 // Assert that Smi::FromInt(0) is really 0. | |
| 4417 STATIC_ASSERT(kSmiTag == 0); | |
| 4418 ASSERT(Smi::FromInt(0) == 0); | |
| 4419 __ lw(a2, FieldMemOperand(a0, String::kLengthOffset)); | |
| 4420 __ lw(a3, FieldMemOperand(a1, String::kLengthOffset)); | |
| 4421 __ mov(v0, a0); // Assume we'll return first string (from a0). | |
| 4422 __ Movz(v0, a1, a2); // If first is empty, return second (from a1). | |
| 4423 __ slt(t4, zero_reg, a2); // if (a2 > 0) t4 = 1. | |
| 4424 __ slt(t5, zero_reg, a3); // if (a3 > 0) t5 = 1. | |
| 4425 __ and_(t4, t4, t5); // Branch if both strings were non-empty. | |
| 4426 __ Branch(&strings_not_empty, ne, t4, Operand(zero_reg)); | |
| 4427 | |
| 4428 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | |
| 4429 __ DropAndRet(2); | |
| 4430 | |
| 4431 __ bind(&strings_not_empty); | |
| 4432 } | |
| 4433 | |
| 4434 // Untag both string-lengths. | |
| 4435 __ sra(a2, a2, kSmiTagSize); | |
| 4436 __ sra(a3, a3, kSmiTagSize); | |
| 4437 | |
| 4438 // Both strings are non-empty. | |
| 4439 // a0: first string | |
| 4440 // a1: second string | |
| 4441 // a2: length of first string | |
| 4442 // a3: length of second string | |
| 4443 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4444 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4445 // Look at the length of the result of adding the two strings. | |
| 4446 Label string_add_flat_result, longer_than_two; | |
| 4447 // Adding two lengths can't overflow. | |
| 4448 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2); | |
| 4449 __ Addu(t2, a2, Operand(a3)); | |
| 4450 // Use the string table when adding two one character strings, as it | |
| 4451 // helps later optimizations to return a string here. | |
| 4452 __ Branch(&longer_than_two, ne, t2, Operand(2)); | |
| 4453 | |
| 4454 // Check that both strings are non-external ASCII strings. | |
| 4455 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { | |
| 4456 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | |
| 4457 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | |
| 4458 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | |
| 4459 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | |
| 4460 } | |
| 4461 __ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3, | |
| 4462 &call_runtime); | |
| 4463 | |
| 4464 // Get the two characters forming the sub string. | |
| 4465 __ lbu(a2, FieldMemOperand(a0, SeqOneByteString::kHeaderSize)); | |
| 4466 __ lbu(a3, FieldMemOperand(a1, SeqOneByteString::kHeaderSize)); | |
| 4467 | |
| 4468 // Try to lookup two character string in string table. If it is not found | |
| 4469 // just allocate a new one. | |
| 4470 Label make_two_character_string; | |
| 4471 StringHelper::GenerateTwoCharacterStringTableProbe( | |
| 4472 masm, a2, a3, t2, t3, t0, t1, t5, &make_two_character_string); | |
| 4473 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | |
| 4474 __ DropAndRet(2); | |
| 4475 | |
| 4476 __ bind(&make_two_character_string); | |
| 4477 // Resulting string has length 2 and first chars of two strings | |
| 4478 // are combined into single halfword in a2 register. | |
| 4479 // So we can fill resulting string without two loops by a single | |
| 4480 // halfword store instruction (which assumes that processor is | |
| 4481 // in a little endian mode). | |
| 4482 __ li(t2, Operand(2)); | |
| 4483 __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime); | |
| 4484 __ sh(a2, FieldMemOperand(v0, SeqOneByteString::kHeaderSize)); | |
| 4485 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | |
| 4486 __ DropAndRet(2); | |
| 4487 | |
| 4488 __ bind(&longer_than_two); | |
| 4489 // Check if resulting string will be flat. | |
| 4490 __ Branch(&string_add_flat_result, lt, t2, Operand(ConsString::kMinLength)); | |
| 4491 // Handle exceptionally long strings in the runtime system. | |
| 4492 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | |
| 4493 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | |
| 4494 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | |
| 4495 __ Branch(&call_runtime, hs, t2, Operand(String::kMaxLength + 1)); | |
| 4496 | |
| 4497 // If result is not supposed to be flat, allocate a cons string object. | |
| 4498 // If both strings are ASCII the result is an ASCII cons string. | |
| 4499 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { | |
| 4500 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | |
| 4501 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | |
| 4502 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | |
| 4503 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | |
| 4504 } | |
| 4505 Label non_ascii, allocated, ascii_data; | |
| 4506 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 4507 // Branch to non_ascii if either string-encoding field is zero (non-ASCII). | |
| 4508 __ And(t4, t0, Operand(t1)); | |
| 4509 __ And(t4, t4, Operand(kStringEncodingMask)); | |
| 4510 __ Branch(&non_ascii, eq, t4, Operand(zero_reg)); | |
| 4511 | |
| 4512 // Allocate an ASCII cons string. | |
| 4513 __ bind(&ascii_data); | |
| 4514 __ AllocateAsciiConsString(v0, t2, t0, t1, &call_runtime); | |
| 4515 __ bind(&allocated); | |
| 4516 // Fill the fields of the cons string. | |
| 4517 Label skip_write_barrier, after_writing; | |
| 4518 ExternalReference high_promotion_mode = ExternalReference:: | |
| 4519 new_space_high_promotion_mode_active_address(masm->isolate()); | |
| 4520 __ li(t0, Operand(high_promotion_mode)); | |
| 4521 __ lw(t0, MemOperand(t0, 0)); | |
| 4522 __ Branch(&skip_write_barrier, eq, t0, Operand(zero_reg)); | |
| 4523 | |
| 4524 __ mov(t3, v0); | |
| 4525 __ sw(a0, FieldMemOperand(t3, ConsString::kFirstOffset)); | |
| 4526 __ RecordWriteField(t3, | |
| 4527 ConsString::kFirstOffset, | |
| 4528 a0, | |
| 4529 t0, | |
| 4530 kRAHasNotBeenSaved, | |
| 4531 kDontSaveFPRegs); | |
| 4532 __ sw(a1, FieldMemOperand(t3, ConsString::kSecondOffset)); | |
| 4533 __ RecordWriteField(t3, | |
| 4534 ConsString::kSecondOffset, | |
| 4535 a1, | |
| 4536 t0, | |
| 4537 kRAHasNotBeenSaved, | |
| 4538 kDontSaveFPRegs); | |
| 4539 __ jmp(&after_writing); | |
| 4540 | |
| 4541 __ bind(&skip_write_barrier); | |
| 4542 __ sw(a0, FieldMemOperand(v0, ConsString::kFirstOffset)); | |
| 4543 __ sw(a1, FieldMemOperand(v0, ConsString::kSecondOffset)); | |
| 4544 | |
| 4545 __ bind(&after_writing); | |
| 4546 | |
| 4547 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | |
| 4548 __ DropAndRet(2); | |
| 4549 | |
| 4550 __ bind(&non_ascii); | |
| 4551 // At least one of the strings is two-byte. Check whether it happens | |
| 4552 // to contain only one byte characters. | |
| 4553 // t0: first instance type. | |
| 4554 // t1: second instance type. | |
| 4555 // Branch to if _both_ instances have kOneByteDataHintMask set. | |
| 4556 __ And(at, t0, Operand(kOneByteDataHintMask)); | |
| 4557 __ and_(at, at, t1); | |
| 4558 __ Branch(&ascii_data, ne, at, Operand(zero_reg)); | |
| 4559 __ Xor(t0, t0, Operand(t1)); | |
| 4560 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); | |
| 4561 __ And(t0, t0, Operand(kOneByteStringTag | kOneByteDataHintTag)); | |
| 4562 __ Branch(&ascii_data, eq, t0, | |
| 4563 Operand(kOneByteStringTag | kOneByteDataHintTag)); | |
| 4564 | |
| 4565 // Allocate a two byte cons string. | |
| 4566 __ AllocateTwoByteConsString(v0, t2, t0, t1, &call_runtime); | |
| 4567 __ Branch(&allocated); | |
| 4568 | |
| 4569 // We cannot encounter sliced strings or cons strings here since: | |
| 4570 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); | |
| 4571 // Handle creating a flat result from either external or sequential strings. | |
| 4572 // Locate the first characters' locations. | |
| 4573 // a0: first string | |
| 4574 // a1: second string | |
| 4575 // a2: length of first string | |
| 4576 // a3: length of second string | |
| 4577 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4578 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4579 // t2: sum of lengths. | |
| 4580 Label first_prepared, second_prepared; | |
| 4581 __ bind(&string_add_flat_result); | |
| 4582 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { | |
| 4583 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | |
| 4584 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | |
| 4585 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | |
| 4586 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | |
| 4587 } | |
| 4588 // Check whether both strings have same encoding | |
| 4589 __ Xor(t3, t0, Operand(t1)); | |
| 4590 __ And(t3, t3, Operand(kStringEncodingMask)); | |
| 4591 __ Branch(&call_runtime, ne, t3, Operand(zero_reg)); | |
| 4592 | |
| 4593 STATIC_ASSERT(kSeqStringTag == 0); | |
| 4594 __ And(t4, t0, Operand(kStringRepresentationMask)); | |
| 4595 | |
| 4596 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
| 4597 Label skip_first_add; | |
| 4598 __ Branch(&skip_first_add, ne, t4, Operand(zero_reg)); | |
| 4599 __ Branch(USE_DELAY_SLOT, &first_prepared); | |
| 4600 __ addiu(t3, a0, SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
| 4601 __ bind(&skip_first_add); | |
| 4602 // External string: rule out short external string and load string resource. | |
| 4603 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 4604 __ And(t4, t0, Operand(kShortExternalStringMask)); | |
| 4605 __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); | |
| 4606 __ lw(t3, FieldMemOperand(a0, ExternalString::kResourceDataOffset)); | |
| 4607 __ bind(&first_prepared); | |
| 4608 | |
| 4609 STATIC_ASSERT(kSeqStringTag == 0); | |
| 4610 __ And(t4, t1, Operand(kStringRepresentationMask)); | |
| 4611 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
| 4612 Label skip_second_add; | |
| 4613 __ Branch(&skip_second_add, ne, t4, Operand(zero_reg)); | |
| 4614 __ Branch(USE_DELAY_SLOT, &second_prepared); | |
| 4615 __ addiu(a1, a1, SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
| 4616 __ bind(&skip_second_add); | |
| 4617 // External string: rule out short external string and load string resource. | |
| 4618 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 4619 __ And(t4, t1, Operand(kShortExternalStringMask)); | |
| 4620 __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); | |
| 4621 __ lw(a1, FieldMemOperand(a1, ExternalString::kResourceDataOffset)); | |
| 4622 __ bind(&second_prepared); | |
| 4623 | |
| 4624 Label non_ascii_string_add_flat_result; | |
| 4625 // t3: first character of first string | |
| 4626 // a1: first character of second string | |
| 4627 // a2: length of first string | |
| 4628 // a3: length of second string | |
| 4629 // t2: sum of lengths. | |
| 4630 // Both strings have the same encoding. | |
| 4631 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 4632 __ And(t4, t1, Operand(kStringEncodingMask)); | |
| 4633 __ Branch(&non_ascii_string_add_flat_result, eq, t4, Operand(zero_reg)); | |
| 4634 | |
| 4635 __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime); | |
| 4636 __ Addu(t2, v0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
| 4637 // v0: result string. | |
| 4638 // t3: first character of first string. | |
| 4639 // a1: first character of second string | |
| 4640 // a2: length of first string. | |
| 4641 // a3: length of second string. | |
| 4642 // t2: first character of result. | |
| 4643 | |
| 4644 StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, true); | |
| 4645 // t2: next character of result. | |
| 4646 StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, true); | |
| 4647 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | |
| 4648 __ DropAndRet(2); | |
| 4649 | |
| 4650 __ bind(&non_ascii_string_add_flat_result); | |
| 4651 __ AllocateTwoByteString(v0, t2, t0, t1, t5, &call_runtime); | |
| 4652 __ Addu(t2, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
| 4653 // v0: result string. | |
| 4654 // t3: first character of first string. | |
| 4655 // a1: first character of second string. | |
| 4656 // a2: length of first string. | |
| 4657 // a3: length of second string. | |
| 4658 // t2: first character of result. | |
| 4659 StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, false); | |
| 4660 // t2: next character of result. | |
| 4661 StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false); | |
| 4662 | |
| 4663 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | |
| 4664 __ DropAndRet(2); | |
| 4665 | |
| 4666 // Just jump to runtime to add the two strings. | |
| 4667 __ bind(&call_runtime); | |
| 4668 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | |
| 4669 | |
| 4670 if (call_builtin.is_linked()) { | |
| 4671 __ bind(&call_builtin); | |
| 4672 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | |
| 4673 } | |
| 4674 } | |
| 4675 | |
| 4676 | |
| 4677 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
| 4678 __ push(a0); | |
| 4679 __ push(a1); | |
| 4680 } | |
| 4681 | |
| 4682 | |
| 4683 void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) { | |
| 4684 __ pop(a1); | |
| 4685 __ pop(a0); | |
| 4686 } | |
| 4687 | |
| 4688 | |
| 4689 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | |
| 4690 int stack_offset, | |
| 4691 Register arg, | |
| 4692 Register scratch1, | |
| 4693 Register scratch2, | |
| 4694 Register scratch3, | |
| 4695 Register scratch4, | |
| 4696 Label* slow) { | |
| 4697 // First check if the argument is already a string. | |
| 4698 Label not_string, done; | |
| 4699 __ JumpIfSmi(arg, ¬_string); | |
| 4700 __ GetObjectType(arg, scratch1, scratch1); | |
| 4701 __ Branch(&done, lt, scratch1, Operand(FIRST_NONSTRING_TYPE)); | |
| 4702 | |
| 4703 // Check the number to string cache. | |
| 4704 __ bind(¬_string); | |
| 4705 // Puts the cached result into scratch1. | |
| 4706 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, scratch4, slow); | |
| 4707 __ mov(arg, scratch1); | |
| 4708 __ sw(arg, MemOperand(sp, stack_offset)); | |
| 4709 __ bind(&done); | |
| 4710 } | |
| 4711 | |
| 4712 | |
| 4713 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 4402 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
| 4714 ASSERT(state_ == CompareIC::SMI); | 4403 ASSERT(state_ == CompareIC::SMI); |
| 4715 Label miss; | 4404 Label miss; |
| 4716 __ Or(a2, a1, a0); | 4405 __ Or(a2, a1, a0); |
| 4717 __ JumpIfNotSmi(a2, &miss); | 4406 __ JumpIfNotSmi(a2, &miss); |
| 4718 | 4407 |
| 4719 if (GetCondition() == eq) { | 4408 if (GetCondition() == eq) { |
| 4720 // For equality we do not care about the sign of the result. | 4409 // For equality we do not care about the sign of the result. |
| 4721 __ Ret(USE_DELAY_SLOT); | 4410 __ Ret(USE_DELAY_SLOT); |
| 4722 __ Subu(v0, a0, a1); | 4411 __ Subu(v0, a0, a1); |
| (...skipping 1020 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5743 // If we reached this point there is a problem. | 5432 // If we reached this point there is a problem. |
| 5744 __ Abort(kUnexpectedElementsKindInArrayConstructor); | 5433 __ Abort(kUnexpectedElementsKindInArrayConstructor); |
| 5745 } else { | 5434 } else { |
| 5746 UNREACHABLE(); | 5435 UNREACHABLE(); |
| 5747 } | 5436 } |
| 5748 } | 5437 } |
| 5749 | 5438 |
| 5750 | 5439 |
| 5751 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, | 5440 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, |
| 5752 AllocationSiteOverrideMode mode) { | 5441 AllocationSiteOverrideMode mode) { |
| 5753 // a2 - type info cell (if mode != DISABLE_ALLOCATION_SITES) | 5442 // a2 - allocation site (if mode != DISABLE_ALLOCATION_SITES) |
| 5754 // a3 - kind (if mode != DISABLE_ALLOCATION_SITES) | 5443 // a3 - kind (if mode != DISABLE_ALLOCATION_SITES) |
| 5755 // a0 - number of arguments | 5444 // a0 - number of arguments |
| 5756 // a1 - constructor? | 5445 // a1 - constructor? |
| 5757 // sp[0] - last argument | 5446 // sp[0] - last argument |
| 5758 Label normal_sequence; | 5447 Label normal_sequence; |
| 5759 if (mode == DONT_OVERRIDE) { | 5448 if (mode == DONT_OVERRIDE) { |
| 5760 ASSERT(FAST_SMI_ELEMENTS == 0); | 5449 ASSERT(FAST_SMI_ELEMENTS == 0); |
| 5761 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | 5450 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); |
| 5762 ASSERT(FAST_ELEMENTS == 2); | 5451 ASSERT(FAST_ELEMENTS == 2); |
| 5763 ASSERT(FAST_HOLEY_ELEMENTS == 3); | 5452 ASSERT(FAST_HOLEY_ELEMENTS == 3); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 5782 __ TailCallStub(&stub_holey); | 5471 __ TailCallStub(&stub_holey); |
| 5783 | 5472 |
| 5784 __ bind(&normal_sequence); | 5473 __ bind(&normal_sequence); |
| 5785 ArraySingleArgumentConstructorStub stub(initial, | 5474 ArraySingleArgumentConstructorStub stub(initial, |
| 5786 DISABLE_ALLOCATION_SITES); | 5475 DISABLE_ALLOCATION_SITES); |
| 5787 __ TailCallStub(&stub); | 5476 __ TailCallStub(&stub); |
| 5788 } else if (mode == DONT_OVERRIDE) { | 5477 } else if (mode == DONT_OVERRIDE) { |
| 5789 // We are going to create a holey array, but our kind is non-holey. | 5478 // We are going to create a holey array, but our kind is non-holey. |
| 5790 // Fix kind and retry (only if we have an allocation site in the cell). | 5479 // Fix kind and retry (only if we have an allocation site in the cell). |
| 5791 __ Addu(a3, a3, Operand(1)); | 5480 __ Addu(a3, a3, Operand(1)); |
| 5792 __ lw(t1, FieldMemOperand(a2, Cell::kValueOffset)); | |
| 5793 | 5481 |
| 5794 if (FLAG_debug_code) { | 5482 if (FLAG_debug_code) { |
| 5795 __ lw(t1, FieldMemOperand(t1, 0)); | 5483 __ lw(t1, FieldMemOperand(a2, 0)); |
| 5796 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); | 5484 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); |
| 5797 __ Assert(eq, kExpectedAllocationSiteInCell, t1, Operand(at)); | 5485 __ Assert(eq, kExpectedAllocationSite, t1, Operand(at)); |
| 5798 __ lw(t1, FieldMemOperand(a2, Cell::kValueOffset)); | |
| 5799 } | 5486 } |
| 5800 | 5487 |
| 5801 // Save the resulting elements kind in type info. We can't just store a3 | 5488 // Save the resulting elements kind in type info. We can't just store a3 |
| 5802 // in the AllocationSite::transition_info field because elements kind is | 5489 // in the AllocationSite::transition_info field because elements kind is |
| 5803 // restricted to a portion of the field...upper bits need to be left alone. | 5490 // restricted to a portion of the field...upper bits need to be left alone. |
| 5804 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); | 5491 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); |
| 5805 __ lw(t0, FieldMemOperand(t1, AllocationSite::kTransitionInfoOffset)); | 5492 __ lw(t0, FieldMemOperand(a2, AllocationSite::kTransitionInfoOffset)); |
| 5806 __ Addu(t0, t0, Operand(Smi::FromInt(kFastElementsKindPackedToHoley))); | 5493 __ Addu(t0, t0, Operand(Smi::FromInt(kFastElementsKindPackedToHoley))); |
| 5807 __ sw(t0, FieldMemOperand(t1, AllocationSite::kTransitionInfoOffset)); | 5494 __ sw(t0, FieldMemOperand(a2, AllocationSite::kTransitionInfoOffset)); |
| 5808 | 5495 |
| 5809 | 5496 |
| 5810 __ bind(&normal_sequence); | 5497 __ bind(&normal_sequence); |
| 5811 int last_index = GetSequenceIndexFromFastElementsKind( | 5498 int last_index = GetSequenceIndexFromFastElementsKind( |
| 5812 TERMINAL_FAST_ELEMENTS_KIND); | 5499 TERMINAL_FAST_ELEMENTS_KIND); |
| 5813 for (int i = 0; i <= last_index; ++i) { | 5500 for (int i = 0; i <= last_index; ++i) { |
| 5814 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); | 5501 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); |
| 5815 ArraySingleArgumentConstructorStub stub(kind); | 5502 ArraySingleArgumentConstructorStub stub(kind); |
| 5816 __ TailCallStub(&stub, eq, a3, Operand(kind)); | 5503 __ TailCallStub(&stub, eq, a3, Operand(kind)); |
| 5817 } | 5504 } |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5922 __ lw(a3, FieldMemOperand(a2, 0)); | 5609 __ lw(a3, FieldMemOperand(a2, 0)); |
| 5923 __ Assert(eq, kExpectedPropertyCellInRegisterA2, | 5610 __ Assert(eq, kExpectedPropertyCellInRegisterA2, |
| 5924 a3, Operand(cell_map)); | 5611 a3, Operand(cell_map)); |
| 5925 __ bind(&okay_here); | 5612 __ bind(&okay_here); |
| 5926 } | 5613 } |
| 5927 | 5614 |
| 5928 Label no_info; | 5615 Label no_info; |
| 5929 // Get the elements kind and case on that. | 5616 // Get the elements kind and case on that. |
| 5930 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | 5617 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
| 5931 __ Branch(&no_info, eq, a2, Operand(at)); | 5618 __ Branch(&no_info, eq, a2, Operand(at)); |
| 5932 __ lw(a3, FieldMemOperand(a2, Cell::kValueOffset)); | 5619 __ lw(a2, FieldMemOperand(a2, Cell::kValueOffset)); |
| 5933 | 5620 |
| 5934 // If the type cell is undefined, or contains anything other than an | 5621 // If the type cell is undefined, or contains anything other than an |
| 5935 // AllocationSite, call an array constructor that doesn't use AllocationSites. | 5622 // AllocationSite, call an array constructor that doesn't use AllocationSites. |
| 5936 __ lw(t0, FieldMemOperand(a3, 0)); | 5623 __ lw(t0, FieldMemOperand(a2, 0)); |
| 5937 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); | 5624 __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); |
| 5938 __ Branch(&no_info, ne, t0, Operand(at)); | 5625 __ Branch(&no_info, ne, t0, Operand(at)); |
| 5939 | 5626 |
| 5940 __ lw(a3, FieldMemOperand(a3, AllocationSite::kTransitionInfoOffset)); | 5627 __ lw(a3, FieldMemOperand(a2, AllocationSite::kTransitionInfoOffset)); |
| 5941 __ SmiUntag(a3); | 5628 __ SmiUntag(a3); |
| 5942 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); | 5629 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); |
| 5943 __ And(a3, a3, Operand(AllocationSite::ElementsKindBits::kMask)); | 5630 __ And(a3, a3, Operand(AllocationSite::ElementsKindBits::kMask)); |
| 5944 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); | 5631 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); |
| 5945 | 5632 |
| 5946 __ bind(&no_info); | 5633 __ bind(&no_info); |
| 5947 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); | 5634 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); |
| 5948 } | 5635 } |
| 5949 | 5636 |
| 5950 | 5637 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6020 __ bind(&fast_elements_case); | 5707 __ bind(&fast_elements_case); |
| 6021 GenerateCase(masm, FAST_ELEMENTS); | 5708 GenerateCase(masm, FAST_ELEMENTS); |
| 6022 } | 5709 } |
| 6023 | 5710 |
| 6024 | 5711 |
| 6025 #undef __ | 5712 #undef __ |
| 6026 | 5713 |
| 6027 } } // namespace v8::internal | 5714 } } // namespace v8::internal |
| 6028 | 5715 |
| 6029 #endif // V8_TARGET_ARCH_MIPS | 5716 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |