; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.

; this was copied from Mozilla (from xptcinvoke.asm or xptcinvoke_asm_x86_64.asm from the looks of it).
; various changes have been performed for it to fit with ADOxx.
; these procedures execute a provided function *f() in a DLL with the provided parameters (arbitrary number of them).
; the first four of the them are placed in the registers where the Windows ABI for 64 Bits expects them (rcx, rdx, r8 and r9).
; the rest is taken from the stack (where they are after the Ado_CopyToStack call).
; the copying of the remaining (arbitrary number of) parameters onto the stack is performed by a C++ function (Ado_CopyToStack)
; the two procedures here have the same code, but are necessary to use different return types (long and double).
;
; build with ml64.exe /c <filename.asm> /Fo <target.obj>

extrn Ado_CopyToStack:PROC

.CODE

PUBLIC Ado_GenericLongDLLCall
PUBLIC Ado_GenericDoubleDLLCall

Ado_GenericLongDLLCall PROC FRAME

   ; store register parameters

    mov     qword ptr [rsp+32], r9        ; params or pParams
    mov     dword ptr [rsp+24], r8d       ; paramCount or n
    mov     dword ptr [rsp+16], edx       ; dummy
    mov     qword ptr [rsp+8], rcx        ; [*f()] the pointer to the function

    push    rbp
    .PUSHREG rbp
    mov     rbp, rsp            ; store current RSP to RBP
    .SETFRAME rbp, 0
    .ENDPROLOG

    sub     rsp, 40

    ; maybe we don't have any parameters to copy

    test    r8d, r8d
    jz      noparams

    ;
    ; Build stack for stdcall
    ;

    ; 1st parameter is space for parameters

    mov     eax, r8d
    or      eax, 1
    shl     rax, 3              ; *= 8
    sub     rsp, rax
    mov     rcx, rsp

    ; 2nd parameter is parameter count

    mov     edx, r8d

    ; 3rd parameter is params

    mov     r8, r9

    sub     rsp, 40
    call    Ado_CopyToStack ; rcx = stack
                            ; edx = paramCount
                            ; r8  = params
    add     rsp, 40

    ; On Win64 ABI, the first 4 parameters are passed using registers,
    ; and others are on stack. 

    mov     rcx, qword ptr [rsp]
    movsd   xmm0, qword ptr [rsp] ; for double

    mov     rdx, qword ptr [rsp+8] ; 1st parameter
    movsd   xmm1, qword ptr [rsp+8] ; for double

    mov     r8, qword ptr [rsp+16] ; 2nd parameter
    movsd   xmm2, qword ptr [rsp+16] ; for double

    mov     r9, qword ptr [rsp+24] ; 3rd parameter
    movsd   xmm3, qword ptr [rsp+24] ; for double

noparams:

    call    qword ptr [rbp+8+8]

    mov     rsp, rbp
    pop     rbp

    ret

Ado_GenericLongDLLCall ENDP


Ado_GenericDoubleDLLCall PROC FRAME

   ; store register parameters

    mov     qword ptr [rsp+32], r9        ; params
    mov     dword ptr [rsp+24], r8d       ; paramCount
    mov     dword ptr [rsp+16], edx       ; dummy
    mov     qword ptr [rsp+8], rcx        ; [*f()]

    push    rbp
    .PUSHREG rbp
    mov     rbp, rsp            ; store current RSP to RBP
    .SETFRAME rbp, 0
    .ENDPROLOG

    sub     rsp, 40             ; differs from "xptcinvoke_asm_x86_64.asm"

    ; maybe we don't have any parameters to copy

    test    r8d, r8d
    jz      noparams

    ;
    ; Build stack for stdcall
    ;

    ; 1st parameter is space for parameters

    mov     eax, r8d
    or      eax, 1
    shl     rax, 3              ; *= 8
    sub     rsp, rax
    mov     rcx, rsp

    ; 2nd parameter is parameter count

    mov     edx, r8d

    ; 3rd parameter is params

    mov     r8, r9

    sub     rsp, 40
    call    Ado_CopyToStack ; rcx = stack
                            ; edx = paramCount
                            ; r8  = params
    add     rsp, 40

    ; On Win64 ABI, the first 4 parameters are passed using registers,
    ; and others are on stack. 

    mov     rcx, qword ptr [rsp]
    movsd   xmm0, qword ptr [rsp] ; for double

    mov     rdx, qword ptr [rsp+8] ; 1st parameter
    movsd   xmm1, qword ptr [rsp+8] ; for double

    mov     r8, qword ptr [rsp+16] ; 2nd parameter
    movsd   xmm2, qword ptr [rsp+16] ; for double

    mov     r9, qword ptr [rsp+24] ; 3rd parameter
    movsd   xmm3, qword ptr [rsp+24] ; for double

noparams:

    call    qword ptr [rbp+8+8]

    mov     rsp, rbp
    pop     rbp

    ret

Ado_GenericDoubleDLLCall ENDP

END
