xref: /trunk/main/bridges/source/cpp_uno/msvc_win64_x86-64/call.asm (revision 079530e0cc63d88d2438d6ca375766814976df0e)
1;
2; Licensed to the Apache Software Foundation (ASF) under one
3; or more contributor license agreements.  See the NOTICE file
4; distributed with this work for additional information
5; regarding copyright ownership.  The ASF licenses this file
6; to you under the Apache License, Version 2.0 (the
7; "License"); you may not use this file except in compliance
8; with the License.  You may obtain a copy of the License at
9;
10;   http://www.apache.org/licenses/LICENSE-2.0
11;
12; Unless required by applicable law or agreed to in writing,
13; software distributed under the License is distributed on an
14; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15; KIND, either express or implied.  See the License for the
16; specific language governing permissions and limitations
17; under the License.
18;
19
20
21typelib_TypeClass_VOID equ 0
22typelib_TypeClass_CHAR equ 1
23typelib_TypeClass_BOOLEAN equ 2
24typelib_TypeClass_BYTE equ 3
25typelib_TypeClass_SHORT equ 4
26typelib_TypeClass_UNSIGNED_SHORT equ 5
27typelib_TypeClass_LONG equ 6
28typelib_TypeClass_UNSIGNED_LONG equ 7
29typelib_TypeClass_HYPER equ 8
30typelib_TypeClass_UNSIGNED_HYPER equ 9
31typelib_TypeClass_FLOAT equ 10
32typelib_TypeClass_DOUBLE equ 11
33typelib_TypeClass_ENUM equ 15
34
35EXTERN cpp_vtable_call: PROC
36
37.CODE
38
39;
40;               | ...                        |
41;               +----------------------------+
42;               | argument 4                 |
43; rbp+48 rsp+40 +----------------------------+ -------
44;               | argument 3, r9/xmm3 home   | ^ shadow
45; rbp+40 rsp+32 +----------------------------+ | space,
46;               | argument 2, r8/xmm2 home   | | guaranteed to be present but uninitialized,
47; rbp+32 rsp+24 +----------------------------+ | we have to copy
48;               | argument 1, rdx/xmm1 home  | | the first 4 parameters there from the registers,
49; rbp+24 rsp+16 +----------------------------+ | to form the continuous array of arguments.
50;               | argument 0, rcx/xmm0 home  | v
51; rbp+16 rsp+08 +----------------------------+ -------
52;               | return address             |
53; rbp+08 rsp--> +----------------------------+
54;               | caller's rbp               |
55; rbp---------> +----------------------------+ <------ 16 byte boundary
56;               | pRegisterReturn memory     |
57; rbp-08 -----> +----------------------------+
58;               |                            |
59; rbp-16 -----> +----------------------------+ -------
60;               |                            | ^
61; rbp-24 -----> +----------------------------+ | shadow space
62;               |                            | | for cpp_vtable_call
63; rbp-32 -----> +----------------------------+ |
64;               |                            | |
65; rbp-40 -----> +----------------------------+ |
66;               |                            | v
67; rbp-48 -----> +----------------------------+ -------
68;
69; rax = functionIndex
70; r10 = vtableOffset
71; r11 = &privateSnippetExecutor
72;
73
74privateSnippetExecutor PROC FRAME
75    push    rbp
76    .PUSHREG rbp
77    mov rbp, rsp
78    .SETFRAME rbp, 0
79    sub rsp, 48
80    .ENDPROLOG
81
82    ; 4th param: sal_uInt64 *pRegisterReturn
83    lea r9, -8[rbp]
84
85    ; 3rd param: sal_Int32 nVtableOffset
86    mov r8, r10
87
88    ; 2nd param: sal_Int32 nFunctionIndex
89    mov rdx, rax
90
91    ; 1st param: void ** pCallStack
92    lea rcx, 8[rbp]
93
94    call cpp_vtable_call
95
96    ; Integers would return in RAX and floats in XMM0, but both are free for us to clobber,
97    ; and the caller knows where to look:
98    mov rax, -8[rbp]
99    movsd xmm0, qword ptr -8[rbp]
100
101    add rsp, 48
102        pop rbp
103    ret
104
105privateSnippetExecutor ENDP
106
107
108;
109;               | ...                                         |
110; rbp+64 -----> +---------------------------------------------+
111;               | sal_uInt32 nStack                           |
112; rbp+56 -----> +---------------------------------------------+
113;               | sal_uInt64 *pStack                          |
114; rbp+48 -----> +---------------------------------------------+ -------
115;               | typelib_TypeClass eReturnTypeClass, r9 home | ^ shadow
116; rbp+40 -----> +---------------------------------------------+ | space,
117;               | void *pRegisterReturn,              r8 home | | guaranteed to be present but uninitialized,
118; rbp+32 -----> +---------------------------------------------+ | we have to copy
119;               | sal_Int32 nVtableIndex,            rdx home | | the first 4 parameters there from the registers,
120; rbp+24 -----> +---------------------------------------------+ | to form the continuous array of arguments.
121;               | void* pAdjustedThisPtr,            rcx home | v
122; rbp+16 -----> +---------------------------------------------+ -------
123;               | return address                              |
124; rbp+08 -----> +---------------------------------------------+
125;               | caller's rbp                                |
126; rbp --------> +---------------------------------------------+ <---- 16 byte boundary
127;               | (possible 16 byte alignment placeholder)    |
128; rbp-08 -----> +---------------------------------------------+
129;               | (stack for virtual method)                  |
130;               | ...                                         |
131;               | (shadow space for virtual method)           |
132; rsp --------> +---------------------------------------------+ <---- 16 byte boundary
133
134callVirtualMethod PROC FRAME
135
136    push rbp
137    .PUSHREG rbp
138    mov rbp, rsp
139    .SETFRAME rbp, 0
140
141    ; Save our register arguments to the shadow space:
142    mov 16[rbp], rcx
143    mov 24[rbp], rdx
144    mov 32[rbp], r8
145    mov 40[rbp], r9
146
147    ; nStack rounded to multiple of 2, so the stack is aligned to a 16 byte boundary:
148    mov eax, 56[rbp]
149    inc eax
150    shr eax, 1
151    shl eax, 1
152
153    ; if nStack < 4, add (4 - nStack) empty slots to the stack:
154    mov r10d, 4
155    sub r10d, eax
156    js copyStack
157    shl r10, 3
158    sub rsp, r10
159
160copyStack:
161    mov r10, rax
162    shl rax, 3
163    add rax, 48[rbp]
164copyStackLoop:
165    sub rax, 8
166    push [rax]
167    dec r10
168    jne copyStackLoop
169
170populateArgumentRegisters:
171    ; First 4 args are passed in registers. Floating point args needs to be
172    ; in floating point registers, but those are volatile anyway,
173    ; and the callee knows where to look, so put each arg in both
174    ; its general purpose and its floating point register:
175    mov rcx, [rsp]
176    movsd xmm0, qword ptr [rsp]
177    mov rdx, 8[rsp]
178    movsd xmm1, qword ptr 8[rsp]
179    mov r8, 16[rsp]
180    movsd xmm2, qword ptr 16[rsp]
181    mov r9, 24[rsp]
182    movsd xmm3, qword ptr 24[rsp]
183
184    .ENDPROLOG
185
186
187callMethod:
188    ; Find the method pointer
189    mov rax, 16[rbp]
190    mov r10, [rax]    ; pointer to vtable
191    mov r11d, 24[rbp]
192    shl r11, 3        ; sizeof(void*) == 8
193    add r10, r11
194    call qword ptr [r10]
195
196    mov r10d, 40[rbp]
197    mov r11, 32[rbp]
198    cmp r10, typelib_TypeClass_VOID
199    je cleanup
200    cmp r10, typelib_TypeClass_LONG
201    je Lint32
202    cmp r10, typelib_TypeClass_UNSIGNED_LONG
203    je Lint32
204    cmp r10, typelib_TypeClass_ENUM
205    je Lint32
206    cmp r10, typelib_TypeClass_BOOLEAN
207    je Lint8
208    cmp r10, typelib_TypeClass_BYTE
209    je Lint8
210    cmp r10, typelib_TypeClass_CHAR
211    je Lint16
212    cmp r10, typelib_TypeClass_SHORT
213    je Lint16
214    cmp r10, typelib_TypeClass_UNSIGNED_SHORT
215    je Lint16
216    cmp r10, typelib_TypeClass_FLOAT
217    je Lfloat
218    cmp r10, typelib_TypeClass_DOUBLE
219    je Lfloat
220    cmp r10, typelib_TypeClass_HYPER
221    je Lint64
222    cmp r10, typelib_TypeClass_UNSIGNED_HYPER
223    je Lint64
224
225    ; https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017
226    ; "The same pointer must be returned by the callee in RAX."
227    jmp cleanup
228
229Lint64:
230    mov qword ptr [r11], rax
231    jmp cleanup
232
233Lint32:
234    mov dword ptr [r11], eax
235    jmp cleanup
236
237Lint16:
238    mov word ptr [r11], ax
239    jmp cleanup
240
241Lint8:
242    mov byte ptr [r11], al
243    jmp cleanup
244
245Lfloat:
246    movsd qword ptr [r11], xmm0
247    jmp cleanup
248
249cleanup:
250    lea rsp, 0[rbp]
251    pop rbp
252    ret
253
254callVirtualMethod ENDP
255
256
257END
258