diff --git a/src/backend.rs b/src/backend.rs index 994d0c5e96..f9bc16125c 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -346,8 +346,9 @@ pub fn copy_incoming_arg(ctx: &mut Context, frame_size: u32, arg_pos: u32) { ); } -pub fn pass_outgoing_args(ctx: &mut Context, arity: u32) { - let mut stack_args = vec![]; +#[must_use] +fn pass_outgoing_args(ctx: &mut Context, arity: u32) -> i32 { + let mut stack_args = Vec::with_capacity((arity as usize).saturating_sub(ARGS_IN_GPRS.len())); for arg_pos in (0..arity).rev() { ctx.sp_depth.free(1); @@ -368,22 +369,39 @@ pub fn pass_outgoing_args(ctx: &mut Context, arity: u32) { } } - for gpr in stack_args { + let num_stack_args = stack_args.len() as i32; + dynasm!(ctx.asm + ; sub rsp, num_stack_args + ); + for (stack_slot, gpr) in stack_args.into_iter().rev().enumerate() { + let offset = (stack_slot * WORD_SIZE as usize) as i32; dynasm!(ctx.asm - ; push Rq(gpr) + ; mov [rsp + offset], Rq(gpr) ); ctx.regs.release_scratch_gpr(gpr); } + + num_stack_args } -pub fn call_direct(ctx: &mut Context, index: u32, return_arity: u32) { +fn post_call_cleanup(ctx: &mut Context, num_stack_args: i32) { + dynasm!(ctx.asm + ; add rsp, num_stack_args + ); +} + +pub fn call_direct(ctx: &mut Context, index: u32, arg_arity: u32, return_arity: u32) { assert!(return_arity == 0 || return_arity == 1); + let num_stack_args = pass_outgoing_args(ctx, arg_arity); + let label = &ctx.func_starts[index as usize].1; dynasm!(ctx.asm ; call =>*label ); + post_call_cleanup(ctx, num_stack_args); + if return_arity == 1 { dynasm!(ctx.asm ; push rax diff --git a/src/function_body.rs b/src/function_body.rs index 00e07025c6..925b32e502 100644 --- a/src/function_body.rs +++ b/src/function_body.rs @@ -225,8 +225,12 @@ pub fn translate( // TODO: this implementation assumes that this function is locally defined. - pass_outgoing_args(&mut ctx, callee_ty.params.len() as u32); - call_direct(&mut ctx, function_index, callee_ty.returns.len() as u32); + call_direct( + &mut ctx, + function_index, + callee_ty.params.len() as u32, + callee_ty.returns.len() as u32, + ); } _ => { trap(&mut ctx);