| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/crankshaft/arm64/lithium-codegen-arm64.h" | 5 #include "src/crankshaft/arm64/lithium-codegen-arm64.h" |
| 6 | 6 |
| 7 #include "src/arm64/frames-arm64.h" | 7 #include "src/arm64/frames-arm64.h" |
| 8 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
| 9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 1510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1521 Label invoke, loop; | 1521 Label invoke, loop; |
| 1522 // length is a small non-negative integer, due to the test above. | 1522 // length is a small non-negative integer, due to the test above. |
| 1523 __ Cbz(length, &invoke); | 1523 __ Cbz(length, &invoke); |
| 1524 __ Bind(&loop); | 1524 __ Bind(&loop); |
| 1525 __ Ldr(scratch, MemOperand(elements, length, SXTW, kPointerSizeLog2)); | 1525 __ Ldr(scratch, MemOperand(elements, length, SXTW, kPointerSizeLog2)); |
| 1526 __ Push(scratch); | 1526 __ Push(scratch); |
| 1527 __ Subs(length, length, 1); | 1527 __ Subs(length, length, 1); |
| 1528 __ B(ne, &loop); | 1528 __ B(ne, &loop); |
| 1529 | 1529 |
| 1530 __ Bind(&invoke); | 1530 __ Bind(&invoke); |
| 1531 |
| 1532 InvokeFlag flag = CALL_FUNCTION; |
| 1533 if (instr->hydrogen()->tail_call_mode() == TailCallMode::kAllow) { |
| 1534 // TODO(ishell): drop current frame before pushing arguments to the stack. |
| 1535 flag = JUMP_FUNCTION; |
| 1536 ParameterCount actual(x0); |
| 1537 // It is safe to use x3, x4 and x5 as scratch registers here given that |
| 1538 // 1) we are not going to return to caller function anyway, |
| 1539 // 2) x3 (new.target) will be initialized below. |
| 1540 PrepareForTailCall(actual, x3, x4, x5); |
| 1541 } |
| 1542 |
| 1531 DCHECK(instr->HasPointerMap()); | 1543 DCHECK(instr->HasPointerMap()); |
| 1532 LPointerMap* pointers = instr->pointer_map(); | 1544 LPointerMap* pointers = instr->pointer_map(); |
| 1533 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); | 1545 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); |
| 1534 // The number of arguments is stored in argc (receiver) which is x0, as | 1546 // The number of arguments is stored in argc (receiver) which is x0, as |
| 1535 // expected by InvokeFunction. | 1547 // expected by InvokeFunction. |
| 1536 ParameterCount actual(argc); | 1548 ParameterCount actual(argc); |
| 1537 __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, | 1549 __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator); |
| 1538 safepoint_generator); | |
| 1539 } | 1550 } |
| 1540 | 1551 |
| 1541 | 1552 |
| 1542 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { | 1553 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { |
| 1543 Register result = ToRegister(instr->result()); | 1554 Register result = ToRegister(instr->result()); |
| 1544 | 1555 |
| 1545 if (instr->hydrogen()->from_inlined()) { | 1556 if (instr->hydrogen()->from_inlined()) { |
| 1546 // When we are inside an inlined function, the arguments are the last things | 1557 // When we are inside an inlined function, the arguments are the last things |
| 1547 // that have been pushed on the stack. Therefore the arguments array can be | 1558 // that have been pushed on the stack. Therefore the arguments array can be |
| 1548 // accessed directly from jssp. | 1559 // accessed directly from jssp. |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1829 | 1840 |
| 1830 if (!expected.IsGeneric()) { | 1841 if (!expected.IsGeneric()) { |
| 1831 // We've seen something for the first time -> deopt. | 1842 // We've seen something for the first time -> deopt. |
| 1832 // This can only happen if we are not generic already. | 1843 // This can only happen if we are not generic already. |
| 1833 Deoptimize(instr, Deoptimizer::kUnexpectedObject); | 1844 Deoptimize(instr, Deoptimizer::kUnexpectedObject); |
| 1834 } | 1845 } |
| 1835 } | 1846 } |
| 1836 } | 1847 } |
| 1837 } | 1848 } |
| 1838 | 1849 |
| 1839 | |
| 1840 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 1850 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
| 1841 int formal_parameter_count, int arity, | 1851 int formal_parameter_count, int arity, |
| 1842 LInstruction* instr) { | 1852 bool is_tail_call, LInstruction* instr) { |
| 1843 bool dont_adapt_arguments = | 1853 bool dont_adapt_arguments = |
| 1844 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; | 1854 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
| 1845 bool can_invoke_directly = | 1855 bool can_invoke_directly = |
| 1846 dont_adapt_arguments || formal_parameter_count == arity; | 1856 dont_adapt_arguments || formal_parameter_count == arity; |
| 1847 | 1857 |
| 1848 // The function interface relies on the following register assignments. | 1858 // The function interface relies on the following register assignments. |
| 1849 Register function_reg = x1; | 1859 Register function_reg = x1; |
| 1850 Register arity_reg = x0; | 1860 Register arity_reg = x0; |
| 1851 | 1861 |
| 1852 LPointerMap* pointers = instr->pointer_map(); | 1862 LPointerMap* pointers = instr->pointer_map(); |
| 1853 | 1863 |
| 1854 if (FLAG_debug_code) { | 1864 if (FLAG_debug_code) { |
| 1855 Label is_not_smi; | 1865 Label is_not_smi; |
| 1856 // Try to confirm that function_reg (x1) is a tagged pointer. | 1866 // Try to confirm that function_reg (x1) is a tagged pointer. |
| 1857 __ JumpIfNotSmi(function_reg, &is_not_smi); | 1867 __ JumpIfNotSmi(function_reg, &is_not_smi); |
| 1858 __ Abort(kExpectedFunctionObject); | 1868 __ Abort(kExpectedFunctionObject); |
| 1859 __ Bind(&is_not_smi); | 1869 __ Bind(&is_not_smi); |
| 1860 } | 1870 } |
| 1861 | 1871 |
| 1862 if (can_invoke_directly) { | 1872 if (can_invoke_directly) { |
| 1863 // Change context. | 1873 // Change context. |
| 1864 __ Ldr(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); | 1874 __ Ldr(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); |
| 1865 | 1875 |
| 1866 // Always initialize new target and number of actual arguments. | 1876 // Always initialize new target and number of actual arguments. |
| 1867 __ LoadRoot(x3, Heap::kUndefinedValueRootIndex); | 1877 __ LoadRoot(x3, Heap::kUndefinedValueRootIndex); |
| 1868 __ Mov(arity_reg, arity); | 1878 __ Mov(arity_reg, arity); |
| 1869 | 1879 |
| 1880 bool is_self_call = function.is_identical_to(info()->closure()); |
| 1881 |
| 1870 // Invoke function. | 1882 // Invoke function. |
| 1871 __ Ldr(x10, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); | 1883 if (is_self_call) { |
| 1872 __ Call(x10); | 1884 Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location())); |
| 1885 if (is_tail_call) { |
| 1886 __ Jump(self, RelocInfo::CODE_TARGET); |
| 1887 } else { |
| 1888 __ Call(self, RelocInfo::CODE_TARGET); |
| 1889 } |
| 1890 } else { |
| 1891 __ Ldr(x10, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); |
| 1892 if (is_tail_call) { |
| 1893 __ Jump(x10); |
| 1894 } else { |
| 1895 __ Call(x10); |
| 1896 } |
| 1897 } |
| 1873 | 1898 |
| 1874 // Set up deoptimization. | 1899 if (!is_tail_call) { |
| 1875 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); | 1900 // Set up deoptimization. |
| 1901 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
| 1902 } |
| 1876 } else { | 1903 } else { |
| 1877 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 1904 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
| 1878 ParameterCount count(arity); | 1905 ParameterCount actual(arity); |
| 1879 ParameterCount expected(formal_parameter_count); | 1906 ParameterCount expected(formal_parameter_count); |
| 1880 __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator); | 1907 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 1908 __ InvokeFunction(function_reg, expected, actual, flag, generator); |
| 1881 } | 1909 } |
| 1882 } | 1910 } |
| 1883 | 1911 |
| 1884 | |
| 1885 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { | 1912 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { |
| 1886 DCHECK(instr->IsMarkedAsCall()); | 1913 DCHECK(instr->IsMarkedAsCall()); |
| 1887 DCHECK(ToRegister(instr->result()).Is(x0)); | 1914 DCHECK(ToRegister(instr->result()).Is(x0)); |
| 1888 | 1915 |
| 1889 if (instr->hydrogen()->IsTailCall()) { | 1916 if (instr->hydrogen()->IsTailCall()) { |
| 1890 if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL); | 1917 if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL); |
| 1891 | 1918 |
| 1892 if (instr->target()->IsConstantOperand()) { | 1919 if (instr->target()->IsConstantOperand()) { |
| 1893 LConstantOperand* target = LConstantOperand::cast(instr->target()); | 1920 LConstantOperand* target = LConstantOperand::cast(instr->target()); |
| 1894 Handle<Code> code = Handle<Code>::cast(ToHandle(target)); | 1921 Handle<Code> code = Handle<Code>::cast(ToHandle(target)); |
| (...skipping 884 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2779 DoGap(instr); | 2806 DoGap(instr); |
| 2780 } | 2807 } |
| 2781 | 2808 |
| 2782 | 2809 |
| 2783 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { | 2810 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
| 2784 Register value = ToRegister32(instr->value()); | 2811 Register value = ToRegister32(instr->value()); |
| 2785 DoubleRegister result = ToDoubleRegister(instr->result()); | 2812 DoubleRegister result = ToDoubleRegister(instr->result()); |
| 2786 __ Scvtf(result, value); | 2813 __ Scvtf(result, value); |
| 2787 } | 2814 } |
| 2788 | 2815 |
| 2816 void LCodeGen::PrepareForTailCall(const ParameterCount& actual, |
| 2817 Register scratch1, Register scratch2, |
| 2818 Register scratch3) { |
| 2819 #if DEBUG |
| 2820 if (actual.is_reg()) { |
| 2821 DCHECK(!AreAliased(actual.reg(), scratch1, scratch2, scratch3)); |
| 2822 } else { |
| 2823 DCHECK(!AreAliased(scratch1, scratch2, scratch3)); |
| 2824 } |
| 2825 #endif |
| 2826 if (FLAG_code_comments) { |
| 2827 if (actual.is_reg()) { |
| 2828 Comment(";;; PrepareForTailCall, actual: %s {", actual.reg().ToString()); |
| 2829 } else { |
| 2830 Comment(";;; PrepareForTailCall, actual: %d {", actual.immediate()); |
| 2831 } |
| 2832 } |
| 2833 |
| 2834 // Check if next frame is an arguments adaptor frame. |
| 2835 Register caller_args_count_reg = scratch1; |
| 2836 Label no_arguments_adaptor, formal_parameter_count_loaded; |
| 2837 __ Ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 2838 __ Ldr(scratch3, |
| 2839 MemOperand(scratch2, StandardFrameConstants::kContextOffset)); |
| 2840 __ Cmp(scratch3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2841 __ B(ne, &no_arguments_adaptor); |
| 2842 |
| 2843 // Drop current frame and load arguments count from arguments adaptor frame. |
| 2844 __ mov(fp, scratch2); |
| 2845 __ Ldr(caller_args_count_reg, |
| 2846 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2847 __ SmiUntag(caller_args_count_reg); |
| 2848 __ B(&formal_parameter_count_loaded); |
| 2849 |
| 2850 __ bind(&no_arguments_adaptor); |
| 2851 // Load caller's formal parameter count |
| 2852 __ Mov(caller_args_count_reg, |
| 2853 Immediate(info()->literal()->parameter_count())); |
| 2854 |
| 2855 __ bind(&formal_parameter_count_loaded); |
| 2856 __ PrepareForTailCall(actual, caller_args_count_reg, scratch2, scratch3); |
| 2857 |
| 2858 Comment(";;; }"); |
| 2859 } |
| 2789 | 2860 |
| 2790 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { | 2861 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
| 2862 HInvokeFunction* hinstr = instr->hydrogen(); |
| 2791 DCHECK(ToRegister(instr->context()).is(cp)); | 2863 DCHECK(ToRegister(instr->context()).is(cp)); |
| 2792 // The function is required to be in x1. | 2864 // The function is required to be in x1. |
| 2793 DCHECK(ToRegister(instr->function()).is(x1)); | 2865 DCHECK(ToRegister(instr->function()).is(x1)); |
| 2794 DCHECK(instr->HasPointerMap()); | 2866 DCHECK(instr->HasPointerMap()); |
| 2795 | 2867 |
| 2796 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); | 2868 bool is_tail_call = hinstr->tail_call_mode() == TailCallMode::kAllow; |
| 2869 |
| 2870 if (is_tail_call) { |
| 2871 ParameterCount actual(instr->arity()); |
| 2872 // It is safe to use x3, x4 and x5 as scratch registers here given that |
| 2873 // 1) we are not going to return to caller function anyway, |
| 2874 // 2) x3 (new.target) will be initialized below. |
| 2875 PrepareForTailCall(actual, x3, x4, x5); |
| 2876 } |
| 2877 |
| 2878 Handle<JSFunction> known_function = hinstr->known_function(); |
| 2797 if (known_function.is_null()) { | 2879 if (known_function.is_null()) { |
| 2798 LPointerMap* pointers = instr->pointer_map(); | 2880 LPointerMap* pointers = instr->pointer_map(); |
| 2799 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 2881 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
| 2800 ParameterCount count(instr->arity()); | 2882 ParameterCount actual(instr->arity()); |
| 2801 __ InvokeFunction(x1, no_reg, count, CALL_FUNCTION, generator); | 2883 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 2884 __ InvokeFunction(x1, no_reg, actual, flag, generator); |
| 2802 } else { | 2885 } else { |
| 2803 CallKnownFunction(known_function, | 2886 CallKnownFunction(known_function, hinstr->formal_parameter_count(), |
| 2804 instr->hydrogen()->formal_parameter_count(), | 2887 instr->arity(), is_tail_call, instr); |
| 2805 instr->arity(), instr); | |
| 2806 } | 2888 } |
| 2807 RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta()); | 2889 RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta()); |
| 2808 } | 2890 } |
| 2809 | 2891 |
| 2810 | 2892 |
| 2811 Condition LCodeGen::EmitIsString(Register input, | 2893 Condition LCodeGen::EmitIsString(Register input, |
| 2812 Register temp1, | 2894 Register temp1, |
| 2813 Label* is_not_string, | 2895 Label* is_not_string, |
| 2814 SmiCheck check_needed = INLINE_SMI_CHECK) { | 2896 SmiCheck check_needed = INLINE_SMI_CHECK) { |
| 2815 if (check_needed == INLINE_SMI_CHECK) { | 2897 if (check_needed == INLINE_SMI_CHECK) { |
| (...skipping 2845 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5661 | 5743 |
| 5662 | 5744 |
| 5663 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { | 5745 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { |
| 5664 Register context = ToRegister(instr->context()); | 5746 Register context = ToRegister(instr->context()); |
| 5665 __ Str(context, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 5747 __ Str(context, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 5666 } | 5748 } |
| 5667 | 5749 |
| 5668 | 5750 |
| 5669 } // namespace internal | 5751 } // namespace internal |
| 5670 } // namespace v8 | 5752 } // namespace v8 |
| OLD | NEW |