// 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