Index: src/arm64/macro-assembler-arm64.cc |
diff --git a/src/arm64/macro-assembler-arm64.cc b/src/arm64/macro-assembler-arm64.cc |
index 5edcd7b0449bff8457356c544eef0456b587b7b5..8cdfa5d9efe6e03a1f9c9a504d50bbf12ce646cd 100644 |
--- a/src/arm64/macro-assembler-arm64.cc |
+++ b/src/arm64/macro-assembler-arm64.cc |
@@ -1791,14 +1791,12 @@ void MacroAssembler::CallCFunction(ExternalReference function, |
CallCFunction(temp, num_of_reg_args, num_of_double_args); |
} |
+static const int kRegisterPassedArguments = 8; |
void MacroAssembler::CallCFunction(Register function, |
int num_of_reg_args, |
int num_of_double_args) { |
DCHECK(has_frame()); |
- // We can pass 8 integer arguments in registers. If we need to pass more than |
- // that, we'll need to implement support for passing them on the stack. |
- DCHECK(num_of_reg_args <= 8); |
// If we're passing doubles, we're limited to the following prototypes |
// (defined by ExternalReference::Type): |
@@ -1811,6 +1809,10 @@ void MacroAssembler::CallCFunction(Register function, |
DCHECK((num_of_double_args + num_of_reg_args) <= 2); |
} |
+ // We rely on the frame alignment being 16 bytes, which means we never need |
+ // to align the CSP by an unknown number of bytes and we always know the delta |
+ // between the stack pointer and the frame pointer. |
+ DCHECK(ActivationFrameAlignment() == 16); |
// If the stack pointer is not csp, we need to derive an aligned csp from the |
// current stack pointer. |
@@ -1819,16 +1821,18 @@ void MacroAssembler::CallCFunction(Register function, |
AssertStackConsistency(); |
int sp_alignment = ActivationFrameAlignment(); |
- // The ABI mandates at least 16-byte alignment. |
- DCHECK(sp_alignment >= 16); |
- DCHECK(base::bits::IsPowerOfTwo32(sp_alignment)); |
- |
// The current stack pointer is a callee saved register, and is preserved |
// across the call. |
DCHECK(kCalleeSaved.IncludesAliasOf(old_stack_pointer)); |
- // Align and synchronize the system stack pointer with jssp. |
- Bic(csp, old_stack_pointer, sp_alignment - 1); |
+ // If more than eight arguments are passed to the function, we expect the |
+ // ninth argument onwards to have been placed on the csp-based stack |
+ // already. We assume csp already points to the last stack-passed argument |
+ // in that case. |
+ // Otherwise, align and synchronize the system stack pointer with jssp. |
+ if (num_of_reg_args <= kRegisterPassedArguments) { |
+ Bic(csp, old_stack_pointer, sp_alignment - 1); |
+ } |
SetStackPointer(csp); |
} |
@@ -1836,19 +1840,39 @@ void MacroAssembler::CallCFunction(Register function, |
// so the return address in the link register stays correct. |
Call(function); |
- if (!csp.Is(old_stack_pointer)) { |
+ if (csp.Is(old_stack_pointer)) { |
+ if (num_of_reg_args > kRegisterPassedArguments) { |
+ // Drop the register passed arguments. |
+ int claim_slots = RoundUp(num_of_reg_args - kRegisterPassedArguments, 2); |
+ Drop(claim_slots); |
+ } |
+ } else { |
+ DCHECK(jssp.Is(old_stack_pointer)); |
if (emit_debug_code()) { |
- // Because the stack pointer must be aligned on a 16-byte boundary, the |
- // aligned csp can be up to 12 bytes below the jssp. This is the case |
- // where we only pushed one W register on top of an aligned jssp. |
UseScratchRegisterScope temps(this); |
Register temp = temps.AcquireX(); |
- DCHECK(ActivationFrameAlignment() == 16); |
- Sub(temp, csp, old_stack_pointer); |
- // We want temp <= 0 && temp >= -12. |
- Cmp(temp, 0); |
- Ccmp(temp, -12, NFlag, le); |
- Check(ge, kTheStackWasCorruptedByMacroAssemblerCall); |
+ |
+ if (num_of_reg_args > kRegisterPassedArguments) { |
+ // We don't need to drop stack arguments, as the stack pointer will be |
+ // jssp when returning from this function. However, in debug builds, we |
+ // can check that jssp is as expected. |
+ int claim_slots = |
+ RoundUp(num_of_reg_args - kRegisterPassedArguments, 2); |
+ |
+ // Check jssp matches the previous value on the stack. |
+ Ldr(temp, MemOperand(csp, claim_slots * kPointerSize)); |
+ Cmp(jssp, temp); |
+ Check(eq, kTheStackWasCorruptedByMacroAssemblerCall); |
+ } else { |
+ // Because the stack pointer must be aligned on a 16-byte boundary, the |
+ // aligned csp can be up to 12 bytes below the jssp. This is the case |
+ // where we only pushed one W register on top of an aligned jssp. |
+ Sub(temp, csp, old_stack_pointer); |
+ // We want temp <= 0 && temp >= -12. |
+ Cmp(temp, 0); |
+ Ccmp(temp, -12, NFlag, le); |
+ Check(ge, kTheStackWasCorruptedByMacroAssemblerCall); |
+ } |
} |
SetStackPointer(old_stack_pointer); |
} |