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 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
6 | 6 |
7 #include "src/arm64/frames-arm64.h" | 7 #include "src/arm64/frames-arm64.h" |
8 #include "src/assembler.h" | 8 #include "src/assembler.h" |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/base/division-by-constant.h" | 10 #include "src/base/division-by-constant.h" |
(...skipping 1773 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1784 | 1784 |
1785 void MacroAssembler::CallCFunction(ExternalReference function, | 1785 void MacroAssembler::CallCFunction(ExternalReference function, |
1786 int num_of_reg_args, | 1786 int num_of_reg_args, |
1787 int num_of_double_args) { | 1787 int num_of_double_args) { |
1788 UseScratchRegisterScope temps(this); | 1788 UseScratchRegisterScope temps(this); |
1789 Register temp = temps.AcquireX(); | 1789 Register temp = temps.AcquireX(); |
1790 Mov(temp, function); | 1790 Mov(temp, function); |
1791 CallCFunction(temp, num_of_reg_args, num_of_double_args); | 1791 CallCFunction(temp, num_of_reg_args, num_of_double_args); |
1792 } | 1792 } |
1793 | 1793 |
| 1794 static const int kRegisterPassedArguments = 8; |
1794 | 1795 |
1795 void MacroAssembler::CallCFunction(Register function, | 1796 void MacroAssembler::CallCFunction(Register function, |
1796 int num_of_reg_args, | 1797 int num_of_reg_args, |
1797 int num_of_double_args) { | 1798 int num_of_double_args) { |
1798 DCHECK(has_frame()); | 1799 DCHECK(has_frame()); |
1799 // We can pass 8 integer arguments in registers. If we need to pass more than | |
1800 // that, we'll need to implement support for passing them on the stack. | |
1801 DCHECK(num_of_reg_args <= 8); | |
1802 | 1800 |
1803 // If we're passing doubles, we're limited to the following prototypes | 1801 // If we're passing doubles, we're limited to the following prototypes |
1804 // (defined by ExternalReference::Type): | 1802 // (defined by ExternalReference::Type): |
1805 // BUILTIN_COMPARE_CALL: int f(double, double) | 1803 // BUILTIN_COMPARE_CALL: int f(double, double) |
1806 // BUILTIN_FP_FP_CALL: double f(double, double) | 1804 // BUILTIN_FP_FP_CALL: double f(double, double) |
1807 // BUILTIN_FP_CALL: double f(double) | 1805 // BUILTIN_FP_CALL: double f(double) |
1808 // BUILTIN_FP_INT_CALL: double f(double, int) | 1806 // BUILTIN_FP_INT_CALL: double f(double, int) |
1809 if (num_of_double_args > 0) { | 1807 if (num_of_double_args > 0) { |
1810 DCHECK(num_of_reg_args <= 1); | 1808 DCHECK(num_of_reg_args <= 1); |
1811 DCHECK((num_of_double_args + num_of_reg_args) <= 2); | 1809 DCHECK((num_of_double_args + num_of_reg_args) <= 2); |
1812 } | 1810 } |
1813 | 1811 |
| 1812 // We rely on the frame alignment being 16 bytes, which means we never need |
| 1813 // to align the CSP by an unknown number of bytes and we always know the delta |
| 1814 // between the stack pointer and the frame pointer. |
| 1815 DCHECK(ActivationFrameAlignment() == 16); |
1814 | 1816 |
1815 // If the stack pointer is not csp, we need to derive an aligned csp from the | 1817 // If the stack pointer is not csp, we need to derive an aligned csp from the |
1816 // current stack pointer. | 1818 // current stack pointer. |
1817 const Register old_stack_pointer = StackPointer(); | 1819 const Register old_stack_pointer = StackPointer(); |
1818 if (!csp.Is(old_stack_pointer)) { | 1820 if (!csp.Is(old_stack_pointer)) { |
1819 AssertStackConsistency(); | 1821 AssertStackConsistency(); |
1820 | 1822 |
1821 int sp_alignment = ActivationFrameAlignment(); | 1823 int sp_alignment = ActivationFrameAlignment(); |
1822 // The ABI mandates at least 16-byte alignment. | |
1823 DCHECK(sp_alignment >= 16); | |
1824 DCHECK(base::bits::IsPowerOfTwo32(sp_alignment)); | |
1825 | |
1826 // The current stack pointer is a callee saved register, and is preserved | 1824 // The current stack pointer is a callee saved register, and is preserved |
1827 // across the call. | 1825 // across the call. |
1828 DCHECK(kCalleeSaved.IncludesAliasOf(old_stack_pointer)); | 1826 DCHECK(kCalleeSaved.IncludesAliasOf(old_stack_pointer)); |
1829 | 1827 |
1830 // Align and synchronize the system stack pointer with jssp. | 1828 // If more than eight arguments are passed to the function, we expect the |
1831 Bic(csp, old_stack_pointer, sp_alignment - 1); | 1829 // ninth argument onwards to have been placed on the csp-based stack |
| 1830 // already. We assume csp already points to the last stack-passed argument |
| 1831 // in that case. |
| 1832 // Otherwise, align and synchronize the system stack pointer with jssp. |
| 1833 if (num_of_reg_args <= kRegisterPassedArguments) { |
| 1834 Bic(csp, old_stack_pointer, sp_alignment - 1); |
| 1835 } |
1832 SetStackPointer(csp); | 1836 SetStackPointer(csp); |
1833 } | 1837 } |
1834 | 1838 |
1835 // Call directly. The function called cannot cause a GC, or allow preemption, | 1839 // Call directly. The function called cannot cause a GC, or allow preemption, |
1836 // so the return address in the link register stays correct. | 1840 // so the return address in the link register stays correct. |
1837 Call(function); | 1841 Call(function); |
1838 | 1842 |
1839 if (!csp.Is(old_stack_pointer)) { | 1843 if (csp.Is(old_stack_pointer)) { |
| 1844 if (num_of_reg_args > kRegisterPassedArguments) { |
| 1845 // Drop the register passed arguments. |
| 1846 int claim_slots = RoundUp(num_of_reg_args - kRegisterPassedArguments, 2); |
| 1847 Drop(claim_slots); |
| 1848 } |
| 1849 } else { |
| 1850 DCHECK(jssp.Is(old_stack_pointer)); |
1840 if (emit_debug_code()) { | 1851 if (emit_debug_code()) { |
1841 // Because the stack pointer must be aligned on a 16-byte boundary, the | |
1842 // aligned csp can be up to 12 bytes below the jssp. This is the case | |
1843 // where we only pushed one W register on top of an aligned jssp. | |
1844 UseScratchRegisterScope temps(this); | 1852 UseScratchRegisterScope temps(this); |
1845 Register temp = temps.AcquireX(); | 1853 Register temp = temps.AcquireX(); |
1846 DCHECK(ActivationFrameAlignment() == 16); | 1854 |
1847 Sub(temp, csp, old_stack_pointer); | 1855 if (num_of_reg_args > kRegisterPassedArguments) { |
1848 // We want temp <= 0 && temp >= -12. | 1856 // We don't need to drop stack arguments, as the stack pointer will be |
1849 Cmp(temp, 0); | 1857 // jssp when returning from this function. However, in debug builds, we |
1850 Ccmp(temp, -12, NFlag, le); | 1858 // can check that jssp is as expected. |
1851 Check(ge, kTheStackWasCorruptedByMacroAssemblerCall); | 1859 int claim_slots = |
| 1860 RoundUp(num_of_reg_args - kRegisterPassedArguments, 2); |
| 1861 |
| 1862 // Check jssp matches the previous value on the stack. |
| 1863 Ldr(temp, MemOperand(csp, claim_slots * kPointerSize)); |
| 1864 Cmp(jssp, temp); |
| 1865 Check(eq, kTheStackWasCorruptedByMacroAssemblerCall); |
| 1866 } else { |
| 1867 // Because the stack pointer must be aligned on a 16-byte boundary, the |
| 1868 // aligned csp can be up to 12 bytes below the jssp. This is the case |
| 1869 // where we only pushed one W register on top of an aligned jssp. |
| 1870 Sub(temp, csp, old_stack_pointer); |
| 1871 // We want temp <= 0 && temp >= -12. |
| 1872 Cmp(temp, 0); |
| 1873 Ccmp(temp, -12, NFlag, le); |
| 1874 Check(ge, kTheStackWasCorruptedByMacroAssemblerCall); |
| 1875 } |
1852 } | 1876 } |
1853 SetStackPointer(old_stack_pointer); | 1877 SetStackPointer(old_stack_pointer); |
1854 } | 1878 } |
1855 } | 1879 } |
1856 | 1880 |
1857 | 1881 |
1858 void MacroAssembler::Jump(Register target) { | 1882 void MacroAssembler::Jump(Register target) { |
1859 Br(target); | 1883 Br(target); |
1860 } | 1884 } |
1861 | 1885 |
(...skipping 2723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4585 } | 4609 } |
4586 | 4610 |
4587 | 4611 |
4588 #undef __ | 4612 #undef __ |
4589 | 4613 |
4590 | 4614 |
4591 } // namespace internal | 4615 } // namespace internal |
4592 } // namespace v8 | 4616 } // namespace v8 |
4593 | 4617 |
4594 #endif // V8_TARGET_ARCH_ARM64 | 4618 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |