summaryrefslogtreecommitdiff
path: root/src/vm/amd64/RemotingThunksAMD64.asm
blob: 6d555e8bebe291734182e34030b43e4213715cd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
; Licensed to the .NET Foundation under one or more agreements.
; The .NET Foundation licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.

include AsmMacros.inc
include AsmConstants.inc
ifdef FEATURE_REMOTING

extern CallDescrWorkerUnwindFrameChainHandler:proc

extern TransparentProxyStubWorker:proc	

; Stack frame layout:
;
; (stack parameters)
; ...
; r9
; r8
; rdx
; rcx <- TPSCC_PARAMS_OFFSET
; return address <- TPSCC_STACK_FRAME_SIZE
; r10 <- TPSCC_R10_OFFSET
; xmm3
; xmm2
; xmm1
; xmm0 <- TPSCC_XMM_SAVE_OFFSET
; callee's r9
; callee's r8
; callee's rdx
; callee's rcx

TPSCC_XMM_SAVE_OFFSET = 20h
TPSCC_R10_OFFSET = 60h
TPSCC_STACK_FRAME_SIZE = 68h
TPSCC_PARAMS_OFFSET = 70h

TRANSPARENT_PROXY_STUB_PROLOGUE macro
        alloc_stack     TPSCC_STACK_FRAME_SIZE

        save_reg_postrsp r10, TPSCC_R10_OFFSET

        SAVE_ARGUMENT_REGISTERS TPSCC_PARAMS_OFFSET
        SAVE_FLOAT_ARGUMENT_REGISTERS TPSCC_XMM_SAVE_OFFSET

        END_PROLOGUE

        endm

NESTED_ENTRY TransparentProxyStub, _TEXT, CallDescrWorkerUnwindFrameChainHandler

        TRANSPARENT_PROXY_STUB_PROLOGUE
        
        ;; rcx: this
        ;; [rsp]: slot number

        mov             rax, [rcx + TransparentProxyObject___stub]
        mov             rcx, [rcx + TransparentProxyObject___stubData]
        call            rax

        RESTORE_ARGUMENT_REGISTERS TPSCC_PARAMS_OFFSET
        RESTORE_FLOAT_ARGUMENT_REGISTERS TPSCC_XMM_SAVE_OFFSET

        mov             r10, [rsp + TPSCC_R10_OFFSET] 

        test            rax, rax
        jnz             CrossContext

        mov             r11, [rcx + TransparentProxyObject___pMT]

        ; Convert the slot number (r10) into the code address (in rax)
        ; See MethodTable.h for details on vtable layout
        shr             r10, MethodTable_VtableSlotsPerChunkLog2
        mov             rax, [r11 + r10*8 + METHODTABLE_OFFSET_VTABLE]

        mov             r10, [rsp + TPSCC_R10_OFFSET] ; Reload the slot
        and             r10, MethodTable_VtableSlotsPerChunk-1
        mov             rax, [rax + r10*8]
        
        add             rsp, TPSCC_STACK_FRAME_SIZE
        TAILJMP_RAX

CrossContext:        
        add             rsp, TPSCC_STACK_FRAME_SIZE
        jmp             TransparentProxyStub_CrossContext

NESTED_END TransparentProxyStub, _TEXT


NESTED_ENTRY TransparentProxyStub_CrossContext, _TEXT

        PROLOG_WITH_TRANSITION_BLOCK 8

        ;
        ; Call TransparentProxyStubWorker.
        ;
        lea             rcx, [rsp + __PWTB_TransitionBlock] ; pTransitionBlock
        mov             rdx, r10                            ; MethodDesc *
        call            TransparentProxyStubWorker

        ; handle FP return values

        lea             rcx, [rsp + __PWTB_FloatArgumentRegisters - 8]
        cmp             rax, 4
        jne             @F
        movss           xmm0, real4 ptr [rcx]
@@:        
        cmp             rax, 8
        jne             @F
        movsd           xmm0, real8 ptr [rcx]
@@:
        ; load return value
        mov             rax, [rcx]

        EPILOG_WITH_TRANSITION_BLOCK_RETURN

NESTED_END TransparentProxyStub_CrossContext, _TEXT

LEAF_ENTRY TransparentProxyStubPatch, _TEXT
        ; make sure that the basic block is unique
        test            eax,12
PATCH_LABEL TransparentProxyStubPatchLabel
        ret
LEAF_END TransparentProxyStubPatch, _TEXT

;+----------------------------------------------------------------------------
;
;  Method:     CRemotingServices::CallFieldGetter   private
;
;  Synopsis:   Calls the field getter function (Object::__FieldGetter) in
;              managed code by setting up the stack and calling the target
;
;+----------------------------------------------------------------------------
; extern "C"
;void __stdcall CRemotingServices__CallFieldGetter(  MethodDesc *pMD,
;                                                    LPVOID pThis,
;                                                    LPVOID pFirst,
;                                                    LPVOID pSecond,
;                                                    LPVOID pThird
;                                                    )
LEAF_ENTRY CRemotingServices__CallFieldGetter, _TEXT

; +28   pThird
; +20   scratch area
; +18   scratch area
; +10   scratch area
; + 8   scratch area
; rsp   return address

        mov             METHODDESC_REGISTER, rcx
        mov             rcx, rdx
        mov             rdx, r8
        mov             r8, r9
        mov             r9, [rsp + 28h]
        jmp             TransparentProxyStub

LEAF_END CRemotingServices__CallFieldGetter, _TEXT


;+----------------------------------------------------------------------------
;
;  Method:     CRemotingServices::CallFieldSetter   private
;
;  Synopsis:   Calls the field setter function (Object::__FieldSetter) in
;              managed code by setting up the stack and calling the target
;
;+----------------------------------------------------------------------------
; extern "C"
;void __stdcall CRemotingServices__CallFieldSetter(  MethodDesc *pMD,
;                                                    LPVOID pThis,
;                                                    LPVOID pFirst,
;                                                    LPVOID pSecond,
;                                                    LPVOID pThird
;                                                    )
LEAF_ENTRY CRemotingServices__CallFieldSetter, _TEXT

; +28   pThird
; +20   scratch area
; +18   scratch area
; +10   scratch area
; + 8   scratch area
; rsp   return address

        mov             METHODDESC_REGISTER, rcx
        mov             rcx, rdx
        mov             rdx, r8
        mov             r8, r9
        mov             r9, [rsp + 28h]
        jmp             TransparentProxyStub

LEAF_END CRemotingServices__CallFieldSetter, _TEXT


;; extern "C" ARG_SLOT __stdcall CTPMethodTable__CallTargetHelper2(const void *pTarget,
;;                                                                 LPVOID pvFirst,
;;                                                                 LPVOID pvSecond);
NESTED_ENTRY CTPMethodTable__CallTargetHelper2, _TEXT, CallDescrWorkerUnwindFrameChainHandler
        alloc_stack     28h     ;; alloc callee scratch and align the stack
        END_PROLOGUE

        mov     rax, rcx    ; rax <- call target
        mov     rcx, rdx    ; rcx <- first arg
        mov     rdx, r8     ; rdx <- second arg

        call     rax
	;; It is important to have an instruction between the previous call and the epilog.
	;; If the return address is in epilog, OS won't call personality routine because
	;; it thinks personality routine does not help in this case.
	nop

        ; epilog
        add     rsp, 28h
	ret
NESTED_END CTPMethodTable__CallTargetHelper2, _TEXT

;; extern "C" ARG_SLOT __stdcall CTPMethodTable__CallTargetHelper2(const void *pTarget,
;;                                                                 LPVOID pvFirst,
;;                                                                 LPVOID pvSecond,
;;                                                                 LPVOID pvThird);
NESTED_ENTRY CTPMethodTable__CallTargetHelper3, _TEXT, CallDescrWorkerUnwindFrameChainHandler
        alloc_stack     28h     ;; alloc callee scratch and align the stack
        END_PROLOGUE

        mov     rax, rcx    ; rax <- call target
        mov     rcx, rdx    ; rcx <- first arg
        mov     rdx, r8     ; rdx <- second arg
        mov     r8,  r9     ; r8  <- third arg

        call     rax

	;; It is important to have an instruction between the previous call and the epilog.
	;; If the return address is in epilog, OS won't call personality routine because
	;; it thinks personality routine does not help in this case.
	nop

        ; epilog
        add     rsp, 28h
	ret
NESTED_END CTPMethodTable__CallTargetHelper3, _TEXT

NESTED_ENTRY CRemotingServices__DispatchInterfaceCall, _TEXT, CallDescrWorkerUnwindFrameChainHandler

        TRANSPARENT_PROXY_STUB_PROLOGUE

        ;
        ; 'this' is a TransparentProxy.  Call to stub to see if need to cross contexts.
        ;

        mov             rax, [rcx + TransparentProxyObject___stub]
        mov             rcx, [rcx + TransparentProxyObject___stubData]
        call            rax

        test            rax, rax
        jnz             CrossContext

extern VSD_GetTargetForTPWorkerQuick:proc
        mov             rcx, [rsp + TPSCC_PARAMS_OFFSET]                ; rcx <- this
        mov             rdx, [rsp + TPSCC_R10_OFFSET]                   ; rdx <- Get the MethodDesc* or slot number        
        call            VSD_GetTargetForTPWorkerQuick

        RESTORE_ARGUMENT_REGISTERS TPSCC_PARAMS_OFFSET
        RESTORE_FLOAT_ARGUMENT_REGISTERS TPSCC_XMM_SAVE_OFFSET

        mov             r10, [rsp + TPSCC_R10_OFFSET] 

        test            rax, rax                                         ; Did we find a target?
        jz              SlowDispatch

        add             rsp, TPSCC_STACK_FRAME_SIZE
        TAILJMP_RAX

SlowDispatch:
        add             rsp, TPSCC_STACK_FRAME_SIZE
        jmp             InContextTPDispatchAsmStub

CrossContext:        
        RESTORE_ARGUMENT_REGISTERS TPSCC_PARAMS_OFFSET
        RESTORE_FLOAT_ARGUMENT_REGISTERS TPSCC_XMM_SAVE_OFFSET

        mov             r10, [rsp + TPSCC_R10_OFFSET] 

        add             rsp, TPSCC_STACK_FRAME_SIZE
        jmp             TransparentProxyStub_CrossContext

NESTED_END CRemotingServices__DispatchInterfaceCall, _TEXT

NESTED_ENTRY InContextTPDispatchAsmStub, _TEXT

        PROLOG_WITH_TRANSITION_BLOCK

extern VSD_GetTargetForTPWorker:proc
        lea             rcx, [rsp + __PWTB_TransitionBlock] ; pTransitionBlock
        mov             rdx, r10                            ; token
        call            VSD_GetTargetForTPWorker

        EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
        TAILJMP_RAX

NESTED_END InContextTPDispatchAsmStub, _TEXT

endif ; FEATURE_REMOTING

        end