Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: src/crankshaft/arm64/lithium-codegen-arm64.cc

Issue 1760253003: [crankshaft] Support ES6 tail call elimination. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@tco-crank-2
Patch Set: Addressing comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/crankshaft/arm64/lithium-codegen-arm64.h ('k') | src/crankshaft/hydrogen.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/crankshaft/arm64/lithium-codegen-arm64.h ('k') | src/crankshaft/hydrogen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698