// 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" .syntax unified .thumb // ------------------------------------------------------------------ // Macro to generate PInvoke Stubs. // Params :- // \__PInvokeStubFuncName : function which calls the actual stub obtained from VASigCookie // \__PInvokeGenStubFuncName : function which generates the IL stubs for PInvoke // \__PInvokeStubWorkerName : prefix of the function name for the stub // \VASigCookieReg : register which contains the VASigCookie // \SaveFPArgs : "1" or "0" . 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,SaveFPArgs NESTED_ENTRY \__PInvokeStubFuncName, _TEXT, NoHandler // save reg value before using the reg PROLOG_PUSH {\VASigCookieReg} // get the stub ldr \VASigCookieReg, [\VASigCookieReg,#VASigCookie__pNDirectILStub] // if null goto stub generation cbz \VASigCookieReg, \__PInvokeStubFuncName\()Label EPILOG_STACK_FREE 4 EPILOG_BRANCH_REG \VASigCookieReg \__PInvokeStubFuncName\()Label: EPILOG_POP {\VASigCookieReg} EPILOG_BRANCH \__PInvokeGenStubFuncName NESTED_END \__PInvokeStubFuncName, _TEXT NESTED_ENTRY \__PInvokeGenStubFuncName, _TEXT, NoHandler PROLOG_WITH_TRANSITION_BLOCK 0, \SaveFPArgs // r2 = UnmanagedTarget\ MethodDesc mov r2, r12 // r1 = VaSigCookie .ifnc \VASigCookieReg, r1 mov r1, \VASigCookieReg .endif // r0 = pTransitionBlock add r0, sp, #__PWTB_TransitionBlock // save hidden arg mov r4, r12 bl \__PInvokeStubWorkerName // restore hidden arg (method desc or unmanaged target) mov r12, r4 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL EPILOG_BRANCH \__PInvokeStubFuncName NESTED_END \__PInvokeGenStubFuncName, _TEXT .endmacro // ------------------------------------------------------------------ // IN: // InlinedCallFrame (r0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right // before actual InlinedCallFrame data) // // NESTED_ENTRY JIT_PInvokeBegin,_TEXT,NoHandler PROLOG_PUSH "{r4, lr}" ldr r1, =s_gsCookie ldr r1, [r1] str r1, [r0] add r4, r0, SIZEOF__GSCookie // r4 = pFrame // set first slot to the value of InlinedCallFrame::`vftable' (checked by runtime code) ldr r1, .L12 str r1, [r4] mov r1, 0 str r1, [r4, #InlinedCallFrame__m_Datum] add r1, sp, 8 str r1, [r4, #InlinedCallFrame__m_pCallSiteSP] str r11, [r4, #InlinedCallFrame__m_pCalleeSavedFP] str lr, [r4, #InlinedCallFrame__m_pCallerReturnAddress] str r9, [r4, #InlinedCallFrame__m_pSPAfterProlog] ;; r0 = GetThread() bl C_FUNC(GetThread) str r0, [r4, #InlinedCallFrame__m_pThread] // pFrame->m_Next = pThread->m_pFrame; ldr r1, [r0, #Thread_m_pFrame] str r1, [r4, #Frame__m_Next] // pThread->m_pFrame = pFrame; str r4, [r0, #Thread_m_pFrame] // pThread->m_fPreemptiveGCDisabled = 0 mov r1, 0 str r1, [r0, #Thread_m_fPreemptiveGCDisabled] EPILOG_POP "{r4, pc}" NESTED_END JIT_PInvokeBegin, _TEXT .L12: .word _ZTV16InlinedCallFrame+8 // ------------------------------------------------------------------ // IN: // InlinedCallFrame (r0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right // before actual InlinedCallFrame data) // // LEAF_ENTRY JIT_PInvokeEnd, _TEXT add r0, r0, SIZEOF__GSCookie ldr r1, [r0, #InlinedCallFrame__m_pThread] // r0 = pFrame // r1 = pThread // pThread->m_fPreemptiveGCDisabled = 1 mov r2, 1 str r2, [r1, #Thread_m_fPreemptiveGCDisabled] // Check return trap ldr r2, =g_TrapReturningThreads ldr r2, [r2] cbnz r2, LOCAL_LABEL(RarePath) // pThread->m_pFrame = pFrame->m_Next ldr r2, [r0, #Frame__m_Next] str r2, [r1, #Thread_m_pFrame] bx lr LOCAL_LABEL(RarePath): b C_FUNC(JIT_PInvokeEndRarePath) LEAF_END JIT_PInvokeEnd, _TEXT // ------------------------------------------------------------------ // VarargPInvokeStub & VarargPInvokeGenILStub // There is a separate stub when the method has a hidden return buffer arg. // // in: // r0 = VASigCookie* // r12 = MethodDesc * // PINVOKE_STUB VarargPInvokeStub, VarargPInvokeGenILStub, VarargPInvokeStubWorker, r0, 0 // ------------------------------------------------------------------ // GenericPInvokeCalliHelper & GenericPInvokeCalliGenILStub // Helper for generic pinvoke calli instruction // // in: // r4 = VASigCookie* // r12 = Unmanaged target // PINVOKE_STUB GenericPInvokeCalliHelper, GenericPInvokeCalliGenILStub, GenericPInvokeCalliStubWorker r4, 1 // ------------------------------------------------------------------ // VarargPInvokeStub_RetBuffArg & VarargPInvokeGenILStub_RetBuffArg // Vararg PInvoke Stub when the method has a hidden return buffer arg // // in: // r1 = VASigCookie* // r12 = MethodDesc* // PINVOKE_STUB VarargPInvokeStub_RetBuffArg, VarargPInvokeGenILStub_RetBuffArg, VarargPInvokeStubWorker, r1, 0