summaryrefslogtreecommitdiff
path: root/src/vm/arm64/pinvokestubs.S
blob: 8b8a611f667009e1cb8582bf12bddc67fb7a3360 (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
// 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 "asmconstants.h"
#include "unixasmmacros.inc"

// ------------------------------------------------------------------
// Macro to generate PInvoke Stubs.
// $__PInvokeStubFuncName : function which calls the actual stub obtained from VASigCookie
// $__PInvokeGenStubFuncName : function which generates the IL stubs for PInvoke
// 
// Params :-
// $FuncPrefix : prefix of the function name for the stub
//                     Eg. VarargPinvoke, GenericPInvokeCalli
// $VASigCookieReg : register which contains the VASigCookie
// $SaveFPArgs : "Yes" or "No" . For varidic functions FP Args are not present in FP regs 
//                        So need not save FP Args registers for vararg Pinvoke
.macro PINVOKE_STUB __PInvokeStubFuncName,__PInvokeGenStubFuncName,__PInvokeStubWorkerName,VASigCookieReg,HiddenArg,SaveFPArgs,ShiftLeftAndOrSecret=0


        NESTED_ENTRY \__PInvokeStubFuncName, _TEXT, NoHandler

        // get the stub
        ldr                 x9, [\VASigCookieReg, #VASigCookie__pNDirectILStub]

        // if null goto stub generation
        cbz                 x9, LOCAL_LABEL(\__PInvokeStubFuncName\()_0)

        .if (\ShiftLeftAndOrSecret == 1)
            //
            // We need to distinguish between a MethodDesc* and an unmanaged target.
            // The way we do this is to shift the managed target to the left by one bit and then set the
            // least significant bit to 1.  This works because MethodDesc* are always 8-byte aligned.
            //
            lsl             \HiddenArg, \HiddenArg, #1
            orr             \HiddenArg, \HiddenArg, #1
        .endif

        EPILOG_BRANCH_REG   x9 

LOCAL_LABEL(\__PInvokeStubFuncName\()_0):

        EPILOG_BRANCH       \__PInvokeGenStubFuncName

        NESTED_END \__PInvokeStubFuncName, _TEXT

        
        NESTED_ENTRY \__PInvokeGenStubFuncName, _TEXT, NoHandler

        PROLOG_WITH_TRANSITION_BLOCK 0, \SaveFPArgs

        // x2 = Umanaged Target\MethodDesc
        mov                 x2, \HiddenArg 

        // x1 = VaSigCookie
        mov                 x1, \VASigCookieReg

        // x0 = pTransitionBlock
        add                 x0, sp, #__PWTB_TransitionBlock      

        // save hidden arg
        mov                 x19, \HiddenArg 

        // save VASigCookieReg
        mov                 x20, \VASigCookieReg

        bl                  \__PInvokeStubWorkerName

        // restore VASigCookieReg
        mov                 \VASigCookieReg, x20

        // restore hidden arg (method desc or unmanaged target)
        mov                 \HiddenArg , x19


        EPILOG_WITH_TRANSITION_BLOCK_TAILCALL

        EPILOG_BRANCH       \__PInvokeStubFuncName
     
        NESTED_END \__PInvokeGenStubFuncName, _TEXT
.endm

// ------------------------------------------------------------------
// IN:
// InlinedCallFrame (x0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right 
//                         before actual InlinedCallFrame data)
//
//
    NESTED_ENTRY JIT_PInvokeBegin, _TEXT, NoHandler
    
        PROLOG_SAVE_REG_PAIR_INDEXED   fp, lr, -32
        PROLOG_SAVE_REG    x19, 16           //the stack slot at sp+24 is empty for 16 byte alignment

        PREPARE_EXTERNAL_VAR s_gsCookie, x9
        ldr     x9, [x9]
        str     x9, [x0]
        add     x19, x0, SIZEOF__GSCookie

        // x19 = pFrame
        
        // set first slot to the value of InlinedCallFrame::`vftable' (checked by runtime code)
        PREPARE_EXTERNAL_VAR _ZTV16InlinedCallFrame, x9
        add     x9, x9, 16
        str     x9, [x19]

        str     xzr, [x19, #InlinedCallFrame__m_Datum]
    
        add     x9, sp, 32
        str     x9, [x19, #InlinedCallFrame__m_pCallSiteSP]
        str     lr, [x19, #InlinedCallFrame__m_pCallerReturnAddress]

        ldr     x9, [sp,#0]
        str     x9, [x19, #InlinedCallFrame__m_pCalleeSavedFP]

        // x0 = GetThread()
        bl      C_FUNC(GetThread)
        str     x0, [x19, #InlinedCallFrame__m_pThread]

        // pFrame->m_Next = pThread->m_pFrame;
        ldr     x9, [x0, #Thread_m_pFrame]
        str     x9, [x19, #Frame__m_Next]

        // pThread->m_pFrame = pFrame;
        str     x19, [x0, #Thread_m_pFrame]

        // pThread->m_fPreemptiveGCDisabled = 0
        str     wzr, [x0, #Thread_m_fPreemptiveGCDisabled]

        EPILOG_RESTORE_REG      x19, 16    //the stack slot at sp+24 is empty for 16 byte alignment
        EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
        EPILOG_RETURN

    NESTED_END JIT_PInvokeBegin, _TEXT

// ------------------------------------------------------------------
// IN:
// InlinedCallFrame (x0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right 
//                         before actual InlinedCallFrame data)
//
//
    LEAF_ENTRY JIT_PInvokeEnd, _TEXT

        add     x0, x0, SIZEOF__GSCookie
        ldr     x1, [x0, #InlinedCallFrame__m_pThread]

        // x0 = pFrame
        // x1 = pThread
            
        // pThread->m_fPreemptiveGCDisabled = 1
        mov     x9, 1
        str     w9, [x1, #Thread_m_fPreemptiveGCDisabled]

        // Check return trap
        PREPARE_EXTERNAL_VAR g_TrapReturningThreads, x9
        ldr     x9, [x9]
        cbnz    x9, LOCAL_LABEL(RarePath)

        // pThread->m_pFrame = pFrame->m_Next
        ldr     x9, [x0, #Frame__m_Next]
        str     x9, [x1, #Thread_m_pFrame]

        ret
            
LOCAL_LABEL(RarePath):
        b       C_FUNC(JIT_PInvokeEndRarePath)

    LEAF_END JIT_PInvokeEnd, _TEXT

// ------------------------------------------------------------------
// VarargPInvokeStub & VarargPInvokeGenILStub
//
// in:
// x0 = VASigCookie*
// x12 = MethodDesc *       
//
PINVOKE_STUB VarargPInvokeStub, VarargPInvokeGenILStub, VarargPInvokeStubWorker, x0, x12, 0


// ------------------------------------------------------------------
// GenericPInvokeCalliHelper & GenericPInvokeCalliGenILStub
// Helper for generic pinvoke calli instruction 
//
// in:
// x15 = VASigCookie*
// x12 = Unmanaged target
//
PINVOKE_STUB GenericPInvokeCalliHelper, GenericPInvokeCalliGenILStub, GenericPInvokeCalliStubWorker, x15, x12, 1, 1