| 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 874 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 885 | 885 |
| 886 __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE); | 886 __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE); |
| 887 __ b(ge, &return_not_equal); | 887 __ b(ge, &return_not_equal); |
| 888 | 888 |
| 889 // Check for oddballs: true, false, null, undefined. | 889 // Check for oddballs: true, false, null, undefined. |
| 890 __ cmp(r3, Operand(ODDBALL_TYPE)); | 890 __ cmp(r3, Operand(ODDBALL_TYPE)); |
| 891 __ b(eq, &return_not_equal); | 891 __ b(eq, &return_not_equal); |
| 892 | 892 |
| 893 // Now that we have the types we might as well check for | 893 // Now that we have the types we might as well check for |
| 894 // internalized-internalized. | 894 // internalized-internalized. |
| 895 // Ensure that no non-strings have the internalized bit set. | 895 Label not_internalized; |
| 896 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask); | |
| 897 STATIC_ASSERT(kInternalizedTag != 0); | 896 STATIC_ASSERT(kInternalizedTag != 0); |
| 898 __ and_(r2, r2, Operand(r3)); | 897 __ and_(r2, r2, Operand(kIsNotStringMask | kIsInternalizedMask)); |
| 899 __ tst(r2, Operand(kIsInternalizedMask)); | 898 __ cmp(r2, Operand(kInternalizedTag | kStringTag)); |
| 900 __ b(ne, &return_not_equal); | 899 __ b(ne, ¬_internalized); // r2 (rhs) is not an internalized string |
| 900 |
| 901 __ and_(r3, r3, Operand(kIsNotStringMask | kIsInternalizedMask)); |
| 902 __ cmp(r3, Operand(kInternalizedTag | kStringTag)); |
| 903 __ b(eq, &return_not_equal); // both rhs and lhs are internalized strings |
| 904 |
| 905 __ bind(¬_internalized); |
| 901 } | 906 } |
| 902 | 907 |
| 903 | 908 |
| 904 // See comment at call site. | 909 // See comment at call site. |
| 905 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, | 910 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, |
| 906 Register lhs, | 911 Register lhs, |
| 907 Register rhs, | 912 Register rhs, |
| 908 Label* both_loaded_as_doubles, | 913 Label* both_loaded_as_doubles, |
| 909 Label* not_heap_numbers, | 914 Label* not_heap_numbers, |
| 910 Label* slow) { | 915 Label* slow) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 930 // Fast negative check for internalized-to-internalized equality. | 935 // Fast negative check for internalized-to-internalized equality. |
| 931 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, | 936 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, |
| 932 Register lhs, | 937 Register lhs, |
| 933 Register rhs, | 938 Register rhs, |
| 934 Label* possible_strings, | 939 Label* possible_strings, |
| 935 Label* not_both_strings) { | 940 Label* not_both_strings) { |
| 936 ASSERT((lhs.is(r0) && rhs.is(r1)) || | 941 ASSERT((lhs.is(r0) && rhs.is(r1)) || |
| 937 (lhs.is(r1) && rhs.is(r0))); | 942 (lhs.is(r1) && rhs.is(r0))); |
| 938 | 943 |
| 939 // r2 is object type of rhs. | 944 // r2 is object type of rhs. |
| 940 // Ensure that no non-strings have the internalized bit set. | |
| 941 Label object_test; | 945 Label object_test; |
| 942 STATIC_ASSERT(kInternalizedTag != 0); | 946 STATIC_ASSERT(kInternalizedTag != 0); |
| 943 __ tst(r2, Operand(kIsNotStringMask)); | 947 __ tst(r2, Operand(kIsNotStringMask)); |
| 944 __ b(ne, &object_test); | 948 __ b(ne, &object_test); |
| 945 __ tst(r2, Operand(kIsInternalizedMask)); | 949 __ tst(r2, Operand(kIsInternalizedMask)); |
| 946 __ b(eq, possible_strings); | 950 __ b(eq, possible_strings); |
| 947 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE); | 951 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE); |
| 948 __ b(ge, not_both_strings); | 952 __ b(ge, not_both_strings); |
| 949 __ tst(r3, Operand(kIsInternalizedMask)); | 953 __ tst(r3, Operand(kIsInternalizedMask)); |
| 950 __ b(eq, possible_strings); | 954 __ b(eq, possible_strings); |
| (...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2068 masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true, | 2072 masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true, |
| 2069 use_runtime, gc_required, ¬_smis, op, mode); | 2073 use_runtime, gc_required, ¬_smis, op, mode); |
| 2070 } | 2074 } |
| 2071 __ bind(¬_smis); | 2075 __ bind(¬_smis); |
| 2072 } | 2076 } |
| 2073 | 2077 |
| 2074 | 2078 |
| 2075 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 2079 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 2076 Label right_arg_changed, call_runtime; | 2080 Label right_arg_changed, call_runtime; |
| 2077 | 2081 |
| 2078 if (op_ == Token::MOD && has_fixed_right_arg_) { | 2082 if (op_ == Token::MOD && encoded_right_arg_.has_value) { |
| 2079 // It is guaranteed that the value will fit into a Smi, because if it | 2083 // It is guaranteed that the value will fit into a Smi, because if it |
| 2080 // didn't, we wouldn't be here, see BinaryOp_Patch. | 2084 // didn't, we wouldn't be here, see BinaryOp_Patch. |
| 2081 __ cmp(r0, Operand(Smi::FromInt(fixed_right_arg_value()))); | 2085 __ cmp(r0, Operand(Smi::FromInt(fixed_right_arg_value()))); |
| 2082 __ b(ne, &right_arg_changed); | 2086 __ b(ne, &right_arg_changed); |
| 2083 } | 2087 } |
| 2084 | 2088 |
| 2085 if (result_type_ == BinaryOpIC::UNINITIALIZED || | 2089 if (result_type_ == BinaryOpIC::UNINITIALIZED || |
| 2086 result_type_ == BinaryOpIC::SMI) { | 2090 result_type_ == BinaryOpIC::SMI) { |
| 2087 // Only allow smi results. | 2091 // Only allow smi results. |
| 2088 BinaryOpStub_GenerateSmiCode( | 2092 BinaryOpStub_GenerateSmiCode( |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2245 mode_); | 2249 mode_); |
| 2246 __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); | 2250 __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); |
| 2247 __ vstr(d5, r0, HeapNumber::kValueOffset); | 2251 __ vstr(d5, r0, HeapNumber::kValueOffset); |
| 2248 __ mov(r0, heap_number_result); | 2252 __ mov(r0, heap_number_result); |
| 2249 __ Ret(); | 2253 __ Ret(); |
| 2250 | 2254 |
| 2251 // A DIV operation expecting an integer result falls through | 2255 // A DIV operation expecting an integer result falls through |
| 2252 // to type transition. | 2256 // to type transition. |
| 2253 | 2257 |
| 2254 } else { | 2258 } else { |
| 2255 if (has_fixed_right_arg_) { | 2259 if (encoded_right_arg_.has_value) { |
| 2256 __ Vmov(d8, fixed_right_arg_value(), scratch1); | 2260 __ Vmov(d8, fixed_right_arg_value(), scratch1); |
| 2257 __ VFPCompareAndSetFlags(d1, d8); | 2261 __ VFPCompareAndSetFlags(d1, d8); |
| 2258 __ b(ne, &transition); | 2262 __ b(ne, &transition); |
| 2259 } | 2263 } |
| 2260 | 2264 |
| 2261 // We preserved r0 and r1 to be able to call runtime. | 2265 // We preserved r0 and r1 to be able to call runtime. |
| 2262 // Save the left value on the stack. | 2266 // Save the left value on the stack. |
| 2263 __ Push(r5, r4); | 2267 __ Push(r5, r4); |
| 2264 | 2268 |
| 2265 Label pop_and_call_runtime; | 2269 Label pop_and_call_runtime; |
| (...skipping 723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2989 result_size_ == 1; | 2993 result_size_ == 1; |
| 2990 } | 2994 } |
| 2991 | 2995 |
| 2992 | 2996 |
| 2993 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 2997 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
| 2994 CEntryStub::GenerateAheadOfTime(isolate); | 2998 CEntryStub::GenerateAheadOfTime(isolate); |
| 2995 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate); | 2999 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 2996 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 3000 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 2997 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 3001 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
| 2998 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); | 3002 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 2999 if (FLAG_optimize_constructed_arrays) { | 3003 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
| 3000 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | |
| 3001 } | |
| 3002 } | 3004 } |
| 3003 | 3005 |
| 3004 | 3006 |
| 3005 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 3007 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
| 3006 SaveFPRegsMode mode = kSaveFPRegs; | 3008 SaveFPRegsMode mode = kSaveFPRegs; |
| 3007 CEntryStub save_doubles(1, mode); | 3009 CEntryStub save_doubles(1, mode); |
| 3008 StoreBufferOverflowStub stub(mode); | 3010 StoreBufferOverflowStub stub(mode); |
| 3009 // These stubs might already be in the snapshot, detect that and don't | 3011 // These stubs might already be in the snapshot, detect that and don't |
| 3010 // regenerate, which would lead to code stub initialization state being messed | 3012 // regenerate, which would lead to code stub initialization state being messed |
| 3011 // up. | 3013 // up. |
| (...skipping 1604 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4616 | 4618 |
| 4617 __ bind(&done); | 4619 __ bind(&done); |
| 4618 __ add(sp, sp, Operand(3 * kPointerSize)); | 4620 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 4619 __ Ret(); | 4621 __ Ret(); |
| 4620 | 4622 |
| 4621 __ bind(&slowcase); | 4623 __ bind(&slowcase); |
| 4622 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); | 4624 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); |
| 4623 } | 4625 } |
| 4624 | 4626 |
| 4625 | 4627 |
| 4626 static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) { | |
| 4627 // Cache the called function in a global property cell. Cache states | |
| 4628 // are uninitialized, monomorphic (indicated by a JSFunction), and | |
| 4629 // megamorphic. | |
| 4630 // r1 : the function to call | |
| 4631 // r2 : cache cell for call target | |
| 4632 Label done; | |
| 4633 | |
| 4634 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), | |
| 4635 masm->isolate()->heap()->undefined_value()); | |
| 4636 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()), | |
| 4637 masm->isolate()->heap()->the_hole_value()); | |
| 4638 | |
| 4639 // Load the cache state into r3. | |
| 4640 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); | |
| 4641 | |
| 4642 // A monomorphic cache hit or an already megamorphic state: invoke the | |
| 4643 // function without changing the state. | |
| 4644 __ cmp(r3, r1); | |
| 4645 __ b(eq, &done); | |
| 4646 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); | |
| 4647 __ b(eq, &done); | |
| 4648 | |
| 4649 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | |
| 4650 // megamorphic. | |
| 4651 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); | |
| 4652 // MegamorphicSentinel is an immortal immovable object (undefined) so no | |
| 4653 // write-barrier is needed. | |
| 4654 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex, ne); | |
| 4655 __ str(ip, FieldMemOperand(r2, Cell::kValueOffset), ne); | |
| 4656 | |
| 4657 // An uninitialized cache is patched with the function. | |
| 4658 __ str(r1, FieldMemOperand(r2, Cell::kValueOffset), eq); | |
| 4659 // No need for a write barrier here - cells are rescanned. | |
| 4660 | |
| 4661 __ bind(&done); | |
| 4662 } | |
| 4663 | |
| 4664 | |
| 4665 static void GenerateRecordCallTarget(MacroAssembler* masm) { | 4628 static void GenerateRecordCallTarget(MacroAssembler* masm) { |
| 4666 // Cache the called function in a global property cell. Cache states | 4629 // Cache the called function in a global property cell. Cache states |
| 4667 // are uninitialized, monomorphic (indicated by a JSFunction), and | 4630 // are uninitialized, monomorphic (indicated by a JSFunction), and |
| 4668 // megamorphic. | 4631 // megamorphic. |
| 4669 // r1 : the function to call | 4632 // r1 : the function to call |
| 4670 // r2 : cache cell for call target | 4633 // r2 : cache cell for call target |
| 4671 ASSERT(FLAG_optimize_constructed_arrays); | |
| 4672 Label initialize, done, miss, megamorphic, not_array_function; | 4634 Label initialize, done, miss, megamorphic, not_array_function; |
| 4673 | 4635 |
| 4674 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), | 4636 ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), |
| 4675 masm->isolate()->heap()->undefined_value()); | 4637 masm->isolate()->heap()->undefined_value()); |
| 4676 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()), | 4638 ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()), |
| 4677 masm->isolate()->heap()->the_hole_value()); | 4639 masm->isolate()->heap()->the_hole_value()); |
| 4678 | 4640 |
| 4679 // Load the cache state into r3. | 4641 // Load the cache state into r3. |
| 4680 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); | 4642 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); |
| 4681 | 4643 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4765 } | 4727 } |
| 4766 | 4728 |
| 4767 // Check that the function is really a JavaScript function. | 4729 // Check that the function is really a JavaScript function. |
| 4768 // r1: pushed function (to be verified) | 4730 // r1: pushed function (to be verified) |
| 4769 __ JumpIfSmi(r1, &non_function); | 4731 __ JumpIfSmi(r1, &non_function); |
| 4770 // Get the map of the function object. | 4732 // Get the map of the function object. |
| 4771 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); | 4733 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); |
| 4772 __ b(ne, &slow); | 4734 __ b(ne, &slow); |
| 4773 | 4735 |
| 4774 if (RecordCallTarget()) { | 4736 if (RecordCallTarget()) { |
| 4775 if (FLAG_optimize_constructed_arrays) { | 4737 GenerateRecordCallTarget(masm); |
| 4776 GenerateRecordCallTarget(masm); | |
| 4777 } else { | |
| 4778 GenerateRecordCallTargetNoArray(masm); | |
| 4779 } | |
| 4780 } | 4738 } |
| 4781 | 4739 |
| 4782 // Fast-case: Invoke the function now. | 4740 // Fast-case: Invoke the function now. |
| 4783 // r1: pushed function | 4741 // r1: pushed function |
| 4784 ParameterCount actual(argc_); | 4742 ParameterCount actual(argc_); |
| 4785 | 4743 |
| 4786 if (ReceiverMightBeImplicit()) { | 4744 if (ReceiverMightBeImplicit()) { |
| 4787 Label call_as_function; | 4745 Label call_as_function; |
| 4788 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); | 4746 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); |
| 4789 __ b(eq, &call_as_function); | 4747 __ b(eq, &call_as_function); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4844 // r2 : cache cell for call target | 4802 // r2 : cache cell for call target |
| 4845 Label slow, non_function_call; | 4803 Label slow, non_function_call; |
| 4846 | 4804 |
| 4847 // Check that the function is not a smi. | 4805 // Check that the function is not a smi. |
| 4848 __ JumpIfSmi(r1, &non_function_call); | 4806 __ JumpIfSmi(r1, &non_function_call); |
| 4849 // Check that the function is a JSFunction. | 4807 // Check that the function is a JSFunction. |
| 4850 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); | 4808 __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); |
| 4851 __ b(ne, &slow); | 4809 __ b(ne, &slow); |
| 4852 | 4810 |
| 4853 if (RecordCallTarget()) { | 4811 if (RecordCallTarget()) { |
| 4854 if (FLAG_optimize_constructed_arrays) { | 4812 GenerateRecordCallTarget(masm); |
| 4855 GenerateRecordCallTarget(masm); | |
| 4856 } else { | |
| 4857 GenerateRecordCallTargetNoArray(masm); | |
| 4858 } | |
| 4859 } | 4813 } |
| 4860 | 4814 |
| 4861 // Jump to the function-specific construct stub. | 4815 // Jump to the function-specific construct stub. |
| 4862 Register jmp_reg = FLAG_optimize_constructed_arrays ? r3 : r2; | 4816 Register jmp_reg = r3; |
| 4863 __ ldr(jmp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | 4817 __ ldr(jmp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
| 4864 __ ldr(jmp_reg, FieldMemOperand(jmp_reg, | 4818 __ ldr(jmp_reg, FieldMemOperand(jmp_reg, |
| 4865 SharedFunctionInfo::kConstructStubOffset)); | 4819 SharedFunctionInfo::kConstructStubOffset)); |
| 4866 __ add(pc, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); | 4820 __ add(pc, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 4867 | 4821 |
| 4868 // r0: number of arguments | 4822 // r0: number of arguments |
| 4869 // r1: called object | 4823 // r1: called object |
| 4870 // r3: object type | 4824 // r3: object type |
| 4871 Label do_call; | 4825 Label do_call; |
| 4872 __ bind(&slow); | 4826 __ bind(&slow); |
| (...skipping 1383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6256 | 6210 |
| 6257 // Check that both operands are heap objects. | 6211 // Check that both operands are heap objects. |
| 6258 __ JumpIfEitherSmi(left, right, &miss); | 6212 __ JumpIfEitherSmi(left, right, &miss); |
| 6259 | 6213 |
| 6260 // Check that both operands are internalized strings. | 6214 // Check that both operands are internalized strings. |
| 6261 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 6215 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 6262 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 6216 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 6263 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 6217 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6264 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 6218 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6265 STATIC_ASSERT(kInternalizedTag != 0); | 6219 STATIC_ASSERT(kInternalizedTag != 0); |
| 6266 __ and_(tmp1, tmp1, Operand(tmp2)); | 6220 |
| 6267 __ tst(tmp1, Operand(kIsInternalizedMask)); | 6221 __ and_(tmp1, tmp1, Operand(kIsNotStringMask | kIsInternalizedMask)); |
| 6268 __ b(eq, &miss); | 6222 __ cmp(tmp1, Operand(kInternalizedTag | kStringTag)); |
| 6223 __ b(ne, &miss); |
| 6224 |
| 6225 __ and_(tmp2, tmp2, Operand(kIsNotStringMask | kIsInternalizedMask)); |
| 6226 __ cmp(tmp2, Operand(kInternalizedTag | kStringTag)); |
| 6227 __ b(ne, &miss); |
| 6269 | 6228 |
| 6270 // Internalized strings are compared by identity. | 6229 // Internalized strings are compared by identity. |
| 6271 __ cmp(left, right); | 6230 __ cmp(left, right); |
| 6272 // Make sure r0 is non-zero. At this point input operands are | 6231 // Make sure r0 is non-zero. At this point input operands are |
| 6273 // guaranteed to be non-zero. | 6232 // guaranteed to be non-zero. |
| 6274 ASSERT(right.is(r0)); | 6233 ASSERT(right.is(r0)); |
| 6275 STATIC_ASSERT(EQUAL == 0); | 6234 STATIC_ASSERT(EQUAL == 0); |
| 6276 STATIC_ASSERT(kSmiTag == 0); | 6235 STATIC_ASSERT(kSmiTag == 0); |
| 6277 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); | 6236 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); |
| 6278 __ Ret(); | 6237 __ Ret(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 6297 __ JumpIfEitherSmi(left, right, &miss); | 6256 __ JumpIfEitherSmi(left, right, &miss); |
| 6298 | 6257 |
| 6299 // Check that both operands are unique names. This leaves the instance | 6258 // Check that both operands are unique names. This leaves the instance |
| 6300 // types loaded in tmp1 and tmp2. | 6259 // types loaded in tmp1 and tmp2. |
| 6301 STATIC_ASSERT(kInternalizedTag != 0); | 6260 STATIC_ASSERT(kInternalizedTag != 0); |
| 6302 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 6261 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 6303 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 6262 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 6304 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 6263 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6305 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 6264 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6306 | 6265 |
| 6307 Label succeed1; | 6266 __ JumpIfNotUniqueName(tmp1, &miss); |
| 6308 __ tst(tmp1, Operand(kIsInternalizedMask)); | 6267 __ JumpIfNotUniqueName(tmp2, &miss); |
| 6309 __ b(ne, &succeed1); | |
| 6310 __ cmp(tmp1, Operand(SYMBOL_TYPE)); | |
| 6311 __ b(ne, &miss); | |
| 6312 __ bind(&succeed1); | |
| 6313 | |
| 6314 Label succeed2; | |
| 6315 __ tst(tmp2, Operand(kIsInternalizedMask)); | |
| 6316 __ b(ne, &succeed2); | |
| 6317 __ cmp(tmp2, Operand(SYMBOL_TYPE)); | |
| 6318 __ b(ne, &miss); | |
| 6319 __ bind(&succeed2); | |
| 6320 | 6268 |
| 6321 // Unique names are compared by identity. | 6269 // Unique names are compared by identity. |
| 6322 __ cmp(left, right); | 6270 __ cmp(left, right); |
| 6323 // Make sure r0 is non-zero. At this point input operands are | 6271 // Make sure r0 is non-zero. At this point input operands are |
| 6324 // guaranteed to be non-zero. | 6272 // guaranteed to be non-zero. |
| 6325 ASSERT(right.is(r0)); | 6273 ASSERT(right.is(r0)); |
| 6326 STATIC_ASSERT(EQUAL == 0); | 6274 STATIC_ASSERT(EQUAL == 0); |
| 6327 STATIC_ASSERT(kSmiTag == 0); | 6275 STATIC_ASSERT(kSmiTag == 0); |
| 6328 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); | 6276 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); |
| 6329 __ Ret(); | 6277 __ Ret(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6364 // Fast check for identical strings. | 6312 // Fast check for identical strings. |
| 6365 __ cmp(left, right); | 6313 __ cmp(left, right); |
| 6366 STATIC_ASSERT(EQUAL == 0); | 6314 STATIC_ASSERT(EQUAL == 0); |
| 6367 STATIC_ASSERT(kSmiTag == 0); | 6315 STATIC_ASSERT(kSmiTag == 0); |
| 6368 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); | 6316 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); |
| 6369 __ Ret(eq); | 6317 __ Ret(eq); |
| 6370 | 6318 |
| 6371 // Handle not identical strings. | 6319 // Handle not identical strings. |
| 6372 | 6320 |
| 6373 // Check that both strings are internalized strings. If they are, we're done | 6321 // Check that both strings are internalized strings. If they are, we're done |
| 6374 // because we already know they are not identical. | 6322 // because we already know they are not identical. We know they are both |
| 6323 // strings. |
| 6375 if (equality) { | 6324 if (equality) { |
| 6376 ASSERT(GetCondition() == eq); | 6325 ASSERT(GetCondition() == eq); |
| 6377 STATIC_ASSERT(kInternalizedTag != 0); | 6326 STATIC_ASSERT(kInternalizedTag != 0); |
| 6378 __ and_(tmp3, tmp1, Operand(tmp2)); | 6327 __ and_(tmp3, tmp1, Operand(tmp2)); |
| 6379 __ tst(tmp3, Operand(kIsInternalizedMask)); | 6328 __ tst(tmp3, Operand(kIsInternalizedMask)); |
| 6380 // Make sure r0 is non-zero. At this point input operands are | 6329 // Make sure r0 is non-zero. At this point input operands are |
| 6381 // guaranteed to be non-zero. | 6330 // guaranteed to be non-zero. |
| 6382 ASSERT(right.is(r0)); | 6331 ASSERT(right.is(r0)); |
| 6383 __ Ret(ne); | 6332 __ Ret(ne); |
| 6384 } | 6333 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6550 __ b(eq, miss); | 6499 __ b(eq, miss); |
| 6551 | 6500 |
| 6552 Label good; | 6501 Label good; |
| 6553 __ cmp(entity_name, tmp); | 6502 __ cmp(entity_name, tmp); |
| 6554 __ b(eq, &good); | 6503 __ b(eq, &good); |
| 6555 | 6504 |
| 6556 // Check if the entry name is not a unique name. | 6505 // Check if the entry name is not a unique name. |
| 6557 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); | 6506 __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); |
| 6558 __ ldrb(entity_name, | 6507 __ ldrb(entity_name, |
| 6559 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); | 6508 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); |
| 6560 __ tst(entity_name, Operand(kIsInternalizedMask)); | 6509 __ JumpIfNotUniqueName(entity_name, miss); |
| 6561 __ b(ne, &good); | |
| 6562 __ cmp(entity_name, Operand(SYMBOL_TYPE)); | |
| 6563 __ b(ne, miss); | |
| 6564 | |
| 6565 __ bind(&good); | 6510 __ bind(&good); |
| 6566 | 6511 |
| 6567 // Restore the properties. | 6512 // Restore the properties. |
| 6568 __ ldr(properties, | 6513 __ ldr(properties, |
| 6569 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 6514 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 6570 } | 6515 } |
| 6571 | 6516 |
| 6572 const int spill_mask = | 6517 const int spill_mask = |
| 6573 (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() | | 6518 (lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() | |
| 6574 r2.bit() | r1.bit() | r0.bit()); | 6519 r2.bit() | r1.bit() | r0.bit()); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6721 // Having undefined at this place means the name is not contained. | 6666 // Having undefined at this place means the name is not contained. |
| 6722 __ cmp(entry_key, Operand(undefined)); | 6667 __ cmp(entry_key, Operand(undefined)); |
| 6723 __ b(eq, ¬_in_dictionary); | 6668 __ b(eq, ¬_in_dictionary); |
| 6724 | 6669 |
| 6725 // Stop if found the property. | 6670 // Stop if found the property. |
| 6726 __ cmp(entry_key, Operand(key)); | 6671 __ cmp(entry_key, Operand(key)); |
| 6727 __ b(eq, &in_dictionary); | 6672 __ b(eq, &in_dictionary); |
| 6728 | 6673 |
| 6729 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { | 6674 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 6730 // Check if the entry name is not a unique name. | 6675 // Check if the entry name is not a unique name. |
| 6731 Label cont; | |
| 6732 __ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); | 6676 __ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); |
| 6733 __ ldrb(entry_key, | 6677 __ ldrb(entry_key, |
| 6734 FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); | 6678 FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); |
| 6735 __ tst(entry_key, Operand(kIsInternalizedMask)); | 6679 __ JumpIfNotUniqueName(entry_key, &maybe_in_dictionary); |
| 6736 __ b(ne, &cont); | |
| 6737 __ cmp(entry_key, Operand(SYMBOL_TYPE)); | |
| 6738 __ b(ne, &maybe_in_dictionary); | |
| 6739 __ bind(&cont); | |
| 6740 } | 6680 } |
| 6741 } | 6681 } |
| 6742 | 6682 |
| 6743 __ bind(&maybe_in_dictionary); | 6683 __ bind(&maybe_in_dictionary); |
| 6744 // If we are doing negative lookup then probing failure should be | 6684 // If we are doing negative lookup then probing failure should be |
| 6745 // treated as a lookup success. For positive lookup probing failure | 6685 // treated as a lookup success. For positive lookup probing failure |
| 6746 // should be treated as lookup failure. | 6686 // should be treated as lookup failure. |
| 6747 if (mode_ == POSITIVE_LOOKUP) { | 6687 if (mode_ == POSITIVE_LOOKUP) { |
| 6748 __ mov(result, Operand::Zero()); | 6688 __ mov(result, Operand::Zero()); |
| 6749 __ Ret(); | 6689 __ Ret(); |
| (...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7334 Label okay_here; | 7274 Label okay_here; |
| 7335 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); | 7275 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); |
| 7336 __ cmp(r2, Operand(undefined_sentinel)); | 7276 __ cmp(r2, Operand(undefined_sentinel)); |
| 7337 __ b(eq, &okay_here); | 7277 __ b(eq, &okay_here); |
| 7338 __ ldr(r3, FieldMemOperand(r2, 0)); | 7278 __ ldr(r3, FieldMemOperand(r2, 0)); |
| 7339 __ cmp(r3, Operand(cell_map)); | 7279 __ cmp(r3, Operand(cell_map)); |
| 7340 __ Assert(eq, "Expected property cell in register ebx"); | 7280 __ Assert(eq, "Expected property cell in register ebx"); |
| 7341 __ bind(&okay_here); | 7281 __ bind(&okay_here); |
| 7342 } | 7282 } |
| 7343 | 7283 |
| 7344 if (FLAG_optimize_constructed_arrays) { | 7284 Label no_info, switch_ready; |
| 7345 Label no_info, switch_ready; | 7285 // Get the elements kind and case on that. |
| 7346 // Get the elements kind and case on that. | 7286 __ cmp(r2, Operand(undefined_sentinel)); |
| 7347 __ cmp(r2, Operand(undefined_sentinel)); | 7287 __ b(eq, &no_info); |
| 7348 __ b(eq, &no_info); | 7288 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); |
| 7349 __ ldr(r3, FieldMemOperand(r2, PropertyCell::kValueOffset)); | 7289 __ JumpIfNotSmi(r3, &no_info); |
| 7350 __ JumpIfNotSmi(r3, &no_info); | 7290 __ SmiUntag(r3); |
| 7351 __ SmiUntag(r3); | 7291 __ jmp(&switch_ready); |
| 7352 __ jmp(&switch_ready); | 7292 __ bind(&no_info); |
| 7353 __ bind(&no_info); | 7293 __ mov(r3, Operand(GetInitialFastElementsKind())); |
| 7354 __ mov(r3, Operand(GetInitialFastElementsKind())); | 7294 __ bind(&switch_ready); |
| 7355 __ bind(&switch_ready); | |
| 7356 | 7295 |
| 7357 if (argument_count_ == ANY) { | 7296 if (argument_count_ == ANY) { |
| 7358 Label not_zero_case, not_one_case; | 7297 Label not_zero_case, not_one_case; |
| 7359 __ tst(r0, r0); | 7298 __ tst(r0, r0); |
| 7360 __ b(ne, ¬_zero_case); | 7299 __ b(ne, ¬_zero_case); |
| 7361 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); | 7300 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); |
| 7362 | 7301 |
| 7363 __ bind(¬_zero_case); | 7302 __ bind(¬_zero_case); |
| 7364 __ cmp(r0, Operand(1)); | 7303 __ cmp(r0, Operand(1)); |
| 7365 __ b(gt, ¬_one_case); | 7304 __ b(gt, ¬_one_case); |
| 7366 CreateArrayDispatchOneArgument(masm); | 7305 CreateArrayDispatchOneArgument(masm); |
| 7367 | 7306 |
| 7368 __ bind(¬_one_case); | 7307 __ bind(¬_one_case); |
| 7369 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); | 7308 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); |
| 7370 } else if (argument_count_ == NONE) { | 7309 } else if (argument_count_ == NONE) { |
| 7371 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); | 7310 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); |
| 7372 } else if (argument_count_ == ONE) { | 7311 } else if (argument_count_ == ONE) { |
| 7373 CreateArrayDispatchOneArgument(masm); | 7312 CreateArrayDispatchOneArgument(masm); |
| 7374 } else if (argument_count_ == MORE_THAN_ONE) { | 7313 } else if (argument_count_ == MORE_THAN_ONE) { |
| 7375 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); | 7314 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); |
| 7376 } else { | |
| 7377 UNREACHABLE(); | |
| 7378 } | |
| 7379 } else { | 7315 } else { |
| 7380 Label generic_constructor; | 7316 UNREACHABLE(); |
| 7381 // Run the native code for the Array function called as a constructor. | |
| 7382 ArrayNativeCode(masm, &generic_constructor); | |
| 7383 | |
| 7384 // Jump to the generic construct code in case the specialized code cannot | |
| 7385 // handle the construction. | |
| 7386 __ bind(&generic_constructor); | |
| 7387 Handle<Code> generic_construct_stub = | |
| 7388 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
| 7389 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | |
| 7390 } | 7317 } |
| 7391 } | 7318 } |
| 7392 | 7319 |
| 7393 | 7320 |
| 7394 void InternalArrayConstructorStub::GenerateCase( | 7321 void InternalArrayConstructorStub::GenerateCase( |
| 7395 MacroAssembler* masm, ElementsKind kind) { | 7322 MacroAssembler* masm, ElementsKind kind) { |
| 7396 Label not_zero_case, not_one_case; | 7323 Label not_zero_case, not_one_case; |
| 7397 Label normal_sequence; | 7324 Label normal_sequence; |
| 7398 | 7325 |
| 7399 __ tst(r0, r0); | 7326 __ tst(r0, r0); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7441 | 7368 |
| 7442 // Initial map for the builtin Array function should be a map. | 7369 // Initial map for the builtin Array function should be a map. |
| 7443 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); | 7370 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); |
| 7444 // Will both indicate a NULL and a Smi. | 7371 // Will both indicate a NULL and a Smi. |
| 7445 __ tst(r3, Operand(kSmiTagMask)); | 7372 __ tst(r3, Operand(kSmiTagMask)); |
| 7446 __ Assert(ne, "Unexpected initial map for Array function"); | 7373 __ Assert(ne, "Unexpected initial map for Array function"); |
| 7447 __ CompareObjectType(r3, r3, r4, MAP_TYPE); | 7374 __ CompareObjectType(r3, r3, r4, MAP_TYPE); |
| 7448 __ Assert(eq, "Unexpected initial map for Array function"); | 7375 __ Assert(eq, "Unexpected initial map for Array function"); |
| 7449 } | 7376 } |
| 7450 | 7377 |
| 7451 if (FLAG_optimize_constructed_arrays) { | 7378 // Figure out the right elements kind |
| 7452 // Figure out the right elements kind | 7379 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); |
| 7453 __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset)); | 7380 // Load the map's "bit field 2" into |result|. We only need the first byte, |
| 7381 // but the following bit field extraction takes care of that anyway. |
| 7382 __ ldr(r3, FieldMemOperand(r3, Map::kBitField2Offset)); |
| 7383 // Retrieve elements_kind from bit field 2. |
| 7384 __ Ubfx(r3, r3, Map::kElementsKindShift, Map::kElementsKindBitCount); |
| 7454 | 7385 |
| 7455 // Load the map's "bit field 2" into |result|. We only need the first byte, | 7386 if (FLAG_debug_code) { |
| 7456 // but the following bit field extraction takes care of that anyway. | 7387 Label done; |
| 7457 __ ldr(r3, FieldMemOperand(r3, Map::kBitField2Offset)); | 7388 __ cmp(r3, Operand(FAST_ELEMENTS)); |
| 7458 // Retrieve elements_kind from bit field 2. | 7389 __ b(eq, &done); |
| 7459 __ Ubfx(r3, r3, Map::kElementsKindShift, Map::kElementsKindBitCount); | 7390 __ cmp(r3, Operand(FAST_HOLEY_ELEMENTS)); |
| 7391 __ Assert(eq, |
| 7392 "Invalid ElementsKind for InternalArray or InternalPackedArray"); |
| 7393 __ bind(&done); |
| 7394 } |
| 7460 | 7395 |
| 7461 if (FLAG_debug_code) { | 7396 Label fast_elements_case; |
| 7462 Label done; | 7397 __ cmp(r3, Operand(FAST_ELEMENTS)); |
| 7463 __ cmp(r3, Operand(FAST_ELEMENTS)); | 7398 __ b(eq, &fast_elements_case); |
| 7464 __ b(eq, &done); | 7399 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
| 7465 __ cmp(r3, Operand(FAST_HOLEY_ELEMENTS)); | |
| 7466 __ Assert(eq, | |
| 7467 "Invalid ElementsKind for InternalArray or InternalPackedArray"); | |
| 7468 __ bind(&done); | |
| 7469 } | |
| 7470 | 7400 |
| 7471 Label fast_elements_case; | 7401 __ bind(&fast_elements_case); |
| 7472 __ cmp(r3, Operand(FAST_ELEMENTS)); | 7402 GenerateCase(masm, FAST_ELEMENTS); |
| 7473 __ b(eq, &fast_elements_case); | |
| 7474 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | |
| 7475 | |
| 7476 __ bind(&fast_elements_case); | |
| 7477 GenerateCase(masm, FAST_ELEMENTS); | |
| 7478 } else { | |
| 7479 Label generic_constructor; | |
| 7480 // Run the native code for the Array function called as constructor. | |
| 7481 ArrayNativeCode(masm, &generic_constructor); | |
| 7482 | |
| 7483 // Jump to the generic construct code in case the specialized code cannot | |
| 7484 // handle the construction. | |
| 7485 __ bind(&generic_constructor); | |
| 7486 Handle<Code> generic_construct_stub = | |
| 7487 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
| 7488 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | |
| 7489 } | |
| 7490 } | 7403 } |
| 7491 | 7404 |
| 7492 | 7405 |
| 7493 #undef __ | 7406 #undef __ |
| 7494 | 7407 |
| 7495 } } // namespace v8::internal | 7408 } } // namespace v8::internal |
| 7496 | 7409 |
| 7497 #endif // V8_TARGET_ARCH_ARM | 7410 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |