xref: /trunk/main/bridges/source/cpp_uno/msvc_win64_x86-64/call.asm (revision 3f2293a34d640799d3a646809239d04f5e6f46e0)
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;               | old rbp                    |
55; rbp---------> +----------------------------+
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
76    push    rbp
77    mov rbp, rsp
78    sub rsp, 48
79    .ALLOCSTACK(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    leave
102    ret
103
104privateSnippetExecutor ENDP
105
106
107;
108;               | ...                                         |
109; rbp+64 -----> +---------------------------------------------+
110;               | sal_uInt32 nStack                           |
111; rbp+56 -----> +---------------------------------------------+
112;               | sal_uInt64 *pStack                          |
113; rbp+48 -----> +---------------------------------------------+ -------
114;               | typelib_TypeClass eReturnTypeClass, r9 home | ^ shadow
115; rbp+40 -----> +---------------------------------------------+ | space,
116;               | void *pRegisterReturn,              r8 home | | guaranteed to be present but uninitialized,
117; rbp+32 -----> +---------------------------------------------+ | we have to copy
118;               | sal_Int32 nVtableIndex,            rdx home | | the first 4 parameters there from the registers,
119; rbp+24 -----> +---------------------------------------------+ | to form the continuous array of arguments.
120;               | void* pAdjustedThisPtr,            rcx home | v
121; rbp+16 -----> +---------------------------------------------+ -------
122;               | return address                              |
123; rbp+08 -----> +---------------------------------------------+
124;               | old rbp                                     |
125; rbp --------> +---------------------------------------------+ <---- 16 byte boundary
126;               | (possible 16 byte alignment placeholder)    |
127; rbp-08 -----> +---------------------------------------------+
128;               | (stack for virtual method)                  |
129;               | ...                                         |
130;               | (shadow space for virtual method)           |
131; rsp --------> +---------------------------------------------+ <---- 16 byte boundary
132
133callVirtualMethod PROC FRAME
134
135    push rbp
136    mov rbp, rsp
137    .ENDPROLOG
138
139    ; Save our register arguments to the shadow space:
140    mov 16[rbp], rcx
141    mov 24[rbp], rdx
142    mov 32[rbp], r8
143    mov 40[rbp], r9
144
145    ; We must maintain the stack aligned to a 16 byte boundary:
146    mov eax, 56[rbp]
147    cmp rax, 0
148    je stackIsEmpty
149    mov r11, rax
150    test rax,1
151    jz stackSizeEven
152    sub rsp, 8
153stackSizeEven:
154    mov r10, 48[rbp]
155    shl rax, 3        ; nStack is in units of sal_uInt64, and sizeof(sal_uInt64) == 8
156    add rax, r10
157
158copyStack:
159    sub rax, 8
160    push [rax]
161    dec r11
162    jne copyStack
163
164    ; First 4 args are passed in registers. Floating point args needs to be
165    ; in floating point registers, but those are free for us to clobber
166    ; anyway, and the callee knows where to look, so put each arg in both
167    ; its general purpose and its floating point register:
168    mov rcx, [rsp]
169    movsd xmm0, qword ptr [rsp]
170    mov rdx, 8[rsp]
171    movsd xmm1, qword ptr 8[rsp]
172    mov r8, 16[rsp]
173    movsd xmm2, qword ptr 16[rsp]
174    mov r9, 24[rsp]
175    movsd xmm3, qword ptr 24[rsp]
176    jmp callMethod
177
178stackIsEmpty:
179    sub rsp, 32       ; we still need shadow space
180
181callMethod:
182    ; Find the method pointer
183    mov rax, 16[rbp]
184    mov r10, [rax]    ; pointer to vtable
185    mov r11d, 24[rbp]
186    shl r11, 3        ; sizeof(void*) == 8
187    add r10, r11
188    call qword ptr [r10]
189
190    mov r10d, 40[rbp]
191    cmp r10, typelib_TypeClass_VOID
192    je cleanup
193    cmp r10, typelib_TypeClass_LONG
194    je Lint32
195    cmp r10, typelib_TypeClass_UNSIGNED_LONG
196    je Lint32
197    cmp r10, typelib_TypeClass_ENUM
198    je Lint32
199    cmp r10, typelib_TypeClass_BOOLEAN
200    je Lint8
201    cmp r10, typelib_TypeClass_BYTE
202    je Lint8
203    cmp r10, typelib_TypeClass_CHAR
204    je Lint16
205    cmp r10, typelib_TypeClass_SHORT
206    je Lint16
207    cmp r10, typelib_TypeClass_UNSIGNED_SHORT
208    je Lint16
209    cmp r10, typelib_TypeClass_FLOAT
210    je Lfloat
211    cmp r10, typelib_TypeClass_DOUBLE
212    je Lfloat
213    cmp r10, typelib_TypeClass_HYPER
214    je Lint64
215    cmp r10, typelib_TypeClass_UNSIGNED_HYPER
216    je Lint64
217
218    ; https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017
219    ; "The same pointer must be returned by the callee in RAX."
220    jmp Lint64
221
222Lint64:
223    mov 32[rbp], rax
224    jmp cleanup
225
226Lint32:
227    mov 32[rbp], eax
228    jmp cleanup
229
230Lint16:
231    mov 32[rbp], ax
232    jmp cleanup
233
234Lint8:
235    mov 32[rbp], al
236    jmp cleanup
237
238Lfloat:
239    movsd qword ptr 32[rbp], xmm0
240    jmp cleanup
241
242cleanup:
243    leave
244    ret
245
246callVirtualMethod ENDP
247
248
249END
250