#include "psm.h"
/* NOTE: fastcall calling convention used on all x86 targets */

.text

#if CFG_TARGET_OS_darwin || CFG_TARGET_OS_macos || CFG_TARGET_OS_ios

#define GLOBL(fnname) .globl _##fnname
#define TYPE(fnname)
#define FUNCTION(fnname) _##fnname
#define SIZE(fnname,endlabel)

#else

#define GLOBL(fnname) .globl fnname
#define TYPE(fnname) .type fnname,@function
#define FUNCTION(fnname) fnname
#define SIZE(fnname,endlabel) .size fnname,endlabel-fnname

#endif


GLOBL(rust_psm_stack_direction)
.p2align 4
TYPE(rust_psm_stack_direction)
FUNCTION(rust_psm_stack_direction):
/* extern "fastcall" fn() -> u8 (%al) */
.cfi_startproc
    movb $STACK_DIRECTION_DESCENDING, %al # always descending on x86_64
    retl
.rust_psm_stack_direction_end:
SIZE(rust_psm_stack_direction,.rust_psm_stack_direction_end)
.cfi_endproc


GLOBL(rust_psm_stack_pointer)
.p2align 4
TYPE(rust_psm_stack_pointer)
FUNCTION(rust_psm_stack_pointer):
/* extern "fastcall" fn() -> *mut u8 (%rax) */
.cfi_startproc
    leal 4(%esp), %eax
    retl
.rust_psm_stack_pointer_end:
SIZE(rust_psm_stack_pointer,.rust_psm_stack_pointer_end)
.cfi_endproc


GLOBL(rust_psm_replace_stack)
.p2align 4
TYPE(rust_psm_replace_stack)
FUNCTION(rust_psm_replace_stack):
/* extern "fastcall" fn(%ecx: usize, %edx: extern "fastcall" fn(usize), 4(%esp): *mut u8) */
.cfi_startproc
/*
   All we gotta do is set the stack pointer to 4(%esp) & tail-call the callback in %edx

   Note, that the callee expects the stack to be offset by 4 bytes (normally, a return address
   would be store there) off the required stack alignment on entry. To offset the stack in such a
   way we use the `calll` instruction, however it would also be possible to to use plain `jmpl` but
   would require to adjust the stack manually, which cannot be easily done, because the stack
   pointer argument is already stored in memory.
 */
    movl 4(%esp), %esp
    calll *%edx
    ud2
.rust_psm_replace_stack_end:
SIZE(rust_psm_replace_stack,.rust_psm_replace_stack_end)
.cfi_endproc


GLOBL(rust_psm_on_stack)
.p2align 4
TYPE(rust_psm_on_stack)
FUNCTION(rust_psm_on_stack):
/* extern "fastcall" fn(%ecx: usize, %edx: usize, 4(%esp): extern "fastcall" fn(usize, usize), 8(%esp): *mut u8) */
.cfi_startproc
    pushl %ebp
    .cfi_def_cfa %esp, 8
    .cfi_offset %ebp, -8
    movl  %esp, %ebp
    .cfi_def_cfa_register %ebp
    movl  12(%ebp), %esp
    calll *8(%ebp)
    movl  %ebp, %esp
    popl  %ebp
    .cfi_def_cfa %esp, 4
    retl  $8
.rust_psm_on_stack_end:
SIZE(rust_psm_on_stack,.rust_psm_on_stack_end)
.cfi_endproc
