From 23edf7f909e392f63cd7024c4092b42565672218 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 27 Apr 2020 19:27:41 -0700 Subject: [PATCH 1/2] Delete deprecated tailcalls support --- .../superpmi-shared/icorjitinfoimpl.h | 3 - .../superpmi/superpmi-shared/lwmlist.h | 1 - .../superpmi-shared/methodcontext.cpp | 42 - .../superpmi/superpmi-shared/methodcontext.h | 11 +- .../superpmi-shim-collector/icorjitinfo.cpp | 11 +- .../superpmi-shim-counter/icorjitinfo.cpp | 9 +- .../superpmi-shim-simple/icorjitinfo.cpp | 6 - .../ToolBox/superpmi/superpmi/icorjitinfo.cpp | 7 - src/coreclr/src/inc/corinfo.h | 25 +- src/coreclr/src/inc/jithelpers.h | 6 +- src/coreclr/src/inc/vptr_list.h | 4 + src/coreclr/src/jit/ICorJitInfo_API_names.h | 2 +- .../src/jit/ICorJitInfo_API_wrapper.hpp | 16 +- .../tools/Common/JitInterface/CorInfoBase.cs | 61 +- .../tools/Common/JitInterface/CorInfoImpl.cs | 7 - .../tools/Common/JitInterface/CorInfoTypes.cs | 8 - .../ThunkGenerator/ThunkInput.txt | 2 - .../crossgen2/jitinterface/jitinterface.h | 10 - .../crossgen2/jitinterface/jitwrapper.cpp | 10 +- src/coreclr/src/vm/CMakeLists.txt | 2 - src/coreclr/src/vm/amd64/JitHelpers_Fast.asm | 108 --- src/coreclr/src/vm/amd64/cgenamd64.cpp | 34 - src/coreclr/src/vm/amd64/jithelpersamd64.cpp | 48 -- src/coreclr/src/vm/arm/asmhelpers.S | 113 --- src/coreclr/src/vm/arm/asmhelpers.asm | 116 --- src/coreclr/src/vm/arm/cgencpu.h | 29 +- src/coreclr/src/vm/arm/jithelpersarm.cpp | 51 -- src/coreclr/src/vm/arm/stubs.cpp | 483 +----------- src/coreclr/src/vm/arm64/stubs.cpp | 17 - src/coreclr/src/vm/frames.h | 81 +- src/coreclr/src/vm/i386/stublinkerx86.cpp | 720 ------------------ src/coreclr/src/vm/i386/stublinkerx86.h | 8 - src/coreclr/src/vm/jithelpers.cpp | 259 ------- src/coreclr/src/vm/jitinterface.cpp | 26 - src/coreclr/src/vm/jitinterface.h | 19 - src/coreclr/src/vm/stubmgr.cpp | 30 +- src/coreclr/src/vm/stubmgr.h | 15 + src/coreclr/src/zap/zapinfo.cpp | 10 - src/coreclr/src/zap/zapinfo.h | 4 - 39 files changed, 89 insertions(+), 2325 deletions(-) delete mode 100644 src/coreclr/src/vm/amd64/jithelpersamd64.cpp delete mode 100644 src/coreclr/src/vm/arm/jithelpersarm.cpp diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h index d3d79b84bd0fab..03c722caed8962 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h @@ -880,9 +880,6 @@ CORINFO_METHOD_HANDLE GetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, void MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd); -// return a thunk that will copy the arguments for the given signature. -void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags); - bool getTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h index 18abd23e676cf2..1922e7d0f5dfad 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h @@ -121,7 +121,6 @@ LWM(GetRelocTypeHint, DWORDLONG, DWORD) LWM(GetSharedCCtorHelper, DWORDLONG, DWORD) LWM(GetStringConfigValue, DWORD, DWORD) LWM(GetSystemVAmd64PassStructInRegisterDescriptor, DWORDLONG, Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor) -LWM(GetTailCallCopyArgsThunk, Agnostic_GetTailCallCopyArgsThunk, DWORDLONG) LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) LWM(GetThreadTLSIndex, DWORD, DLD) LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG) diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index 54d0185d296fd1..77603de0a850c6 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -5940,48 +5940,6 @@ const WCHAR* MethodContext::repAppendClassName(CORINFO_CLASS_HANDLE cls, return name; } -void MethodContext::recGetTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, - CorInfoHelperTailCallSpecialHandling flags, - void* result) -{ - if (GetTailCallCopyArgsThunk == nullptr) - GetTailCallCopyArgsThunk = new LightWeightMap(); - - Agnostic_GetTailCallCopyArgsThunk key; - ZeroMemory(&key, sizeof(Agnostic_GetTailCallCopyArgsThunk)); // We use the input structs as a key and use memcmp to - // compare.. so we need to zero out padding too - key.Sig = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(*pSig, GetTailCallCopyArgsThunk); - key.flags = (DWORD)flags; - - GetTailCallCopyArgsThunk->Add(key, (DWORDLONG)result); - DEBUG_REC(dmpGetTailCallCopyArgsThunk(key, (DWORDLONG)result)); -} - -void MethodContext::dmpGetTailCallCopyArgsThunk(const Agnostic_GetTailCallCopyArgsThunk& key, DWORDLONG value) -{ - printf("GetTailCallCopyArgsThunk key sig%s flg-%08X", - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(key.Sig).c_str(), key.flags); - printf(", value res-%016llX", value); -} - -void* MethodContext::repGetTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) -{ - AssertCodeMsg(GetTailCallCopyArgsThunk != nullptr, EXCEPTIONCODE_MC, "Didn't find anything for ..."); - - Agnostic_GetTailCallCopyArgsThunk key; - ZeroMemory(&key, sizeof(Agnostic_GetTailCallCopyArgsThunk)); // We use the input structs as a key and use memcmp to - // compare.. so we need to zero out padding too - key.Sig = SpmiRecordsHelper::RestoreAgnostic_CORINFO_SIG_INFO(*pSig, GetTailCallCopyArgsThunk); - key.flags = (DWORD)flags; - - AssertCodeMsg(GetTailCallCopyArgsThunk->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX", - (DWORDLONG)key.Sig.retTypeClass); - void* result = (void*)GetTailCallCopyArgsThunk->Get(key); - cr->recAddressMap((void*)0x424242, (void*)result, 1); - DEBUG_REP(dmpGetTailCallCopyArgsThunk(key, (DWORDLONG)result)); - return result; -} - void MethodContext::recGetTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h index fccf9ca8bd0fcb..1f34c4569e3358 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -436,11 +436,6 @@ class MethodContext DWORDLONG ProfilerHandle; DWORD bIndirectedHandles; }; - struct Agnostic_GetTailCallCopyArgsThunk - { - Agnostic_CORINFO_SIG_INFO Sig; - DWORD flags; - }; struct Agnostic_GetTailCallHelpers { Agnostic_CORINFO_RESOLVED_TOKEN callToken; @@ -1269,10 +1264,6 @@ class MethodContext void dmpAppendClassName(const Agnostic_AppendClassName& key, DWORD value); const WCHAR* repAppendClassName(CORINFO_CLASS_HANDLE cls, BOOL fNamespace, BOOL fFullInst, BOOL fAssembly); - void recGetTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags, void* result); - void dmpGetTailCallCopyArgsThunk(const Agnostic_GetTailCallCopyArgsThunk& key, DWORDLONG value); - void* repGetTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags); - void recGetTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, @@ -1464,7 +1455,7 @@ enum mcPackets Packet_GetRelocTypeHint = 84, Packet_GetSecurityPrologHelper = 85, // Retired 2/18/2020 Packet_GetSharedCCtorHelper = 86, - Packet_GetTailCallCopyArgsThunk = 87, + Packet_GetTailCallCopyArgsThunk = 87, // Retired 4/27/2020 Packet_GetTailCallHelpers = 178, // Added 3/18/2020 Packet_GetThreadTLSIndex = 88, Packet_GetTokenTypeAsHandle = 89, diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 2c613a6d6ca4d2..2da8785f96bc23 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1857,15 +1857,6 @@ void interceptor_ICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) original_ICorJitInfo->MethodCompileComplete(methHnd); } -// return a thunk that will copy the arguments for the given signature. -void* interceptor_ICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) -{ - mc->cr->AddCall("getTailCallCopyArgsThunk"); - void* result = original_ICorJitInfo->getTailCallCopyArgsThunk(pSig, flags); - mc->recGetTailCallCopyArgsThunk(pSig, flags, result); - return result; -} - bool interceptor_ICJI::getTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, @@ -2106,4 +2097,4 @@ DWORD interceptor_ICJI::getExpectedTargetArchitecture() void interceptor_ICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet, bool supported) { original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supported); -} \ No newline at end of file +} diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 5a885e3d5c0160..febd952a655fab 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -1442,13 +1442,6 @@ void interceptor_ICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) original_ICorJitInfo->MethodCompileComplete(methHnd); } -// return a thunk that will copy the arguments for the given signature. -void* interceptor_ICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) -{ - mcs->AddCall("getTailCallCopyArgsThunk"); - return original_ICorJitInfo->getTailCallCopyArgsThunk(pSig, flags); -} - bool interceptor_ICJI::getTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, @@ -1678,4 +1671,4 @@ void interceptor_ICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instruct { mcs->AddCall("notifyInstructionSetUsage"); original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supported); -} \ No newline at end of file +} diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp index 941cb17144ab80..26141d06068f46 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -1285,12 +1285,6 @@ void interceptor_ICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) original_ICorJitInfo->MethodCompileComplete(methHnd); } -// return a thunk that will copy the arguments for the given signature. -void* interceptor_ICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) -{ - return original_ICorJitInfo->getTailCallCopyArgsThunk(pSig, flags); -} - bool interceptor_ICJI::getTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp index ed6f3472e18db3..1591f347cbe90f 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp @@ -1540,13 +1540,6 @@ void MyICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) DebugBreakorAV(118); } -// return a thunk that will copy the arguments for the given signature. -void* MyICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) -{ - jitInstance->mc->cr->AddCall("getTailCallCopyArgsThunk"); - return jitInstance->mc->repGetTailCallCopyArgsThunk(pSig, flags); -} - bool MyICJI::getTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, diff --git a/src/coreclr/src/inc/corinfo.h b/src/coreclr/src/inc/corinfo.h index 10d3480c506e0c..9467045001daf7 100644 --- a/src/coreclr/src/inc/corinfo.h +++ b/src/coreclr/src/inc/corinfo.h @@ -217,11 +217,11 @@ TODO: Talk about initializing strutures before use #endif #endif -SELECTANY const GUID JITEEVersionIdentifier = { /* 108808e4-71b3-4573-8371-323323c4fb80 */ - 0x108808e4, - 0x71b3, - 0x4573, - {0x83, 0x71, 0x32, 0x33, 0x23, 0xc4, 0xfb, 0x80} +SELECTANY const GUID JITEEVersionIdentifier = { /* bb6ea6c3-ce5a-4543-86b7-c9c88f9ec780 */ + 0xbb6ea6c3, + 0xce5a, + 0x4543, + { 0x86, 0xb7, 0xc9, 0xc8, 0x8f, 0x9e, 0xc7, 0x80 } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1075,15 +1075,6 @@ enum CorInfoIndirectCallReason CORINFO_INDIRECT_CALL_COUNT }; -// When using CORINFO_HELPER_TAILCALL, the JIT needs to pass certain special -// calling convention/argument passing/handling details to the helper -enum CorInfoHelperTailCallSpecialHandling -{ - CORINFO_TAILCALL_NORMAL = 0x00000000, - CORINFO_TAILCALL_STUB_DISPATCH_ARG = 0x00000001, -}; - - inline bool dontInline(CorInfoInline val) { return(val < 0); } @@ -3140,12 +3131,6 @@ class ICorDynamicInfo : public ICorStaticInfo CORINFO_METHOD_HANDLE methHnd ) = 0; - // return a thunk that will copy the arguments for the given signature. - virtual void* getTailCallCopyArgsThunk ( - CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags - ) = 0; - // Obtain tailcall help for the specified call site. virtual bool getTailCallHelpers( diff --git a/src/coreclr/src/inc/jithelpers.h b/src/coreclr/src/inc/jithelpers.h index 9add356aa90514..608398ac17ef2c 100644 --- a/src/coreclr/src/inc/jithelpers.h +++ b/src/coreclr/src/inc/jithelpers.h @@ -220,11 +220,15 @@ JITHELPER(CORINFO_HELP_PINVOKE_CALLI, GenericPInvokeCalliHelper, CORINFO_HELP_SIG_NO_ALIGN_STUB) +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) JITHELPER(CORINFO_HELP_TAILCALL, JIT_TailCall, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) +#else + JITHELPER(CORINFO_HELP_TAILCALL, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) +#endif JITHELPER(CORINFO_HELP_GETCURRENTMANAGEDTHREADID, JIT_GetCurrentManagedThreadId, CORINFO_HELP_SIG_REG_ONLY) -#ifdef HOST_64BIT +#ifdef TARGET_64BIT JITHELPER(CORINFO_HELP_INIT_PINVOKE_FRAME, JIT_InitPInvokeFrame, CORINFO_HELP_SIG_REG_ONLY) #else DYNAMICJITHELPER(CORINFO_HELP_INIT_PINVOKE_FRAME, NULL, CORINFO_HELP_SIG_REG_ONLY) diff --git a/src/coreclr/src/inc/vptr_list.h b/src/coreclr/src/inc/vptr_list.h index 93e978224947d1..f53bbac1edf1e4 100644 --- a/src/coreclr/src/inc/vptr_list.h +++ b/src/coreclr/src/inc/vptr_list.h @@ -39,7 +39,9 @@ VPTR_CLASS(RangeSectionStubManager) VPTR_CLASS(ILStubManager) VPTR_CLASS(InteropDispatchStubManager) VPTR_CLASS(DelegateInvokeStubManager) +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) VPTR_CLASS(TailCallStubManager) +#endif VPTR_CLASS(CallCountingStubManager) VPTR_CLASS(PEFile) VPTR_CLASS(PEAssembly) @@ -93,7 +95,9 @@ VPTR_CLASS(DynamicHelperFrame) #if defined(TARGET_X86) VPTR_CLASS(UMThkCallFrame) #endif +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) VPTR_CLASS(TailCallFrame) +#endif VPTR_CLASS(ExceptionFilterFrame) #ifdef _DEBUG diff --git a/src/coreclr/src/jit/ICorJitInfo_API_names.h b/src/coreclr/src/jit/ICorJitInfo_API_names.h index a65c6c79c904db..b2f623ac96fb19 100644 --- a/src/coreclr/src/jit/ICorJitInfo_API_names.h +++ b/src/coreclr/src/jit/ICorJitInfo_API_names.h @@ -151,7 +151,7 @@ DEF_CLR_API(setOverride) DEF_CLR_API(addActiveDependency) DEF_CLR_API(GetDelegateCtor) DEF_CLR_API(MethodCompileComplete) -DEF_CLR_API(getTailCallCopyArgsThunk) +DEF_CLR_API(getTailCallHelpers) DEF_CLR_API(convertPInvokeCalliToCall) DEF_CLR_API(notifyInstructionSetUsage) DEF_CLR_API(getMemoryManager) diff --git a/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp index 6e4d016d90c5d7..44e4a3ea1055f1 100644 --- a/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp @@ -1476,13 +1476,15 @@ void WrapICorJitInfo::MethodCompileComplete( API_LEAVE(MethodCompileComplete); } -void* WrapICorJitInfo::getTailCallCopyArgsThunk( - CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags) -{ - API_ENTER(getTailCallCopyArgsThunk); - void *result = wrapHnd->getTailCallCopyArgsThunk(pSig, flags); - API_LEAVE(getTailCallCopyArgsThunk); +void* WrapICorJitInfo::getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) +{ + API_ENTER(getTailCallHelpers); + void *result = wrapHnd->getTailCallHelpers(callToken, sig, flags, pResult); + API_LEAVE(getTailCallHelpers); return result; } diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs index cd1aa4d820218b..6b2869f23967e1 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs @@ -314,8 +314,6 @@ unsafe partial class CorInfoImpl [UnmanagedFunctionPointerAttribute(default(CallingConvention))] delegate void __MethodCompileComplete(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd); [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getTailCallCopyArgsThunk(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags); - [UnmanagedFunctionPointerAttribute(default(CallingConvention))] [return: MarshalAs(UnmanagedType.I1)]delegate bool __getTailCallHelpers(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult); [UnmanagedFunctionPointerAttribute(default(CallingConvention))] [return: MarshalAs(UnmanagedType.I1)]delegate bool __convertPInvokeCalliToCall(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool mustConvert); @@ -2431,20 +2429,6 @@ static void _MethodCompileComplete(IntPtr thisHandle, IntPtr* ppException, CORIN } } - static void* _getTailCallCopyArgsThunk(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) - { - var _this = GetThis(thisHandle); - try - { - return _this.getTailCallCopyArgsThunk(pSig, flags); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - [return: MarshalAs(UnmanagedType.I1)]static bool _getTailCallHelpers(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) { var _this = GetThis(thisHandle); @@ -2705,8 +2689,8 @@ static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, ref CORJIT_FLAG static IntPtr GetUnmanagedCallbacks(out Object keepAlive) { - IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 171); - Object[] delegates = new Object[171]; + IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 170); + Object[] delegates = new Object[170]; var d0 = new __getMethodAttribs(_getMethodAttribs); callbacks[0] = Marshal.GetFunctionPointerForDelegate(d0); @@ -3161,66 +3145,63 @@ static IntPtr GetUnmanagedCallbacks(out Object keepAlive) var d150 = new __MethodCompileComplete(_MethodCompileComplete); callbacks[150] = Marshal.GetFunctionPointerForDelegate(d150); delegates[150] = d150; - var d151 = new __getTailCallCopyArgsThunk(_getTailCallCopyArgsThunk); + var d151 = new __getTailCallHelpers(_getTailCallHelpers); callbacks[151] = Marshal.GetFunctionPointerForDelegate(d151); delegates[151] = d151; - var d152 = new __getTailCallHelpers(_getTailCallHelpers); + var d152 = new __convertPInvokeCalliToCall(_convertPInvokeCalliToCall); callbacks[152] = Marshal.GetFunctionPointerForDelegate(d152); delegates[152] = d152; - var d153 = new __convertPInvokeCalliToCall(_convertPInvokeCalliToCall); + var d153 = new __notifyInstructionSetUsage(_notifyInstructionSetUsage); callbacks[153] = Marshal.GetFunctionPointerForDelegate(d153); delegates[153] = d153; - var d154 = new __notifyInstructionSetUsage(_notifyInstructionSetUsage); + var d154 = new __allocMem(_allocMem); callbacks[154] = Marshal.GetFunctionPointerForDelegate(d154); delegates[154] = d154; - var d155 = new __allocMem(_allocMem); + var d155 = new __reserveUnwindInfo(_reserveUnwindInfo); callbacks[155] = Marshal.GetFunctionPointerForDelegate(d155); delegates[155] = d155; - var d156 = new __reserveUnwindInfo(_reserveUnwindInfo); + var d156 = new __allocUnwindInfo(_allocUnwindInfo); callbacks[156] = Marshal.GetFunctionPointerForDelegate(d156); delegates[156] = d156; - var d157 = new __allocUnwindInfo(_allocUnwindInfo); + var d157 = new __allocGCInfo(_allocGCInfo); callbacks[157] = Marshal.GetFunctionPointerForDelegate(d157); delegates[157] = d157; - var d158 = new __allocGCInfo(_allocGCInfo); + var d158 = new __setEHcount(_setEHcount); callbacks[158] = Marshal.GetFunctionPointerForDelegate(d158); delegates[158] = d158; - var d159 = new __setEHcount(_setEHcount); + var d159 = new __setEHinfo(_setEHinfo); callbacks[159] = Marshal.GetFunctionPointerForDelegate(d159); delegates[159] = d159; - var d160 = new __setEHinfo(_setEHinfo); + var d160 = new __logMsg(_logMsg); callbacks[160] = Marshal.GetFunctionPointerForDelegate(d160); delegates[160] = d160; - var d161 = new __logMsg(_logMsg); + var d161 = new __doAssert(_doAssert); callbacks[161] = Marshal.GetFunctionPointerForDelegate(d161); delegates[161] = d161; - var d162 = new __doAssert(_doAssert); + var d162 = new __reportFatalError(_reportFatalError); callbacks[162] = Marshal.GetFunctionPointerForDelegate(d162); delegates[162] = d162; - var d163 = new __reportFatalError(_reportFatalError); + var d163 = new __allocMethodBlockCounts(_allocMethodBlockCounts); callbacks[163] = Marshal.GetFunctionPointerForDelegate(d163); delegates[163] = d163; - var d164 = new __allocMethodBlockCounts(_allocMethodBlockCounts); + var d164 = new __getMethodBlockCounts(_getMethodBlockCounts); callbacks[164] = Marshal.GetFunctionPointerForDelegate(d164); delegates[164] = d164; - var d165 = new __getMethodBlockCounts(_getMethodBlockCounts); + var d165 = new __recordCallSite(_recordCallSite); callbacks[165] = Marshal.GetFunctionPointerForDelegate(d165); delegates[165] = d165; - var d166 = new __recordCallSite(_recordCallSite); + var d166 = new __recordRelocation(_recordRelocation); callbacks[166] = Marshal.GetFunctionPointerForDelegate(d166); delegates[166] = d166; - var d167 = new __recordRelocation(_recordRelocation); + var d167 = new __getRelocTypeHint(_getRelocTypeHint); callbacks[167] = Marshal.GetFunctionPointerForDelegate(d167); delegates[167] = d167; - var d168 = new __getRelocTypeHint(_getRelocTypeHint); + var d168 = new __getExpectedTargetArchitecture(_getExpectedTargetArchitecture); callbacks[168] = Marshal.GetFunctionPointerForDelegate(d168); delegates[168] = d168; - var d169 = new __getExpectedTargetArchitecture(_getExpectedTargetArchitecture); + var d169 = new __getJitFlags(_getJitFlags); callbacks[169] = Marshal.GetFunctionPointerForDelegate(d169); delegates[169] = d169; - var d170 = new __getJitFlags(_getJitFlags); - callbacks[170] = Marshal.GetFunctionPointerForDelegate(d170); - delegates[170] = d170; keepAlive = delegates; return (IntPtr)callbacks; diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs index a40175039e25da..66f33ea70a6220 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs @@ -2538,13 +2538,6 @@ private void addActiveDependency(CORINFO_MODULE_STRUCT_* moduleFrom, CORINFO_MOD private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) { throw new NotImplementedException("MethodCompileComplete"); } - private void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) - { - // Slow tailcalls are not supported yet - // https://github.com/dotnet/runtime/issues/35423 - return null; - } - private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) { // Slow tailcalls are not supported yet diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs index f94af052f654a7..1c13a74c864525 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs @@ -756,14 +756,6 @@ public unsafe struct DelegateCtorArgs public void* pArg5; } - // When using CORINFO_HELPER_TAILCALL, the JIT needs to pass certain special - // calling convention/argument passing/handling details to the helper - public enum CorInfoHelperTailCallSpecialHandling - { - CORINFO_TAILCALL_NORMAL = 0x00000000, - CORINFO_TAILCALL_STUB_DISPATCH_ARG = 0x00000001, - } - /*****************************************************************************/ // These are flags passed to ICorJitInfo::allocMem // to guide the memory allocation for the code, readonly data, and read-write data diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 42b770afb0c086..fd5b9f464452c0 100644 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -111,7 +111,6 @@ ICorJitInfo::BlockCounts**,ref BlockCounts*,void** ; Enums CorInfoClassId,,int -CorInfoHelperTailCallSpecialHandling,,int CorInfoHelpFunc,,int CorInfoInitClassResult,,int CorInfoInlineTypeCheck,,int @@ -314,7 +313,6 @@ FUNCTIONS void addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom, CORINFO_MODULE_HANDLE moduleTo); CORINFO_METHOD_HANDLE GetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE targetMethodHnd, DelegateCtorArgs * pCtorData); void MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd); - void* getTailCallCopyArgsThunk (CORINFO_SIG_INFO *pSig, CorInfoHelperTailCallSpecialHandling flags); bool getTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, CORINFO_TAILCALL_HELPERS* pResult); bool convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool mustConvert); void notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet,bool supportEnabled); diff --git a/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h b/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h index 5ba6e043ae3f29..88144e0bb8455f 100644 --- a/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h +++ b/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h @@ -161,7 +161,6 @@ struct JitInterfaceCallbacks void (* addActiveDependency)(void * thisHandle, CorInfoException** ppException, void* moduleFrom, void* moduleTo); void* (* GetDelegateCtor)(void * thisHandle, CorInfoException** ppException, void* methHnd, void* clsHnd, void* targetMethodHnd, void* pCtorData); void (* MethodCompileComplete)(void * thisHandle, CorInfoException** ppException, void* methHnd); - void* (* getTailCallCopyArgsThunk)(void * thisHandle, CorInfoException** ppException, void* pSig, int flags); bool (* getTailCallHelpers)(void * thisHandle, CorInfoException** ppException, void* callToken, void* sig, int flags, void* pResult); bool (* convertPInvokeCalliToCall)(void * thisHandle, CorInfoException** ppException, void* pResolvedToken, bool mustConvert); void (* notifyInstructionSetUsage)(void * thisHandle, CorInfoException** ppException, int instructionSet, bool supportEnabled); @@ -1494,15 +1493,6 @@ class JitInterfaceWrapper throw pException; } - virtual void* getTailCallCopyArgsThunk(void* pSig, int flags) - { - CorInfoException* pException = nullptr; - void* _ret = _callbacks->getTailCallCopyArgsThunk(_thisHandle, &pException, pSig, flags); - if (pException != nullptr) - throw pException; - return _ret; - } - virtual bool getTailCallHelpers(void* callToken, void* sig, int flags, void* pResult) { CorInfoException* pException = nullptr; diff --git a/src/coreclr/src/tools/crossgen2/jitinterface/jitwrapper.cpp b/src/coreclr/src/tools/crossgen2/jitinterface/jitwrapper.cpp index 2db90ecf500293..85942a9551a145 100644 --- a/src/coreclr/src/tools/crossgen2/jitinterface/jitwrapper.cpp +++ b/src/coreclr/src/tools/crossgen2/jitinterface/jitwrapper.cpp @@ -27,11 +27,11 @@ class CORJIT_FLAGS uint64_t corJitFlags; }; -static const GUID JITEEVersionIdentifier = { /* 108808e4-71b3-4573-8371-323323c4fb80 */ - 0x108808e4, - 0x71b3, - 0x4573, - {0x83, 0x71, 0x32, 0x33, 0x23, 0xc4, 0xfb, 0x80} +static const GUID JITEEVersionIdentifier = { /* bb6ea6c3-ce5a-4543-86b7-c9c88f9ec780 */ + 0xbb6ea6c3, + 0xce5a, + 0x4543, + { 0x86, 0xb7, 0xc9, 0xc8, 0x8f, 0x9e, 0xc7, 0x80 } }; class Jit diff --git a/src/coreclr/src/vm/CMakeLists.txt b/src/coreclr/src/vm/CMakeLists.txt index 604c5d33e261b0..e11e58d777251d 100644 --- a/src/coreclr/src/vm/CMakeLists.txt +++ b/src/coreclr/src/vm/CMakeLists.txt @@ -786,7 +786,6 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64) ) set(VM_SOURCES_WKS_ARCH - ${ARCH_SOURCES_DIR}/jithelpersamd64.cpp ${ARCH_SOURCES_DIR}/jitinterfaceamd64.cpp ${ARCH_SOURCES_DIR}/profiler.cpp exceptionhandling.cpp @@ -839,7 +838,6 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM) ) set(VM_SOURCES_WKS_ARCH - ${ARCH_SOURCES_DIR}/jithelpersarm.cpp ${ARCH_SOURCES_DIR}/profiler.cpp exceptionhandling.cpp gcinfodecoder.cpp diff --git a/src/coreclr/src/vm/amd64/JitHelpers_Fast.asm b/src/coreclr/src/vm/amd64/JitHelpers_Fast.asm index 662c2d4509f829..8866399b41dd11 100644 --- a/src/coreclr/src/vm/amd64/JitHelpers_Fast.asm +++ b/src/coreclr/src/vm/amd64/JitHelpers_Fast.asm @@ -389,114 +389,6 @@ endif ret LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT - -extern JIT_FailFast:proc -extern s_gsCookie:qword - -OFFSETOF_GSCOOKIE equ 0h -OFFSETOF_FRAME equ OFFSETOF_GSCOOKIE + \ - 8h - -; -; incoming: -; -; rsp -> return address -; : -; -; Stack Layout: -; -; rsp-> callee scratch -; + 8h callee scratch -; +10h callee scratch -; +18h callee scratch -; : -; stack arguments -; : -; r13-> gsCookie -; + 8h __VFN_table -; +10h m_Next -; +18h m_pGCLayout -; +20h m_padding -; +28h m_rdi -; +30h m_rsi -; +38h m_rbx -; +40h m_rbp -; +48h m_r12 -; +50h m_r13 -; +58h m_r14 -; +60h m_r15 -; +68h m_ReturnAddress -; r12 -> // Caller's SP -; -; r14 = GetThread(); -; r15 = GetThread()->GetFrame(); // For restoring/popping the frame -; -NESTED_ENTRY TailCallHelperStub, _TEXT - PUSH_CALLEE_SAVED_REGISTERS - - alloc_stack 48h ; m_padding, m_pGCLayout, m_Next, __VFN_table, gsCookie, outgoing shadow area - - set_frame r13, 20h - END_PROLOGUE - - ; - ; This part is never executed, but we keep it here for reference - ; - int 3 - -if 0 ne 0 - ; Save the caller's SP - mov r12, rsp + ... - - ; - ; fully initialize the TailCallFrame - ; - call TCF_GETMETHODFRAMEVPTR - mov [r13 + OFFSETOF_FRAME], rax - - mov rax, s_gsCookie - mov [r13 + OFFSETOF_GSCOOKIE], rax - - ; - ; link the TailCallFrame - ; - INLINE_GETTHREAD r14 - mov r15, [r14 + OFFSETOF__Thread__m_pFrame] - mov [r13 + OFFSETOF_FRAME + OFFSETOF__Frame__m_Next], r15 - lea r10, [r13 + OFFSETOF_FRAME] - mov [r14 + OFFSETOF__Thread__m_pFrame], r10 -endif - - ; the pretend call would be here - ; with the return address pointing this this real epilog - -PATCH_LABEL JIT_TailCallHelperStub_ReturnAddress - - ; our epilog (which also unlinks the TailCallFrame) - -ifdef _DEBUG - mov rcx, s_gsCookie - cmp [r13 + OFFSETOF_GSCookie], rcx - je GoodGSCookie - call JIT_FailFast -GoodGSCookie: -endif ; _DEBUG - - ; - ; unlink the TailCallFrame - ; - mov [r14 + OFFSETOF__Thread__m_pFrame], r15 - - ; - ; epilog - ; - - lea rsp, [r13 + 28h] - POP_CALLEE_SAVED_REGISTERS - ret - -NESTED_END TailCallHelperStub, _TEXT - ; The following helper will access ("probe") a word on each page of the stack ; starting with the page right beneath rsp down to the one pointed to by r11. ; The procedure is needed to make sure that the "guard" page is pushed down below the allocated stack frame. diff --git a/src/coreclr/src/vm/amd64/cgenamd64.cpp b/src/coreclr/src/vm/amd64/cgenamd64.cpp index 35d00720264c8a..320884a50f46f0 100644 --- a/src/coreclr/src/vm/amd64/cgenamd64.cpp +++ b/src/coreclr/src/vm/amd64/cgenamd64.cpp @@ -77,40 +77,6 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); } -#ifndef DACCESS_COMPILE - -void TailCallFrame::InitFromContext(T_CONTEXT * pContext) -{ - WRAPPER_NO_CONTRACT; - -#define CALLEE_SAVED_REGISTER(regname) m_calleeSavedRegisters.regname = pContext->regname; - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - - m_pGCLayout = 0; - m_ReturnAddress = pContext->Rip; -} - -#endif // !DACCESS_COMPILE - -void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) -{ - LIMITED_METHOD_CONTRACT; - - pRD->IsCallerContextValid = FALSE; - pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. - - pRD->pCurrentContext->Rip = m_ReturnAddress; - pRD->pCurrentContext->Rsp = dac_cast(this) + sizeof(*this); - - UpdateRegDisplayFromCalleeSavedRegisters(pRD, &m_calleeSavedRegisters); - ClearRegDisplayArgumentAndScratchRegisters(pRD); - - SyncRegDisplayToCurrentContext(pRD); - - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); -} - void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) { CONTRACTL diff --git a/src/coreclr/src/vm/amd64/jithelpersamd64.cpp b/src/coreclr/src/vm/amd64/jithelpersamd64.cpp deleted file mode 100644 index 8f0a889fde231e..00000000000000 --- a/src/coreclr/src/vm/amd64/jithelpersamd64.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// 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. -// =========================================================================== -// File: JITHelpers.CPP -// =========================================================================== - -// This contains JITinterface routines that are specific to the -// AMD64 platform. They are modeled after the X86 specific routines -// found in JIThelp.asm - - -#include "common.h" -#include "jitinterface.h" -#include "eeconfig.h" -#include "excep.h" -#include "ecall.h" -#include "asmconstants.h" - -EXTERN_C void JIT_TailCallHelperStub_ReturnAddress(); - -TailCallFrame * TailCallFrame::GetFrameFromContext(CONTEXT * pContext) -{ - _ASSERTE((void*)::GetIP(pContext) == JIT_TailCallHelperStub_ReturnAddress); - return (TailCallFrame*)(pContext->R13 + sizeof(GSCookie)); -} - -// Assuming pContext is a plain generic call-site, adjust it to look like -// it called into TailCallHelperStub, and is at the point of the call. -TailCallFrame * TailCallFrame::AdjustContextForTailCallHelperStub(CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread) -{ - TailCallFrame * pNewFrame = (TailCallFrame *)(GetSP(pContext) - sizeof(TailCallFrame)); - - // R13 is the frame pointer (for popping the stack) - pContext->R13 = (size_t)pNewFrame - sizeof(GSCookie); - // R12 is the previous stack pointer, so we can determine if a return buffer from the - // immediate caller (and thus being discarded via the tail call), or someplace else - pContext->R12 = GetSP(pContext); - // for the args and pushed return address of the 'call' - SetSP(pContext, (size_t)pNewFrame - (cbNewArgArea + sizeof(void*) + sizeof(GSCookie))); - - // For popping the Frame, store the Thread - pContext->R14 = (DWORD_PTR)pThread; - // And the current head/top - pContext->R15 = (DWORD_PTR)pThread->GetFrame(); // m_Next - - return (TailCallFrame *) pNewFrame; -} diff --git a/src/coreclr/src/vm/arm/asmhelpers.S b/src/coreclr/src/vm/arm/asmhelpers.S index 0bb2dbee981fc9..e7f61937d886a1 100644 --- a/src/coreclr/src/vm/arm/asmhelpers.S +++ b/src/coreclr/src/vm/arm/asmhelpers.S @@ -134,119 +134,6 @@ LOCAL_LABEL(LReturnDone): NESTED_END CallDescrWorkerInternal,_TEXT - -//----------------------------------------------------------------------------- -// This helper routine is where returns for irregular tail calls end up -// so they can dynamically pop their stack arguments. -//----------------------------------------------------------------------------- -// -// Stack Layout (stack grows up, 0 at the top, offsets relative to frame pointer, r7): -// -// sp -> callee stack arguments -// : -// : -// -0Ch gsCookie -// TailCallHelperFrame -> -// -08h __VFN_table -// -04h m_Next -// r7 -> -// +00h m_calleeSavedRgisters.r4 -// +04h .r5 -// +08h .r6 -// +0Ch .r7 -// +10h .r8 -// +14h .r9 -// +18h .r10 -// r11-> -// +1Ch .r11 -// +20h .r14 -or- m_ReturnAddress -// -// r6 -> GetThread() -// r5 -> r6->m_pFrame (old Frame chain head) -// r11 is used to preserve the ETW call stack - - NESTED_ENTRY TailCallHelperStub, _TEXT, NoHandler - // - // This prolog is never executed, but we keep it here for reference - // and for the unwind data it generates - // - - // Spill callee saved registers and return address. - PROLOG_PUSH "{r4-r11,lr}" - - PROLOG_STACK_SAVE_OFFSET r7, #12 - - // - // This is the code that would have to run to setup this frame - // like the C++ helper does before calling RtlRestoreContext - // - // Allocate space for the rest of the frame and GSCookie. - // PROLOG_STACK_ALLOC 0x0C - // - // Set r11 for frame chain - //add r11, r7, 0x1C - // - // Set the vtable for TailCallFrame - //bl TCF_GETMETHODFRAMEVPTR - //str r0, [r7, #-8] - // - // Initialize the GSCookie within the Frame - //ldr r0, =s_gsCookie - //str r0, [r7, #-0x0C] - // - // Link the TailCallFrameinto the Frame chain - // and initialize r5 & r6 for unlinking later - //CALL_GETTHREAD - //mov r6, r0 - //ldr r5, [r6, #Thread__m_pFrame] - //str r5, [r7, #-4] - //sub r0, r7, 8 - //str r0, [r6, #Thread__m_pFrame] - // - // None of the previous stuff is ever executed, - // but we keep it here for reference - // - - // - // Here's the pretend call (make it real so the unwinder - // doesn't think we're in the prolog) - // - bl C_FUNC(TailCallHelperStub) - // - // with the real return address pointing to this real epilog - // -C_FUNC(JIT_TailCallHelperStub_ReturnAddress): -.global C_FUNC(JIT_TailCallHelperStub_ReturnAddress) - - // - // Our epilog (which also unlinks the StubHelperFrame) - // Be careful not to trash the return registers - // - -#ifdef _DEBUG - ldr r3, =s_gsCookie - ldr r3, [r3] - ldr r2, [r7, #-0x0C] - cmp r2, r3 - beq LOCAL_LABEL(GoodGSCookie) - bl C_FUNC(DoJITFailFast) -LOCAL_LABEL(GoodGSCookie): -#endif // _DEBUG - - // - // unlink the TailCallFrame - // - str r5, [r6, #Thread__m_pFrame] - - // - // epilog - // - EPILOG_STACK_RESTORE_OFFSET r7, #12 - EPILOG_POP "{r4-r11,lr}" - bx lr - - NESTED_END TailCallHelperStub, _TEXT - // ------------------------------------------------------------------ // void LazyMachStateCaptureState(struct LazyMachState *pState)// diff --git a/src/coreclr/src/vm/arm/asmhelpers.asm b/src/coreclr/src/vm/arm/asmhelpers.asm index a76f1103c13ac5..26b8619aef3c66 100644 --- a/src/coreclr/src/vm/arm/asmhelpers.asm +++ b/src/coreclr/src/vm/arm/asmhelpers.asm @@ -62,9 +62,6 @@ #endif IMPORT JIT_RareDisableHelperWorker - IMPORT DoJITFailFast - IMPORT s_gsCookie - IMPORT g_TrapReturningThreads ;; Imports for singleDomain statics helpers IMPORT JIT_GetSharedNonGCStaticBase_Helper @@ -193,119 +190,6 @@ LReturnDone NESTED_END - -;;----------------------------------------------------------------------------- -;; This helper routine is where returns for irregular tail calls end up -:: so they can dynamically pop their stack arguments. -;;----------------------------------------------------------------------------- -; -; Stack Layout (stack grows up, 0 at the top, offsets relative to frame pointer, r7): -; -; sp -> callee stack arguments -; : -; : -; -0Ch gsCookie -; TailCallHelperFrame -> -; -08h __VFN_table -; -04h m_Next -; r7 -> -; +00h m_calleeSavedRgisters.r4 -; +04h .r5 -; +08h .r6 -; +0Ch .r7 -; +10h .r8 -; +14h .r9 -; +18h .r10 -; r11-> -; +1Ch .r11 -; +20h .r14 -or- m_ReturnAddress -; -; r6 -> GetThread() -; r5 -> r6->m_pFrame (old Frame chain head) -; r11 is used to preserve the ETW call stack - - NESTED_ENTRY TailCallHelperStub - ; - ; This prolog is never executed, but we keep it here for reference - ; and for the unwind data it generates - ; - - ; Spill callee saved registers and return address. - PROLOG_PUSH {r4-r11,lr} - - PROLOG_STACK_SAVE r7 - - ; - ; This is the code that would have to run to setup this frame - ; like the C++ helper does before calling RtlRestoreContext - ; - ; Allocate space for the rest of the frame and GSCookie. - ; PROLOG_STACK_ALLOC 0x0C - ; - ; Set r11 for frame chain - ;add r11, r7, 0x1C - ; - ; Set the vtable for TailCallFrame - ;bl TCF_GETMETHODFRAMEVPTR - ;str r0, [r7, #-8] - ; - ; Initialize the GSCookie within the Frame - ;ldr r0, =s_gsCookie - ;str r0, [r7, #-0x0C] - ; - ; Link the TailCallFrameinto the Frame chain - ; and initialize r5 & r6 for unlinking later - ;CALL_GETTHREAD - ;mov r6, r0 - ;ldr r5, [r6, #Thread__m_pFrame] - ;str r5, [r7, #-4] - ;sub r0, r7, 8 - ;str r0, [r6, #Thread__m_pFrame] - ; - ; None of the previous stuff is ever executed, - ; but we keep it here for reference - ; - - ; - ; Here's the pretend call (make it real so the unwinder - ; doesn't think we're in the prolog) - ; - bl TailCallHelperStub - ; - ; with the real return address pointing to this real epilog - ; -JIT_TailCallHelperStub_ReturnAddress - EXPORT JIT_TailCallHelperStub_ReturnAddress - - ; - ; Our epilog (which also unlinks the StubHelperFrame) - ; Be careful not to trash the return registers - ; - -#ifdef _DEBUG - ldr r3, =s_gsCookie - ldr r3, [r3] - ldr r2, [r7, #-0x0C] - cmp r2, r3 - beq GoodGSCookie - bl DoJITFailFast -GoodGSCookie -#endif ; _DEBUG - - ; - ; unlink the TailCallFrame - ; - str r5, [r6, #Thread__m_pFrame] - - ; - ; epilog - ; - EPILOG_STACK_RESTORE r7 - EPILOG_POP {r4-r11,lr} - EPILOG_RETURN - - NESTED_END - ; ------------------------------------------------------------------ ; void LazyMachStateCaptureState(struct LazyMachState *pState); diff --git a/src/coreclr/src/vm/arm/cgencpu.h b/src/coreclr/src/vm/arm/cgencpu.h index edd80606ffd3c2..7b23a51c61a564 100644 --- a/src/coreclr/src/vm/arm/cgencpu.h +++ b/src/coreclr/src/vm/arm/cgencpu.h @@ -784,19 +784,6 @@ class StubLinkerCPU : public StubLinker Emit16((WORD)((imm3 << 12) | (dest << 8) | imm8)); } - void ThumbEmitCmpReg(ThumbReg reg1, ThumbReg reg2) - { - if(reg1 < 8 && reg2 <8) - { - Emit16((WORD)(0x4280 | reg2 << 3 | reg1)); - } - else - { - _ASSERTE(reg1 != ThumbReg(15) && reg2 != ThumbReg(15)); - Emit16((WORD)(0x4500 | reg2 << 3 | (reg1 & 0x7) | (reg1 & 0x8 ? 0x80 : 0x0))); - } - } - void ThumbEmitIncrement(ThumbReg dest, unsigned int value) { while (value) @@ -934,25 +921,11 @@ class StubLinkerCPU : public StubLinker } #endif // FEATURE_INTERPRETER - void ThumbEmitCondFlagJump(CodeLabel * target,UINT cond); - - void ThumbEmitCondRegJump(CodeLabel *target, BOOL nonzero, ThumbReg reg); - - void ThumbEmitNearJump(CodeLabel *target); - // Scratches r12. - void ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall); + void ThumbEmitTailCallManagedMethod(MethodDesc *pMD); void EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray); VOID EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, struct ShuffleEntry *pShuffleEntryArray, void* extraArg); - - static Stub * CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig, - MethodDesc* pMD, - CorInfoHelperTailCallSpecialHandling flags); - -private: - void ThumbCopyOneTailCallArg(UINT * pnSrcAlign, const ArgLocDesc * pArgLoc, UINT * pcbStackSpace); - void ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *pMD, void *pHiddenArg); }; extern "C" void SinglecastDelegateInvokeStub(); diff --git a/src/coreclr/src/vm/arm/jithelpersarm.cpp b/src/coreclr/src/vm/arm/jithelpersarm.cpp deleted file mode 100644 index 40827dd7127b8a..00000000000000 --- a/src/coreclr/src/vm/arm/jithelpersarm.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// 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. - -// =========================================================================== -// File: JITHelpersARM.CPP -// =========================================================================== - -// This contains JITinterface routines that are specific to the -// ARM platform. They are modeled after the AMD64 specific routines -// found in JIThelpersAMD64.cpp - - -#include "common.h" -#include "jitinterface.h" -#include "eeconfig.h" -#include "excep.h" -#include "ecall.h" -#include "asmconstants.h" - -EXTERN_C void JIT_TailCallHelperStub_ReturnAddress(); - -TailCallFrame * TailCallFrame::GetFrameFromContext(CONTEXT * pContext) -{ - _ASSERTE((void*)::GetIP(pContext) == JIT_TailCallHelperStub_ReturnAddress); - return (TailCallFrame*)(pContext->R7 - offsetof(TailCallFrame, m_calleeSavedRegisters)); -} - -// Assuming pContext is a plain generic call-site, adjust it to look like -// it called into TailCallHelperStub, and is at the point of the call. -TailCallFrame * TailCallFrame::AdjustContextForTailCallHelperStub(CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread) -{ - TailCallFrame * pNewFrame = (TailCallFrame *) (GetSP(pContext) - sizeof(TailCallFrame)); - - // The return addres for the pseudo-call - pContext->Lr = (DWORD_PTR)JIT_TailCallHelperStub_ReturnAddress; - // The R11/ETW chain 'frame' pointer - pContext->R11 = GetSP(pContext) - (2 * sizeof(DWORD)); // LR & R11 - // The unwind data frame pointer - pContext->R7 = pContext->R11 - (7 * sizeof(DWORD)); // r4-R10 non-volatile registers - // for the args and the remainder of the FrameWithCookie - SetSP(pContext, (size_t) pNewFrame - (cbNewArgArea + sizeof(GSCookie))); - - // For popping the Frame, store the Thread - pContext->R6 = (DWORD_PTR)pThread; - // And the current head/top - pContext->R5 = (DWORD_PTR)pThread->GetFrame(); - - return pNewFrame; -} - diff --git a/src/coreclr/src/vm/arm/stubs.cpp b/src/coreclr/src/vm/arm/stubs.cpp index 0a23cc413dd874..ce4cedb7538fd7 100644 --- a/src/coreclr/src/vm/arm/stubs.cpp +++ b/src/coreclr/src/vm/arm/stubs.cpp @@ -1609,7 +1609,7 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) #ifndef CROSSGEN_COMPILE -void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall) +void StubLinkerCPU::ThumbEmitTailCallManagedMethod(MethodDesc *pMD) { bool isRelative = MethodTable::VTableIndir2_t::isRelative && pMD->IsVtableSlot(); @@ -1631,12 +1631,6 @@ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall) if (isRelative) { - if (!fTailcall) - { - // str r4, [sp, 0] - ThumbEmitStoreRegIndirect(ThumbReg(4), thumbRegSp, 0); - } - // mov r4, r12 ThumbEmitMovRegReg(ThumbReg(4), ThumbReg(12)); } @@ -1648,33 +1642,19 @@ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall) { // add r12, r4 ThumbEmitAddReg(ThumbReg(12), ThumbReg(4)); - - if (!fTailcall) - { - // ldr r4, [sp, 0] - ThumbEmitLoadRegIndirect(ThumbReg(4), thumbRegSp, 0); - } } } - if (fTailcall) + if (!isRelative) { - if (!isRelative) - { - // bx r12 - ThumbEmitJumpRegister(ThumbReg(12)); - } - else - { - // Replace LR with R12 on stack: hybrid-tail call, same as for EmitShuffleThunk - // str r12, [sp, 4] - ThumbEmitStoreRegIndirect(ThumbReg(12), thumbRegSp, 4); - } + // bx r12 + ThumbEmitJumpRegister(ThumbReg(12)); } else { - // blx r12 - ThumbEmitCallRegister(ThumbReg(12)); + // Replace LR with R12 on stack: hybrid-tail call, same as for EmitShuffleThunk + // str r12, [sp, 4] + ThumbEmitStoreRegIndirect(ThumbReg(12), thumbRegSp, 4); } } @@ -1819,47 +1799,6 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); } -void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) -{ - pRD->IsCallerContextValid = FALSE; - pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. - - // Next, copy all the callee saved registers - UpdateRegDisplayFromCalleeSavedRegisters(pRD, &m_calleeSavedRegisters); - - // Set ControlPC to be the same as the saved "return address" - // value, which is actually a ControlPC in the frameless method (e.g. - // faulting address incase of AV or TAE). - pRD->pCurrentContext->Pc = m_ReturnAddress; - - // Set the caller SP - pRD->pCurrentContext->Sp = dac_cast(this) + sizeof(*this); - - // Finally, syncup the regdisplay with the context - SyncRegDisplayToCurrentContext(pRD); - - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); -} - -#ifndef DACCESS_COMPILE - -void TailCallFrame::InitFromContext(T_CONTEXT * pContext) -{ - WRAPPER_NO_CONTRACT; - - r4 = pContext->R4; - r5 = pContext->R5; - r6 = pContext->R6; - r7 = pContext->R7; - r8 = pContext->R8; - r9 = pContext->R9; - r10 = pContext->R10; - r11 = pContext->R11; - m_ReturnAddress = pContext->Lr; -} - -#endif // !DACCESS_COMPILE - void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) { LIMITED_METHOD_DAC_CONTRACT; @@ -2104,414 +2043,6 @@ void InitJITHelpers1() #endif // CROSSGEN_COMPILE -void StubLinkerCPU::ThumbEmitNearJump(CodeLabel *target) -{ - WRAPPER_NO_CONTRACT; - EmitLabelRef(target, reinterpret_cast(gThumbNearJump), 0xe); -} - -void StubLinkerCPU::ThumbEmitCondFlagJump(CodeLabel *target, UINT cond) -{ - WRAPPER_NO_CONTRACT; - EmitLabelRef(target, reinterpret_cast(gThumbNearJump), cond); -} - -void StubLinkerCPU::ThumbEmitCondRegJump(CodeLabel *target, BOOL nonzero, ThumbReg reg) -{ - WRAPPER_NO_CONTRACT; - _ASSERTE(reg <= 7); - UINT variation = reg; - if(nonzero) - variation = variation | 0x8; - EmitLabelRef(target, reinterpret_cast(gThumbCondJump), variation); -} - -void StubLinkerCPU::ThumbCopyOneTailCallArg(UINT * pnSrcAlign, const ArgLocDesc * pArgLoc, UINT * pcbStackSpace) -{ - if (pArgLoc->m_fRequires64BitAlignment && (*pnSrcAlign & 1)) { - // ADD R0, #4 - ThumbEmitIncrement(ThumbReg(0), 4); - *pnSrcAlign = 0; - } - - // Integer register arguments - if (pArgLoc->m_cGenReg > 0) { - int iReg = pArgLoc->m_idxGenReg; - int maxReg = iReg + pArgLoc->m_cGenReg; - while (iReg + 2 <= maxReg) { - // LDM r0!, {r4,r5} ; Post incremented loads (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(0), true, ThumbReg(4).Mask() | ThumbReg(5).Mask()); - // STR r4, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(4), ThumbReg(1), offsetof(T_CONTEXT, R0) + (iReg * sizeof(DWORD))); - iReg++; - // STR r5, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(5), ThumbReg(1), offsetof(T_CONTEXT, R0) + (iReg * sizeof(DWORD))); - iReg++; - } - if (iReg < maxReg) { - // LDR r3, [R0], #+4 ; Post incremented load (4 bytes) - ThumbEmitLoadIndirectPostIncrement(ThumbReg(3), ThumbReg(0), 4); - (*pnSrcAlign)++; - - // STR r3, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(3), ThumbReg(1), offsetof(T_CONTEXT, R0) + (iReg * sizeof(DWORD))); - } - } - if (pArgLoc->m_cFloatReg > 0) { - int iReg = pArgLoc->m_idxFloatReg; - int maxReg = iReg + pArgLoc->m_cFloatReg; - while (iReg + 2 <= maxReg) { - // LDM r0!, {r4,r5} ; Post incremented loads (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(0), true, ThumbReg(4).Mask() | ThumbReg(5).Mask()); - // STR r4, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(4), ThumbReg(1), offsetof(T_CONTEXT, S) + (iReg * sizeof(DWORD))); - iReg++; - // STR r5, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(5), ThumbReg(1), offsetof(T_CONTEXT, S) + (iReg * sizeof(DWORD))); - iReg++; - } - if (iReg < maxReg) { - // LDR r3, [R0], #+4 ; Post incremented load (4 bytes) - ThumbEmitLoadIndirectPostIncrement(ThumbReg(3), ThumbReg(0), 4); - (*pnSrcAlign)++; - - // STR r3, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(3), ThumbReg(1), offsetof(T_CONTEXT, S) + (iReg * sizeof(DWORD))); - } - } - - if (pArgLoc->m_cStack > 0) { - // Copy to the stack - // Be careful because this can get big and ugly. - _ASSERTE(*pcbStackSpace <= (pArgLoc->m_idxStack * sizeof(DWORD))); - - // Pad the output - if (*pcbStackSpace < (pArgLoc->m_idxStack * sizeof(DWORD))) - { - const UINT cbPad = ((pArgLoc->m_idxStack * sizeof(DWORD)) - *pcbStackSpace); - _ASSERTE(cbPad == 4); - // ADD R2, #4 - ThumbEmitIncrement(ThumbReg(2), cbPad); - *pcbStackSpace += cbPad; - } - int cStack = pArgLoc->m_cStack; - *pcbStackSpace += (cStack * sizeof(DWORD)); - - // Now start the copying - if (cStack > 8) { - // Loop to copy in 16-byte chunks per loop. - // Sacrifice r3 for the loop counter - ThumbEmitMovConstant(ThumbReg(3), pArgLoc->m_cStack & ~3); - // LoopLabel: - CodeLabel *pLoopLabel = NewCodeLabel(); - EmitLabel(pLoopLabel); - const WORD mask = ThumbReg(4).Mask() | ThumbReg(5).Mask() | ThumbReg(6).Mask() | ThumbReg(7).Mask(); - // LDM r0!, {r4,r5,r6,r7} ; Post incremented loads (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(0), true, mask); - // STM r2!, {r4,r5,r6,r7} ; Post incremented stores (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(2), false, mask); - // SUBS r3, #4 - Emit16((WORD)(0x3800 | (ThumbReg(3) << 8) | 4)); - // BNZ LoopLabel - ThumbEmitCondFlagJump(pLoopLabel, thumbCondNe.cond); - - cStack = cStack % 4; - // Now deal with the tail if any - } - _ASSERTE(cStack <= 8); - - while (cStack > 1) { - _ASSERTE(cStack >= 2); - WORD mask = ThumbReg(4).Mask() | ThumbReg(5).Mask(); - cStack -= 2; - if (cStack > 0) { - mask |= ThumbReg(6).Mask(); - cStack--; - // Instead of copying 4 slots and leaving a single slot remainder - // which would require us to use the bigger opcodes for the tail - // Only copy 3 slots this loop, saving 2 for next time. :) - if (cStack == 1 || cStack > 2) { - mask |= ThumbReg(7).Mask(); - cStack--; - } - else { - // We're reading an odd amount from the stack - (*pnSrcAlign)++; - } - } - - // LDM r0!, {r4,r5,r6,r7} ; Post incremented loads (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(0), true, mask); - // STM r2!, {r4,r5,r6,r7} ; Post incremented stores (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(2), false, mask); - _ASSERTE((cStack == 0) || (cStack >= 2)); - } - if (cStack > 0) { - _ASSERTE(cStack == 1); - // We're reading an odd amount from the stack - (*pnSrcAlign)++; - // LDR r12, [R0], #+4 ; Post incremented load (4 bytes) - ThumbEmitLoadIndirectPostIncrement(ThumbReg(12), ThumbReg(0), 4); - // STR r12, [R2], #+4 ; Post incremented store (4 bytes) - ThumbEmitStoreIndirectPostIncrement(ThumbReg(12), ThumbReg(2), 4); - } - } -} - - -Stub * StubLinkerCPU::CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig, - MethodDesc* pMD, - CorInfoHelperTailCallSpecialHandling flags) -{ - STANDARD_VM_CONTRACT; - - CPUSTUBLINKER sl; - CPUSTUBLINKER* pSl = &sl; - - // Generates a function that looks like this: - // size_t CopyArguments(va_list args, (R0) - // CONTEXT *pCtx, (R1) - // DWORD *pvStack, (R2) - // size_t cbStack) (R3) - // { - // if (pCtx != NULL) { - // foreach (arg in args) { - // copy into pCtx or pvStack - // } - // } - // return ; - // } - // - - Module * module = GetModule(pSig->scope); - Instantiation classInst((TypeHandle*)pSig->sigInst.classInst, pSig->sigInst.classInstCount); - Instantiation methodInst((TypeHandle*)pSig->sigInst.methInst, pSig->sigInst.methInstCount); - SigTypeContext typeCtxt(classInst, methodInst); - - // The -8 is because R11 points at the pushed {R11, LR} pair, and it is aligned. - // This is the magic distance, between the frame pointer and the Frame. - const UINT cbFrameOffset = (sizeof(FrameWithCookie) - 8); - - bool fNeedExtraRegs = false; - UINT copyEstimate = 0; - { - // Do a quick scan of the arguments looking for ones that will probably need extra registers - // and guestimating the size of the method - if (flags & CORINFO_TAILCALL_STUB_DISPATCH_ARG) - copyEstimate += 6; - - if (pSig->hasThis()) - copyEstimate += 6; - - MetaSig msig(pSig->pSig, pSig->cbSig, module, &typeCtxt); - if (pSig->hasTypeArg()) - msig.SetHasParamTypeArg(); - ArgIterator argPlacer(&msig); - - if (argPlacer.HasRetBuffArg()) { - copyEstimate += 24; - } - - if (pSig->hasTypeArg() || pSig->isVarArg()) - copyEstimate += 6; - - int argOffset; - while ((argOffset = argPlacer.GetNextOffset()) != TransitionBlock::InvalidOffset) - { - ArgLocDesc argLoc; - argPlacer.GetArgLoc(argOffset, &argLoc); - - if (argLoc.m_cStack > 1 || argLoc.m_cGenReg > 1 || argLoc.m_cFloatReg > 1) { - fNeedExtraRegs = true; - } - else { - copyEstimate += 8; - } - } - } - - if (fNeedExtraRegs) { - // Inject a proper prolog - // push {r4-r7,lr} - pSl->ThumbEmitProlog(4, 0, false); - } - - CodeLabel *pNullLabel = pSl->NewCodeLabel(); - - if (!fNeedExtraRegs && copyEstimate < 100) { - // The real range of BCZ is 0-126, but that's hard to estimate that precisely - // and we don't want to do that much work just to save a few bytes - - // BCZ R1, NullLabel - pSl->ThumbEmitCondRegJump(pNullLabel, false, ThumbReg(1)); - } - else { - // CMP R1, 0 ; T1 encoding - pSl->Emit16((WORD)(0x2900)); - - // BEQ NullLabel - pSl->ThumbEmitCondFlagJump(pNullLabel, thumbCondEq.cond); - } - - UINT cbStackSpace = 0; - UINT cbReturnBufferSpace = 0; - UINT nSrcAlign = 0; - - if (flags & CORINFO_TAILCALL_STUB_DISPATCH_ARG) { - // This is set for stub dispatch or 'thisInSecretRegister' - // The JIT placed an extra argument in the list that needs to - // get shoved into R4, and not counted. - // pCtx->R4 = va_arg(args, DWORD); - - // LDR r3, [R0], #+4 ; Post incremented load (4 bytes) - pSl->ThumbEmitLoadIndirectPostIncrement(ThumbReg(3), ThumbReg(0), 4); - // STR r3, [R1, #offset of R4] ; (2 bytes) - pSl->ThumbEmitStoreRegIndirect(ThumbReg(3), ThumbReg(1), offsetof(T_CONTEXT, R4)); - nSrcAlign++; - } - - - MetaSig msig(pSig->pSig, pSig->cbSig, module, &typeCtxt); - if (pSig->hasTypeArg()) - msig.SetHasParamTypeArg(); - ArgIterator argPlacer(&msig); - ArgLocDesc argLoc; - - // First comes the 'this' pointer - if (argPlacer.HasThis()) { - argPlacer.GetThisLoc(&argLoc); - pSl->ThumbCopyOneTailCallArg(&nSrcAlign, &argLoc, &cbStackSpace); - } - - // Next comes the return buffer - if (argPlacer.HasRetBuffArg()) { - // We always reserve space for the return buffer, but we never zero it out, - // and we never report it. Thus the callee shouldn't do RVO and expect - // to be able to read GC pointers from it. - // If the passed in return buffer is already pointing above the frame, - // then we need to pass it along (so it will get passed out). - // Otherwise we assume the caller is returning void, so we just pass in - // dummy space to be overwritten. - - argPlacer.GetRetBuffArgLoc(&argLoc); - _ASSERTE(argLoc.m_cStack == 0); - _ASSERTE(argLoc.m_cFloatReg == 0); - _ASSERTE(argLoc.m_cGenReg == 1); - - // Grab some space from the top of the frame and pass that in as a dummy - // buffer if needed. Align to 8-byte boundary (after taking in account the Frame). - // Do this by adding the Frame size, align, then remove the Frame size... - _ASSERTE((pSig->retType == CORINFO_TYPE_REFANY) || (pSig->retType == CORINFO_TYPE_VALUECLASS)); - TypeHandle th(pSig->retTypeClass); - UINT cbUsed = ((th.GetSize() + cbFrameOffset + 0x7) & ~0x7) - cbFrameOffset; - _ASSERTE(cbUsed >= th.GetSize()); - cbReturnBufferSpace += cbUsed; - - // LDR r3, [R0], #+4 ; Post incremented load (4 bytes) - pSl->ThumbEmitLoadIndirectPostIncrement(ThumbReg(3), ThumbReg(0), 4); - - // LDR r12, [R1, #offset of R11] ; (2 bytes) - pSl->ThumbEmitLoadRegIndirect(ThumbReg(12), ThumbReg(1), offsetof(T_CONTEXT, R11)); - - // CMP r3, r12 ; (2 bytes) - pSl->ThumbEmitCmpReg(ThumbReg(3), ThumbReg(12)); - - CodeLabel *pSkipLabel = pSl->NewCodeLabel(); - // BHI NullLabel ; skip if R3 > R12 unsigned (2 bytes) - pSl->ThumbEmitCondFlagJump(pSkipLabel, thumbCondHi.cond); - - // Also check the lower bound of the stack in case the return buffer is on the GC heap - // and the GC heap is below the stack - // CMP r3, sp ; (2 bytes) - pSl->ThumbEmitCmpReg(ThumbReg(3), thumbRegSp); - // BLO NullLabel ; skip if r3 < sp unsigned (2 bytes) - pSl->ThumbEmitCondFlagJump(pSkipLabel, thumbCondCc.cond); - - // If the caller is expecting us to simulate a return buffer for the callee - // pass that pointer in now, by subtracting from R11 space for the Frame - // and space for the return buffer. - UINT offset = cbUsed + cbFrameOffset; - if (offset < 4096) { - // SUB r3, r12, #offset ; (4 bytes) - pSl->ThumbEmitSub(ThumbReg(3), ThumbReg(12), offset); - } - else { - offset = UINT(-int(offset)); // Silence the @#$%^ warning - // MOVW/MOVT (4-8 bytes) - // ADD r3, r12; (2 bytes) - pSl->ThumbEmitAdd(ThumbReg(3), ThumbReg(12), offset); - } - // SkipLabel: - pSl->EmitLabel(pSkipLabel); - // STR r3, [R1, #offset of arg reg] ; (2 bytes) - pSl->ThumbEmitStoreRegIndirect(ThumbReg(3), ThumbReg(1), offsetof(T_CONTEXT, R0) + (argLoc.m_idxGenReg * sizeof(DWORD))); - - nSrcAlign++; - } - - // Generics Instantiation Parameter - if (pSig->hasTypeArg()) { - argPlacer.GetParamTypeLoc(&argLoc); - pSl->ThumbCopyOneTailCallArg(&nSrcAlign, &argLoc, &cbStackSpace); - } - - // VarArgs Cookie Parameter - if (pSig->isVarArg()) { - argPlacer.GetVASigCookieLoc(&argLoc); - pSl->ThumbCopyOneTailCallArg(&nSrcAlign, &argLoc, &cbStackSpace); - } - - // Now for *all* the 'real' arguments - int argOffset; - while ((argOffset = argPlacer.GetNextOffset()) != TransitionBlock::InvalidOffset) - { - argPlacer.GetArgLoc(argOffset, &argLoc); - - pSl->ThumbCopyOneTailCallArg(&nSrcAlign, &argLoc, &cbStackSpace); - } - - // Now that we are done moving arguments, add back in the stack space we reserved - // for the return buffer. - cbStackSpace += cbReturnBufferSpace; - - // Keep the stack space 8-byte aligned - if ((cbStackSpace + cbFrameOffset) & 7) { - cbStackSpace += 4; - } - _ASSERTE(((cbStackSpace + cbFrameOffset) & 7) == 0); - - CodeLabel *pReturnLabel = pSl->NewCodeLabel(); - // B ReturnLabel: - pSl->ThumbEmitNearJump(pReturnLabel); - - // NullLabel: - pSl->EmitLabel(pNullLabel); - // MOVW/MOVT r0, 0 ; No GCLayout info - pSl->ThumbEmitMovConstant(ThumbReg(0), 0); - // STR r0, [r3] - pSl->ThumbEmitStoreRegIndirect(ThumbReg(0), ThumbReg(3), 0); - - // ReturnLabel: - pSl->EmitLabel(pReturnLabel); - - // MOVW/MOVT r0, #cbStackSpace - pSl->ThumbEmitMovConstant(ThumbReg(0), cbStackSpace); - - if (fNeedExtraRegs) { - // Inject a proper prolog - // pop {r4-r7,pc} - pSl->ThumbEmitEpilog(); - } - else { - // bx lr - pSl->ThumbEmitJumpRegister(thumbRegLr); - } - - LoaderHeap* pHeap = pMD->GetLoaderAllocator()->GetStubHeap(); - return pSl->Link(pHeap); -} - - VOID ResetCurrentContext() { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/src/vm/arm64/stubs.cpp b/src/coreclr/src/vm/arm64/stubs.cpp index 9987da8e79ff72..2c482db470ff7d 100644 --- a/src/coreclr/src/vm/arm64/stubs.cpp +++ b/src/coreclr/src/vm/arm64/stubs.cpp @@ -837,23 +837,6 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) #endif -#ifndef CROSSGEN_COMPILE - -void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) -{ - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TailCallFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); - _ASSERTE(!"ARM64:NYI"); -} - -#ifndef DACCESS_COMPILE -void TailCallFrame::InitFromContext(T_CONTEXT * pContext) -{ - _ASSERTE(!"ARM64:NYI"); -} -#endif // !DACCESS_COMPILE - -#endif // CROSSGEN_COMPILE - void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) { LIMITED_METHOD_DAC_CONTRACT; diff --git a/src/coreclr/src/vm/frames.h b/src/coreclr/src/vm/frames.h index 1976d7397fe26c..7e519763bbef38 100644 --- a/src/coreclr/src/vm/frames.h +++ b/src/coreclr/src/vm/frames.h @@ -108,9 +108,10 @@ // | +-UMThkCallFrame - this frame represents an unmanaged->managed // | transition through N/Direct #endif -// | +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) // +-TailCallFrame - padding for tailcalls // | +#endif // +-ProtectByRefsFrame // | // +-ProtectValueClassFrame @@ -242,7 +243,9 @@ FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame) FRAME_TYPE_NAME(UMThkCallFrame) #endif FRAME_TYPE_NAME(InlinedCallFrame) +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) FRAME_TYPE_NAME(TailCallFrame) +#endif FRAME_TYPE_NAME(ExceptionFilterFrame) #if defined(_DEBUG) FRAME_TYPE_NAME(AssumeByrefFromJITStack) @@ -3006,8 +3009,8 @@ class InlinedCallFrame : public Frame //bool isLegalManagedCodeCaller(TADDR retAddr); bool isRetAddr(TADDR retAddr, TADDR* whereCalled); +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) //------------------------------------------------------------------------ -#ifdef TARGET_X86 // This frame is used as padding for virtual stub dispatch tailcalls. // When A calls B via virtual stub dispatch, the stub dispatch stub resolves // the target code for B and jumps to it. If A wants to do a tail call, @@ -3024,69 +3027,18 @@ bool isRetAddr(TADDR retAddr, TADDR* whereCalled); // We could eliminate TailCallFrame if we factor the VSD stub to return // the target code address. This is currently not a very important scenario // as tail calls on interface calls are uncommon. -#else -// This frame is used as padding for tailcalls which require more space -// than the caller has in it's incoming argument space. -// To do a tail call from A to B, A calls JIT_TailCall, which unwinds A's frame -// and sets up a TailCallFrame and the arguments. It then jumps to B. -// If B also does a tail call, then we reuse the -// existing TailCallFrame instead of setting up a second one. -// -// This is also used whenever value types that aren't enregisterable are -// passed by value instead of ref. This is currently not a very important -// scenario as tail calls are uncommon. -#endif //------------------------------------------------------------------------ class TailCallFrame : public Frame { VPTR_VTABLE_CLASS(TailCallFrame, Frame) -#if defined(TARGET_X86) TADDR m_CallerAddress; // the address the tailcall was initiated from CalleeSavedRegisters m_regs; // callee saved registers - the stack walk assumes that all non-JIT frames have them TADDR m_ReturnAddress; // the return address of the tailcall -#elif defined(TARGET_AMD64) - TADDR m_pGCLayout; - TADDR m_padding; // code:StubLinkerCPU::CreateTailCallCopyArgsThunk expects the size of TailCallFrame to be 16-byte aligned - CalleeSavedRegisters m_calleeSavedRegisters; - TADDR m_ReturnAddress; -#elif defined(TARGET_ARM) - union { - CalleeSavedRegisters m_calleeSavedRegisters; - // alias saved link register as m_ReturnAddress - struct { - INT32 r4, r5, r6, r7, r8, r9, r10; - INT32 r11; - TADDR m_ReturnAddress; - }; - }; -#else - TADDR m_ReturnAddress; -#endif public: -#ifndef CROSSGEN_COMPILE -#if !defined(TARGET_X86) - -#ifndef DACCESS_COMPILE - TailCallFrame(T_CONTEXT * pContext, Thread * pThread) - { - InitFromContext(pContext); - m_Next = pThread->GetFrame(); - } - - void InitFromContext(T_CONTEXT * pContext); - - // Architecture-specific method to initialize a CONTEXT record as if the first - // part of the TailCallHelperStub had executed - static TailCallFrame * AdjustContextForTailCallHelperStub(_CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread); -#endif - - static TailCallFrame * GetFrameFromContext(CONTEXT * pContext); -#endif // !TARGET_X86 - -#if defined(TARGET_X86) +#ifndef CROSSGEN_COMPILE static TailCallFrame* FindTailCallFrame(Frame* pFrame) { LIMITED_METHOD_CONTRACT; @@ -3101,7 +3053,6 @@ class TailCallFrame : public Frame LIMITED_METHOD_CONTRACT; return m_CallerAddress; } -#endif // TARGET_X86 virtual TADDR GetReturnAddressPtr() { @@ -3117,26 +3068,12 @@ class TailCallFrame : public Frame virtual void UpdateRegDisplay(const PREGDISPLAY pRD); #endif // !CROSSGEN_COMPILE -#ifdef TARGET_AMD64 - void SetGCLayout(TADDR pGCLayout) - { - LIMITED_METHOD_CONTRACT; - m_pGCLayout = pGCLayout; - } - - virtual void GcScanRoots(promote_func *fn, ScanContext* sc); -#else - void SetGCLayout(TADDR pGCLayout) - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(pGCLayout == NULL); - } -#endif private: // Keep as last entry in class DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(TailCallFrame) }; +#endif // TARGET_X86 && !UNIX_X86_ABI //------------------------------------------------------------------------ // ExceptionFilterFrame is a small frame whose only purpose in @@ -3296,10 +3233,6 @@ class FrameWithCookie m_gsCookie(GetProcessGSCookie()), m_frame(pDebuggerEval, returnAddress, showFrame) { WRAPPER_NO_CONTRACT; } #endif // DEBUGGING_SUPPORTED - // TailCallFrame - FrameWithCookie(T_CONTEXT * pContext, Thread *thread) : - m_gsCookie(GetProcessGSCookie()), m_frame(pContext, thread) { WRAPPER_NO_CONTRACT; } - #ifndef DACCESS_COMPILE // GSCookie for HelperMethodFrames is initialized in a common HelperMethodFrame init method diff --git a/src/coreclr/src/vm/i386/stublinkerx86.cpp b/src/coreclr/src/vm/i386/stublinkerx86.cpp index eac75f64b93013..5e801b4d704a13 100644 --- a/src/coreclr/src/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/src/vm/i386/stublinkerx86.cpp @@ -5121,726 +5121,6 @@ Thread* __stdcall CreateThreadBlockReturnHr(ComMethodFrame *pFrame) #endif // !DACCESS_COMPILE - -#ifdef TARGET_AMD64 - -// -// TailCallFrame Object Scanning -// -// This handles scanning/promotion of GC objects that were -// protected by the TailCallHelper routine. Note that the objects -// being protected is somewhat dynamic and is dependent upon the -// the callee... -// - -void TailCallFrame::GcScanRoots(promote_func *fn, ScanContext* sc) -{ - WRAPPER_NO_CONTRACT; - - if (m_pGCLayout != NULL) - { - struct FrameOffsetDecoder { - private: - TADDR prevOffset; - TADDR rangeEnd; - BOOL maybeInterior; - BOOL atEnd; - PTR_SBYTE pbOffsets; - - DWORD ReadNumber() { - signed char i; - DWORD offset = 0; - while ((i = *pbOffsets++) >= 0) - { - offset = (offset << 7) | i; - } - offset = (offset << 7) | (i & 0x7F); - return offset; - } - - public: - FrameOffsetDecoder(PTR_GSCookie _base, TADDR offsets) - : prevOffset(dac_cast(_base)), rangeEnd(~0LL), atEnd(FALSE), pbOffsets(dac_cast(offsets)) { maybeInterior = FALSE;} - - bool MoveNext() { - LIMITED_METHOD_CONTRACT; - - if (rangeEnd < prevOffset) - { - prevOffset -= sizeof(void*); - return true; - } - if (atEnd) return false; - DWORD offset = ReadNumber(); - atEnd = (offset & 1); - BOOL range = (offset & 2); - maybeInterior = (offset & 0x80000000); - - offset &= 0x7FFFFFFC; - -#ifdef HOST_64BIT - offset <<= 1; -#endif - offset += sizeof(void*); - _ASSERTE(prevOffset > offset); - prevOffset -= offset; - - if (range) - { - _ASSERTE(!atEnd); - _ASSERTE(!maybeInterior); - DWORD offsetEnd = ReadNumber(); - atEnd = (offsetEnd & 1); - offsetEnd = (offsetEnd & ~1) << 1; - // range encoding starts with a range of 3 (2 is better to encode as - // 2 offsets), so 0 == 2 (the last offset in the range) - offsetEnd += sizeof(void*) * 2; - rangeEnd = prevOffset - offsetEnd; - } - - return true; - } - - BOOL MaybeInterior() const { return maybeInterior; } - - PTR_PTR_Object Current() const { return PTR_PTR_Object(prevOffset); } - - } decoder(GetGSCookiePtr(), m_pGCLayout); - - while (decoder.MoveNext()) - { - PTR_PTR_Object ppRef = decoder.Current(); - - LOG((LF_GC, INFO3, "Tail Call Frame Promoting" FMT_ADDR "to", - DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*ppRef)) )); - if (decoder.MaybeInterior()) - PromoteCarefully(fn, ppRef, sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN); - else - (*fn)(ppRef, sc, 0); - LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*ppRef)) )); - } - } -} - -#ifndef DACCESS_COMPILE -static void EncodeOneGCOffset(CPUSTUBLINKER *pSl, ULONG delta, BOOL maybeInterior, BOOL range, BOOL last) -{ - CONTRACTL - { - THROWS; // From the stublinker - MODE_ANY; - GC_NOTRIGGER; - } - CONTRACTL_END; - - // Everything should be pointer aligned - // but we use a high bit for interior, and the 0 bit to denote the end of the list - // we use the 1 bit to denote a range - _ASSERTE((delta % sizeof(void*)) == 0); - -#if defined(HOST_64BIT) - // For 64-bit, we have 3 bits of alignment, so we allow larger frames - // by shifting and gaining a free high-bit. - ULONG encodedDelta = delta >> 1; -#else - // For 32-bit, we just limit our frame size to <2GB. - ULONG encodedDelta = delta; -#endif - _ASSERTE((encodedDelta & 0x80000003) == 0); - if (last) - { - encodedDelta |= 1; - } - - if (range) - { - encodedDelta |= 2; - } - else if (maybeInterior) - { - _ASSERTE(!range); - encodedDelta |= 0x80000000; - } - - BYTE bytes[5]; - UINT index = 5; - bytes[--index] = (BYTE)((encodedDelta & 0x7F) | 0x80); - encodedDelta >>= 7; - while (encodedDelta > 0) - { - bytes[--index] = (BYTE)(encodedDelta & 0x7F); - encodedDelta >>= 7; - } - pSl->EmitBytes(&bytes[index], 5 - index); -} - -static void EncodeGCOffsets(CPUSTUBLINKER *pSl, /* const */ ULONGARRAY & gcOffsets) -{ - CONTRACTL - { - THROWS; - MODE_ANY; - GC_NOTRIGGER; - } - CONTRACTL_END; - - _ASSERTE(gcOffsets.Count() > 0); - - ULONG prevOffset = 0; - int i = 0; - BOOL last = FALSE; - do { - ULONG offset = gcOffsets[i]; - // Everything should be pointer aligned - // but we use the 0-bit to mean maybeInterior, for byrefs. - _ASSERTE(((offset % sizeof(void*)) == 0) || ((offset % sizeof(void*)) == 1)); - BOOL maybeInterior = (offset & 1); - offset &= ~1; - - // Encode just deltas because they're smaller (and the list should be sorted) - _ASSERTE(offset >= (prevOffset + sizeof(void*))); - ULONG delta = offset - (prevOffset + sizeof(void*)); - if (!maybeInterior && gcOffsets.Count() > i + 2) - { - // Check for a potential range. - // Only do it if we have 3 or more pointers in a row - ULONG rangeOffset = offset; - int j = i + 1; - do { - ULONG nextOffset = gcOffsets[j]; - // interior pointers can't be in ranges - if (nextOffset & 1) - break; - // ranges must be saturated - if (nextOffset != (rangeOffset + sizeof(void*))) - break; - j++; - rangeOffset = nextOffset; - } while(j < gcOffsets.Count()); - - if (j > (i + 2)) - { - EncodeOneGCOffset(pSl, delta, FALSE, TRUE, last); - i = j - 1; - _ASSERTE(rangeOffset >= (offset + (sizeof(void*) * 2))); - delta = rangeOffset - (offset + (sizeof(void*) * 2)); - offset = rangeOffset; - } - } - last = (++i == gcOffsets.Count()); - - - EncodeOneGCOffset(pSl, delta, maybeInterior, FALSE, last); - - prevOffset = offset; - } while (!last); -} - -static void AppendGCLayout(ULONGARRAY &gcLayout, size_t baseOffset, BOOL fIsTypedRef, TypeHandle VMClsHnd) -{ - STANDARD_VM_CONTRACT; - - _ASSERTE((baseOffset % 16) == 0); - _ASSERTE(FitsInU4(baseOffset)); - - if (fIsTypedRef) - { - *gcLayout.AppendThrowing() = (ULONG)(baseOffset | 1); // "| 1" to mark it as an interior pointer - } - else if (!VMClsHnd.IsNativeValueType()) - { - MethodTable* pMT = VMClsHnd.GetMethodTable(); - _ASSERTE(pMT); - _ASSERTE(pMT->IsValueType()); - - BOOL isByRefLike = pMT->IsByRefLike(); - if (isByRefLike) - { - FindByRefPointerOffsetsInByRefLikeObject( - pMT, - 0 /* baseOffset */, - [&](size_t pointerOffset) - { - // 'gcLayout' requires stack offsets relative to the top of the stack to be recorded, such that subtracting - // the offset from the stack top yields the address of the field, given that subtracting 'baseOffset' from - // the stack top yields the address of the first field in this struct. See TailCallFrame::GcScanRoots() for - // how these offsets are used to calculate stack addresses for fields. - _ASSERTE(pointerOffset < baseOffset); - size_t stackOffsetFromTop = baseOffset - pointerOffset; - _ASSERTE(FitsInU4(stackOffsetFromTop)); - - // Offsets in 'gcLayout' are expected to be in increasing order - int gcLayoutInsertIndex = gcLayout.Count(); - _ASSERTE(gcLayoutInsertIndex >= 0); - for (; gcLayoutInsertIndex != 0; --gcLayoutInsertIndex) - { - ULONG prevStackOffsetFromTop = gcLayout[gcLayoutInsertIndex - 1] & ~(ULONG)1; - if (stackOffsetFromTop > prevStackOffsetFromTop) - { - break; - } - if (stackOffsetFromTop == prevStackOffsetFromTop) - { - return; - } - } - - _ASSERTE(gcLayout.Count() == 0 || stackOffsetFromTop > (gcLayout[gcLayout.Count() - 1] & ~(ULONG)1)); - *gcLayout.InsertThrowing(gcLayoutInsertIndex) = (ULONG)(stackOffsetFromTop | 1); // "| 1" to mark it as an interior pointer - }); - } - - // walk the GC descriptors, reporting the correct offsets - if (pMT->ContainsPointers()) - { - // size of instance when unboxed must be adjusted for the syncblock - // index and the VTable pointer. - DWORD size = pMT->GetBaseSize(); - - // we don't include this term in our 'ppstop' calculation below. - _ASSERTE(pMT->GetComponentSize() == 0); - - CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT); - CGCDescSeries* cur = map->GetLowestSeries(); - CGCDescSeries* last = map->GetHighestSeries(); - - _ASSERTE(cur <= last); - do - { - // offset to embedded references in this series must be - // adjusted by the VTable pointer, when in the unboxed state. - size_t adjustOffset = cur->GetSeriesOffset() - sizeof(void *); - - _ASSERTE(baseOffset >= adjustOffset); - size_t start = baseOffset - adjustOffset; - size_t stop = start - (cur->GetSeriesSize() + size); - for (size_t off = stop + sizeof(void*); off <= start; off += sizeof(void*)) - { - _ASSERTE(FitsInU4(off)); - - int gcLayoutInsertIndex = gcLayout.Count(); - _ASSERTE(gcLayoutInsertIndex >= 0); - if (isByRefLike) - { - // Offsets in 'gcLayout' are expected to be in increasing order and for by-ref-like types the by-refs would - // have already been inserted into 'gcLayout' above. Find the appropriate index at which to insert this - // offset. - while (gcLayoutInsertIndex != 0 && off < gcLayout[gcLayoutInsertIndex - 1]) - { - --gcLayoutInsertIndex; - _ASSERTE(off != (gcLayout[gcLayoutInsertIndex] & ~(ULONG)1)); - } - } - - _ASSERTE(gcLayoutInsertIndex == 0 || off > (gcLayout[gcLayoutInsertIndex - 1] & ~(ULONG)1)); - *gcLayout.InsertThrowing(gcLayoutInsertIndex) = (ULONG)off; - } - cur++; - - } while (cur <= last); - } - } -} - -Stub * StubLinkerCPU::CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig, - MethodDesc* pMD, - CorInfoHelperTailCallSpecialHandling flags) -{ - STANDARD_VM_CONTRACT; - - CPUSTUBLINKER sl; - CPUSTUBLINKER* pSl = &sl; - - // Generates a function that looks like this: - // size_t CopyArguments(va_list args, (RCX) - // CONTEXT *pCtx, (RDX) - // DWORD64 *pvStack, (R8) - // size_t cbStack) (R9) - // { - // if (pCtx != NULL) { - // foreach (arg in args) { - // copy into pCtx or pvStack - // } - // } - // return ; - // } - // - - CodeLabel *pNullLabel = pSl->NewCodeLabel(); - - // test rdx, rdx - pSl->X86EmitR2ROp(0x85, kRDX, kRDX); - - // jz NullLabel - pSl->X86EmitCondJump(pNullLabel, X86CondCode::kJZ); - - UINT nArgSlot = 0; - UINT totalArgs = pSig->totalILArgs() + ((pSig->isVarArg() || pSig->hasTypeArg()) ? 1 : 0); - bool fR10Loaded = false; - UINT cbArg; - static const UINT rgcbArgRegCtxtOffsets[4] = { offsetof(CONTEXT, Rcx), offsetof(CONTEXT, Rdx), - offsetof(CONTEXT, R8), offsetof(CONTEXT, R9) }; - static const UINT rgcbFpArgRegCtxtOffsets[4] = { offsetof(CONTEXT, Xmm0.Low), offsetof(CONTEXT, Xmm1.Low), - offsetof(CONTEXT, Xmm2.Low), offsetof(CONTEXT, Xmm3.Low) }; - - ULONGARRAY gcLayout; - - // On input to the function R9 contains the size of the buffer - // The first time this macro runs, R10 is loaded with the 'top' of the Frame - // and R9 is changed to point to the 'top' of the copy buffer. - // Then both R9 and R10 are decremented by the size of the struct we're copying - // So R10 is the value to put in the argument slot, and R9 is where the data - // should be copied to (or zeroed out in the case of the return buffer). -#define LOAD_STRUCT_OFFSET_IF_NEEDED(cbSize) \ - { \ - _ASSERTE(cbSize > 0); \ - _ASSERTE(FitsInI4(cbSize)); \ - __int32 offset = (__int32)cbSize; \ - if (!fR10Loaded) { \ - /* mov r10, [rdx + offset of RSP] */ \ - pSl->X86EmitIndexRegLoad(kR10, kRDX, offsetof(CONTEXT, Rsp)); \ - /* add an extra 8 because RSP is pointing at the return address */ \ - offset -= 8; \ - /* add r10, r9 */ \ - pSl->X86EmitAddRegReg(kR10, kR9); \ - /* add r9, r8 */ \ - pSl->X86EmitAddRegReg(kR9, kR8); \ - fR10Loaded = true; \ - } \ - /* sub r10, offset */ \ - pSl->X86EmitSubReg(kR10, offset); \ - /* sub r9, cbSize */ \ - pSl->X86EmitSubReg(kR9, cbSize); \ - } - - - if (flags & CORINFO_TAILCALL_STUB_DISPATCH_ARG) { - // This is set for stub dispatch - // The JIT placed an extra argument in the list that needs to - // get shoved into R11, and not counted. - // pCtx->R11 = va_arg(args, DWORD64); - - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - // mov [rdx + offset of R11], rax - pSl->X86EmitIndexRegStore(kRDX, offsetof(CONTEXT, R11), kRAX); - } - - ULONG cbStructOffset = 0; - - // First comes the 'this' pointer - if (pSig->hasThis()) { - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - // mov [rdx + offset of RCX/RDX], rax - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot++], kRAX); - } - - // Next the return buffer - cbArg = 0; - TypeHandle th(pSig->retTypeClass); - if ((pSig->retType == CORINFO_TYPE_REFANY) || (pSig->retType == CORINFO_TYPE_VALUECLASS)) { - cbArg = th.GetSize(); - } - - if (ArgIterator::IsArgPassedByRef(cbArg)) { - totalArgs++; - - // We always reserve space for the return buffer, and we always zero it out, - // so the GC won't complain, but if it's already pointing above the frame, - // then we need to pass it in (so it will get passed out). - // Otherwise we assume the caller is returning void, so we just pass in - // dummy space to be overwritten. - UINT cbUsed = (cbArg + 0xF) & ~0xF; - LOAD_STRUCT_OFFSET_IF_NEEDED(cbUsed); - // now emit a 'memset(r9, 0, cbUsed)' - { - // xorps xmm0, xmm0 - pSl->X86EmitR2ROp(X86_INSTR_XORPS, kXMM0, kXMM0); - if (cbUsed <= 4 * 16) { - // movaps [r9], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 0); - if (16 < cbUsed) { - // movaps [r9 + 16], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 16); - if (32 < cbUsed) { - // movaps [r9 + 32], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 32); - if (48 < cbUsed) { - // movaps [r9 + 48], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 48); - } - } - } - } - else { - // a loop (one double-quadword at a time) - pSl->X86EmitZeroOutReg(kR11); - // LoopLabel: - CodeLabel *pLoopLabel = pSl->NewCodeLabel(); - pSl->EmitLabel(pLoopLabel); - // movaps [r9 + r11], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 0, kR11, 1); - // add r11, 16 - pSl->X86EmitAddReg(kR11, 16); - // cmp r11, cbUsed - pSl->X86EmitCmpRegImm32(kR11, cbUsed); - // jl LoopLabel - pSl->X86EmitCondJump(pLoopLabel, X86CondCode::kJL); - } - } - cbStructOffset += cbUsed; - AppendGCLayout(gcLayout, cbStructOffset, pSig->retType == CORINFO_TYPE_REFANY, th); - - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - // cmp rax, [rdx + offset of R12] - pSl->X86EmitOffsetModRM(0x3B, kRAX, kRDX, offsetof(CONTEXT, R12)); - - CodeLabel *pSkipLabel = pSl->NewCodeLabel(); - // jnb SkipLabel - pSl->X86EmitCondJump(pSkipLabel, X86CondCode::kJNB); - - // Also check the lower bound of the stack in case the return buffer is on the GC heap - // and the GC heap is below the stack - // cmp rax, rsp - pSl->X86EmitR2ROp(0x3B, kRAX, (X86Reg)4 /*kRSP*/); - // jna SkipLabel - pSl->X86EmitCondJump(pSkipLabel, X86CondCode::kJB); - // mov rax, r10 - pSl->X86EmitMovRegReg(kRAX, kR10); - // SkipLabel: - pSl->EmitLabel(pSkipLabel); - // mov [rdx + offset of RCX], rax - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot++], kRAX); - } - - // VarArgs Cookie *or* Generics Instantiation Parameter - if (pSig->hasTypeArg() || pSig->isVarArg()) { - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - // mov [rdx + offset of RCX/RDX], rax - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot++], kRAX); - } - - _ASSERTE(nArgSlot <= 4); - - // Now for *all* the 'real' arguments - SigPointer ptr((PCCOR_SIGNATURE)pSig->args); - Module * module = GetModule(pSig->scope); - Instantiation classInst((TypeHandle*)pSig->sigInst.classInst, pSig->sigInst.classInstCount); - Instantiation methodInst((TypeHandle*)pSig->sigInst.methInst, pSig->sigInst.methInstCount); - SigTypeContext typeCtxt(classInst, methodInst); - - for( ;nArgSlot < totalArgs; ptr.SkipExactlyOne()) { - CorElementType et = ptr.PeekElemTypeNormalized(module, &typeCtxt); - if (et == ELEMENT_TYPE_SENTINEL) - continue; - - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - switch (et) { - case ELEMENT_TYPE_INTERNAL: - // TODO - _ASSERTE(!"Shouldn't see ELEMENT_TYPE_INTERNAL"); - break; - case ELEMENT_TYPE_TYPEDBYREF: - case ELEMENT_TYPE_VALUETYPE: - th = ptr.GetTypeHandleThrowing(module, &typeCtxt, ClassLoader::LoadTypes, CLASS_LOAD_UNRESTOREDTYPEKEY); - _ASSERTE(!th.IsNull()); - g_IBCLogger.LogEEClassAndMethodTableAccess(th.GetMethodTable()); - cbArg = (UINT)th.GetSize(); - if (ArgIterator::IsArgPassedByRef(cbArg)) { - UINT cbUsed = (cbArg + 0xF) & ~0xF; - LOAD_STRUCT_OFFSET_IF_NEEDED(cbUsed); - // rax has the source pointer - // r9 has the intermediate copy location - // r10 has the final destination - if (nArgSlot < 4) { - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot++], kR10); - } - else { - pSl->X86EmitIndexRegStore(kR8, 8 * nArgSlot++, kR10); - } - // now emit a 'memcpy(rax, r9, cbUsed)' - // These structs are supposed to be 16-byte aligned, but - // Reflection puts them on the GC heap, which is only 8-byte - // aligned. It also means we have to be careful about not - // copying too much (because we might cross a page boundary) - UINT cbUsed16 = (cbArg + 7) & ~0xF; - _ASSERTE((cbUsed16 == cbUsed) || ((cbUsed16 + 16) == cbUsed)); - - if (cbArg <= 192) { - // Unrolled version (6 x 16 bytes in parallel) - UINT offset = 0; - while (offset < cbUsed16) { - // movups xmm0, [rax + offset] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM0, kRAX, offset); - if (offset + 16 < cbUsed16) { - // movups xmm1, [rax + offset + 16] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM1, kRAX, offset + 16); - if (offset + 32 < cbUsed16) { - // movups xmm2, [rax + offset + 32] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM2, kRAX, offset + 32); - if (offset + 48 < cbUsed16) { - // movups xmm3, [rax + offset + 48] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM3, kRAX, offset + 48); - if (offset + 64 < cbUsed16) { - // movups xmm4, [rax + offset + 64] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM4, kRAX, offset + 64); - if (offset + 80 < cbUsed16) { - // movups xmm5, [rax + offset + 80] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM5, kRAX, offset + 80); - } - } - } - } - } - // movaps [r9 + offset], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 16], xmm1 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM1, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 32], xmm2 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM2, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 48], xmm3 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM3, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 64], xmm4 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM4, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 80], xmm5 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM5, kR9, offset); - offset += 16; - } - } - } - } - } - } - // Copy the last 8 bytes if needed - if (cbUsed > cbUsed16) { - _ASSERTE(cbUsed16 < cbArg); - // movlps xmm0, [rax + offset] - pSl->X86EmitOp(X86_INSTR_MOVLPS_R_RM, kXMM0, kRAX, offset); - // movlps [r9 + offset], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVLPS_RM_R, kXMM0, kR9, offset); - } - } - else { - // a loop (one double-quadword at a time) - pSl->X86EmitZeroOutReg(kR11); - // LoopLabel: - CodeLabel *pLoopLabel = pSl->NewCodeLabel(); - pSl->EmitLabel(pLoopLabel); - // movups xmm0, [rax + r11] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM0, kRAX, 0, kR11, 1); - // movaps [r9 + r11], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 0, kR11, 1); - // add r11, 16 - pSl->X86EmitAddReg(kR11, 16); - // cmp r11, cbUsed16 - pSl->X86EmitCmpRegImm32(kR11, cbUsed16); - // jl LoopLabel - pSl->X86EmitCondJump(pLoopLabel, X86CondCode::kJL); - if (cbArg > cbUsed16) { - _ASSERTE(cbUsed16 + 8 >= cbArg); - // movlps xmm0, [rax + r11] - pSl->X86EmitOp(X86_INSTR_MOVLPS_R_RM, kXMM0, kRAX, 0, kR11, 1); - // movlps [r9 + r11], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVLPS_RM_R, kXMM0, kR9, 0, kR11, 1); - } - } - cbStructOffset += cbUsed; - AppendGCLayout(gcLayout, cbStructOffset, et == ELEMENT_TYPE_TYPEDBYREF, th); - break; - } - - // - // Explicit Fall-Through for non-IsArgPassedByRef - // - - default: - if (nArgSlot < 4) { - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot], kRAX); - if ((et == ELEMENT_TYPE_R4) || (et == ELEMENT_TYPE_R8)) { - pSl->X86EmitIndexRegStore(kRDX, rgcbFpArgRegCtxtOffsets[nArgSlot], kRAX); - } - } - else { - pSl->X86EmitIndexRegStore(kR8, 8 * nArgSlot, kRAX); - } - nArgSlot++; - break; - } - } - -#undef LOAD_STRUCT_OFFSET_IF_NEEDED - - // Keep our 4 shadow slots and even number of slots (to keep 16-byte aligned) - if (nArgSlot < 4) - nArgSlot = 4; - else if (nArgSlot & 1) - nArgSlot++; - - _ASSERTE((cbStructOffset % 16) == 0); - - // xor eax, eax - pSl->X86EmitZeroOutReg(kRAX); - // ret - pSl->X86EmitReturn(0); - - // NullLabel: - pSl->EmitLabel(pNullLabel); - - CodeLabel *pGCLayoutLabel = NULL; - if (gcLayout.Count() == 0) { - // xor eax, eax - pSl->X86EmitZeroOutReg(kRAX); - } - else { - // lea rax, [rip + offset to gclayout] - pGCLayoutLabel = pSl->NewCodeLabel(); - pSl->X86EmitLeaRIP(pGCLayoutLabel, kRAX); - } - // mov [r9], rax - pSl->X86EmitIndexRegStore(kR9, 0, kRAX); - // mov rax, cbStackNeeded - pSl->X86EmitRegLoad(kRAX, cbStructOffset + nArgSlot * 8); - // ret - pSl->X86EmitReturn(0); - - if (gcLayout.Count() > 0) { - // GCLayout: - pSl->EmitLabel(pGCLayoutLabel); - EncodeGCOffsets(pSl, gcLayout); - } - - LoaderHeap* pHeap = pMD->GetLoaderAllocator()->GetStubHeap(); - return pSl->Link(pHeap); -} -#endif // DACCESS_COMPILE - -#endif // TARGET_AMD64 - - #ifdef HAS_FIXUP_PRECODE #ifdef HAS_FIXUP_PRECODE_CHUNKS diff --git a/src/coreclr/src/vm/i386/stublinkerx86.h b/src/coreclr/src/vm/i386/stublinkerx86.h index 32417ba4171096..23ab0c40ca5716 100644 --- a/src/coreclr/src/vm/i386/stublinkerx86.h +++ b/src/coreclr/src/vm/i386/stublinkerx86.h @@ -443,14 +443,6 @@ class StubLinkerCPU : public StubLinker virtual VOID EmitUnwindInfoCheckSubfunction(); #endif -#ifdef TARGET_AMD64 - - static Stub * CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig, - MethodDesc* pMD, - CorInfoHelperTailCallSpecialHandling flags); - -#endif // TARGET_AMD64 - private: VOID X86EmitSubEspWorker(INT32 imm32); diff --git a/src/coreclr/src/vm/jithelpers.cpp b/src/coreclr/src/vm/jithelpers.cpp index 87bf9680e40f66..8e5d20d993ff6a 100644 --- a/src/coreclr/src/vm/jithelpers.cpp +++ b/src/coreclr/src/vm/jithelpers.cpp @@ -5534,265 +5534,6 @@ void InitJITHelpers2() g_pJitGenericHandleCache = tempGenericHandleCache.Extract(); } -#if defined(TARGET_AMD64) || defined(TARGET_ARM) - -NOINLINE void DoCopy(CONTEXT * ctx, void * pvTempStack, size_t cbTempStack, Thread * pThread, Frame * pNewFrame) -{ - // We need to ensure that copying pvTempStack onto our stack will not in - // *ANY* way trash the context record (or our pointer to it) that we need - // in order to restore context - _ASSERTE((DWORD_PTR)&ctx + sizeof(ctx) < (DWORD_PTR)GetSP(ctx)); - - CONTEXT ctx2; - if ((DWORD_PTR)ctx + sizeof(*ctx) > (DWORD_PTR)GetSP(ctx)) - { - // The context record is in danger, copy it down - _ASSERTE((DWORD_PTR)&ctx2 + sizeof(ctx2) < (DWORD_PTR)GetSP(ctx)); - ctx2 = *ctx; - - // Clear any context that we didn't copy... - ctx2.ContextFlags &= CONTEXT_ALL; - ctx = &ctx2; - } - - _ASSERTE((DWORD_PTR)ctx + sizeof(*ctx) <= (DWORD_PTR)GetSP(ctx)); - - // DevDiv 189140 - use memmove because source and dest might overlap. - memmove((void*)GetSP(ctx), pvTempStack, cbTempStack); - - if (pNewFrame != NULL) - { - // Now that the memmove above is complete, pNewFrame is actually pointing at a - // TailCallFrame, and not garbage. So it's safe to add pNewFrame to the Frame - // chain. - _ASSERTE(pThread != NULL); - pThread->SetFrame(pNewFrame); - } - - RtlRestoreContext(ctx, NULL); -} - -// -// Mostly Architecture-agnostic RtlVirtualUnwind-based tail call helper... -// -// Can't use HCIMPL macro because it requires unwind, and this method *NEVER* unwinds. -// - -#define INVOKE_COPY_ARGS_HELPER(helperFunc, arg1, arg2, arg3, arg4) ((pfnCopyArgs)helperFunc)(arg1, arg2, arg3, arg4) -void F_CALL_VA_CONV JIT_TailCall(PCODE copyArgs, PCODE target, ...) -{ - // Can't have a regular contract because we would never pop it - // We only throw a stack overflow if needed, and we can't handle - // a GC because the incoming parameters are totally unprotected. - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_COOPERATIVE - -#ifndef TARGET_UNIX - - Thread *pThread = GetThread(); - -#ifdef FEATURE_HIJACK - // We can't crawl the stack of a thread that currently has a hijack pending - // (since the hijack routine won't be recognized by any code manager). So we - // undo any hijack, the EE will re-attempt it later. - pThread->UnhijackThread(); -#endif - - ULONG_PTR establisherFrame = 0; - PVOID handlerData = NULL; - CONTEXT ctx; - - // Unwind back to our caller in managed code - static PT_RUNTIME_FUNCTION my_pdata; - static ULONG_PTR my_imagebase; - - ctx.ContextFlags = CONTEXT_ALL; - RtlCaptureContext(&ctx); - - if (!VolatileLoadWithoutBarrier(&my_imagebase)) { - ULONG_PTR imagebase = 0; - my_pdata = RtlLookupFunctionEntry(GetIP(&ctx), &imagebase, NULL); - InterlockedExchangeT(&my_imagebase, imagebase); - } - - RtlVirtualUnwind(UNW_FLAG_NHANDLER, my_imagebase, GetIP(&ctx), my_pdata, &ctx, &handlerData, - &establisherFrame, NULL); - - EECodeInfo codeInfo(GetIP(&ctx)); - - // Now unwind back to our caller's caller - establisherFrame = 0; - RtlVirtualUnwind(UNW_FLAG_NHANDLER, codeInfo.GetModuleBase(), GetIP(&ctx), codeInfo.GetFunctionEntry(), &ctx, &handlerData, - &establisherFrame, NULL); - - va_list args; - - // Compute the space needed for arguments - va_start(args, target); - - ULONG_PTR pGCLayout = 0; - size_t cbArgArea = INVOKE_COPY_ARGS_HELPER(copyArgs, args, NULL, NULL, (size_t)&pGCLayout); - - va_end(args); - - // reset (in case the helper walked them) - va_start(args, target); - - // Fake call frame (if needed) - size_t cbCopyFrame = 0; - bool fCopyDown = false; - BYTE rgFrameBuffer[sizeof(FrameWithCookie)]; - Frame * pNewFrame = NULL; - -#if defined(TARGET_AMD64) -# define STACK_ADJUST_FOR_RETURN_ADDRESS (sizeof(void*)) -# define STACK_ALIGN_MASK (0xF) -#elif defined(TARGET_ARM) -# define STACK_ADJUST_FOR_RETURN_ADDRESS (0) -# define STACK_ALIGN_MASK (0x7) -#else -#error "Unknown tail call architecture" -#endif - - // figure out if we can re-use an existing TailCallHelperStub - // or if we need to create a new one. - if ((void*)GetIP(&ctx) == JIT_TailCallHelperStub_ReturnAddress) { - TailCallFrame * pCurrentFrame = TailCallFrame::GetFrameFromContext(&ctx); - _ASSERTE(pThread->GetFrame() == pCurrentFrame); - // The caller was tail called, so we can re-use that frame - // See if we need to enlarge the ArgArea - // This can potentially enlarge cbArgArea to the size of the - // existing TailCallFrame. - const size_t endOfFrame = (size_t)pCurrentFrame - (size_t)sizeof(GSCookie); - size_t cbOldArgArea = (endOfFrame - GetSP(&ctx)); - if (cbOldArgArea >= cbArgArea) { - cbArgArea = cbOldArgArea; - } - else { - SetSP(&ctx, (endOfFrame - cbArgArea)); - fCopyDown = true; - } - - // Reset the GCLayout - pCurrentFrame->SetGCLayout((TADDR)pGCLayout); - - // We're jumping to the new method, not calling it - // so make room for the return address that the 'call' - // would have pushed. - SetSP(&ctx, GetSP(&ctx) - STACK_ADJUST_FOR_RETURN_ADDRESS); - } - else { - // Create a fake fixed frame as if the new method was called by - // TailCallHelperStub asm stub and did an - // alloca, then called the target method. - cbCopyFrame = sizeof(rgFrameBuffer); - FrameWithCookie * CookieFrame = new (rgFrameBuffer) FrameWithCookie(&ctx, pThread); - TailCallFrame * tailCallFrame = &*CookieFrame; - - tailCallFrame->SetGCLayout((TADDR)pGCLayout); - pNewFrame = TailCallFrame::AdjustContextForTailCallHelperStub(&ctx, cbArgArea, pThread); - fCopyDown = true; - - // Eventually, we'll add pNewFrame to our frame chain, but don't do it yet. It's - // pointing to the place on the stack where the TailCallFrame contents WILL be, - // but aren't there yet. In order to keep the stack walkable by profilers, wait - // until the contents are moved over properly (inside DoCopy), and then add - // pNewFrame onto the frame chain. - } - - // The stack should be properly aligned, modulo the pushed return - // address (at least on x64) - _ASSERTE((GetSP(&ctx) & STACK_ALIGN_MASK) == STACK_ADJUST_FOR_RETURN_ADDRESS); - - // Set the target pointer so we land there when we restore the context - SetIP(&ctx, (PCODE)target); - - // Begin creating the new stack frame and copying arguments - size_t cbTempStack = cbCopyFrame + cbArgArea + STACK_ADJUST_FOR_RETURN_ADDRESS; - - // If we're going to have to overwrite some of our incoming argument slots - // then do a double-copy, first to temporary copy below us on the stack and - // then back up to the real stack. - void * pvTempStack; - if (!fCopyDown && (((ULONG_PTR)args + cbArgArea) < GetSP(&ctx))) { - - // - // After this our stack may no longer be walkable by the debugger!!! - // - - pvTempStack = (void*)GetSP(&ctx); - } - else { - fCopyDown = true; - - // Need to align properly for a return address (if it goes on the stack) - // - // AMD64 ONLY: - // _alloca produces 16-byte aligned buffers, but the return address, - // where our buffer 'starts' is off by 8, so make sure our buffer is - // off by 8. - // - pvTempStack = (BYTE*)_alloca(cbTempStack + STACK_ADJUST_FOR_RETURN_ADDRESS) + STACK_ADJUST_FOR_RETURN_ADDRESS; - } - - _ASSERTE(((size_t)pvTempStack & STACK_ALIGN_MASK) == STACK_ADJUST_FOR_RETURN_ADDRESS); - - // Start creating the new stack (bottom up) - BYTE * pbTempStackFill = (BYTE*)pvTempStack; - // Return address - if (STACK_ADJUST_FOR_RETURN_ADDRESS > 0) { - *((PVOID*)pbTempStackFill) = (PVOID)JIT_TailCallHelperStub_ReturnAddress; // return address - pbTempStackFill += STACK_ADJUST_FOR_RETURN_ADDRESS; - } - - // arguments - INVOKE_COPY_ARGS_HELPER(copyArgs, args, &ctx, (DWORD_PTR*)pbTempStackFill, cbArgArea); - - va_end(args); - - pbTempStackFill += cbArgArea; - - // frame (includes TailCallFrame) - if (cbCopyFrame > 0) { - _ASSERTE(cbCopyFrame == sizeof(rgFrameBuffer)); - memcpy(pbTempStackFill, rgFrameBuffer, cbCopyFrame); - pbTempStackFill += cbCopyFrame; - } - - // If this fires, check the math above, because we copied more than we should have - _ASSERTE((size_t)((pbTempStackFill - (BYTE*)pvTempStack)) == cbTempStack); - - // If this fires, it means we messed up the math and we're about to overwrite - // some of our locals which would be bad because we still need them to call - // RtlRestoreContext and pop the contract... - _ASSERTE(fCopyDown || ((DWORD_PTR)&ctx + sizeof(ctx) < (DWORD_PTR)GetSP(&ctx))); - - if (fCopyDown) { - // We've created a dummy stack below our frame and now we overwrite - // our own real stack. - - // - // After this our stack may no longer be walkable by the debugger!!! - // - - // This does the copy, adds pNewFrame to the frame chain, and calls RtlRestoreContext - DoCopy(&ctx, pvTempStack, cbTempStack, pThread, pNewFrame); - } - - RtlRestoreContext(&ctx, NULL); - -#undef STACK_ADJUST_FOR_RETURN_ADDRESS -#undef STACK_ALIGN_MASK - -#else // !TARGET_UNIX - PORTABILITY_ASSERT("TODO: Implement JIT_TailCall for PAL"); -#endif // !TARGET_UNIX - -} - -#endif // TARGET_AMD64 || TARGET_ARM - //======================================================================== // // JIT HELPERS LOGGING diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp index 1a1cc8b0e3ab48..641a78837855da 100644 --- a/src/coreclr/src/vm/jitinterface.cpp +++ b/src/coreclr/src/vm/jitinterface.cpp @@ -13736,32 +13736,6 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, return TRUE; } -void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - void * ftn = NULL; - -#if (defined(TARGET_AMD64) || defined(TARGET_ARM)) && !defined(TARGET_UNIX) - - JIT_TO_EE_TRANSITION(); - - Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, m_pMethodBeingCompiled, flags); - - ftn = (void*)pStub->GetEntryPoint(); - - EE_TO_JIT_TRANSITION(); - -#endif // (TARGET_AMD64 || TARGET_ARM) && !TARGET_UNIX - - return ftn; -} - bool CEEInfo::getTailCallHelpersInternal(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, diff --git a/src/coreclr/src/vm/jitinterface.h b/src/coreclr/src/vm/jitinterface.h index ed7e3af1ea24c4..faf4300a5c66ce 100644 --- a/src/coreclr/src/vm/jitinterface.h +++ b/src/coreclr/src/vm/jitinterface.h @@ -924,9 +924,6 @@ class CEEInfo : public ICorJitInfo void* getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ void ** ppIndirection); /* OUT */ - void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags); - bool getTailCallHelpersInternal( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, @@ -1614,22 +1611,6 @@ GARY_DECL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT); #define SetJitHelperFunction(ftnNum, pFunc) _SetJitHelperFunction(DYNAMIC_##ftnNum, (void*)(pFunc)) void _SetJitHelperFunction(DynamicCorInfoHelpFunc ftnNum, void * pFunc); -// Helper for RtlVirtualUnwind-based tail calls -#if defined(TARGET_AMD64) || defined(TARGET_ARM) - -// The Stub-linker generated assembly routine to copy arguments from the va_list -// into the CONTEXT and the stack. -// -typedef size_t (*pfnCopyArgs)(va_list, _CONTEXT *, DWORD_PTR *, size_t); - -// Forward declaration from Frames.h -class TailCallFrame; - -// The shared stub return location -EXTERN_C void JIT_TailCallHelperStub_ReturnAddress(); - -#endif // TARGET_AMD64 || TARGET_ARM - void *GenFastGetSharedStaticBase(bool bCheckCCtor); #ifdef HAVE_GCCOVER diff --git a/src/coreclr/src/vm/stubmgr.cpp b/src/coreclr/src/vm/stubmgr.cpp index 8ec6c85456483c..2ff9311167a9d8 100644 --- a/src/coreclr/src/vm/stubmgr.cpp +++ b/src/coreclr/src/vm/stubmgr.cpp @@ -2349,6 +2349,8 @@ BOOL DelegateInvokeStubManager::TraceDelegateObject(BYTE* pbDel, TraceDestinatio #endif // DACCESS_COMPILE +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) + #if !defined(DACCESS_COMPILE) // static @@ -2389,10 +2391,8 @@ BOOL TailCallStubManager::CheckIsStub_Internal(PCODE stubStartAddress) #if !defined(DACCESS_COMPILE) -#if defined(TARGET_X86) EXTERN_C void STDCALL JIT_TailCallLeave(); EXTERN_C void STDCALL JIT_TailCallVSDLeave(); -#endif // TARGET_X86 BOOL TailCallStubManager::TraceManager(Thread * pThread, TraceDestination * pTrace, @@ -2400,7 +2400,6 @@ BOOL TailCallStubManager::TraceManager(Thread * pThread, BYTE ** ppRetAddr) { WRAPPER_NO_CONTRACT; -#if defined(TARGET_X86) TADDR esp = GetSP(pContext); TADDR ebp = GetFP(pContext); @@ -2449,27 +2448,6 @@ BOOL TailCallStubManager::TraceManager(Thread * pThread, pTrace->InitForStub((PCODE)*reinterpret_cast(esp)); return TRUE; } - -#elif defined(TARGET_AMD64) || defined(TARGET_ARM) - - _ASSERTE(GetIP(pContext) == GetEEFuncEntryPoint(JIT_TailCall)); - - // The target address is the second argument -#ifdef TARGET_AMD64 - PCODE target = (PCODE)pContext->Rdx; -#else - PCODE target = (PCODE)pContext->R1; -#endif - *ppRetAddr = reinterpret_cast(target); - pTrace->InitForStub(target); - return TRUE; - -#else // !TARGET_X86 && !TARGET_AMD64 && !TARGET_ARM - - _ASSERTE(!"TCSM::TM - TailCallStubManager should not be necessary on this platform"); - return FALSE; - -#endif // TARGET_X86 || TARGET_AMD64 } #endif // !DACCESS_COMPILE @@ -2491,6 +2469,8 @@ BOOL TailCallStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestination * return fResult; } +#endif // TARGET_X86 && !UNIX_X86_ABI + #ifdef DACCESS_COMPILE @@ -2582,6 +2562,7 @@ VirtualCallStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) GetCacheEntryRangeList()->EnumMemoryRegions(flags); } +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) void TailCallStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) { SUPPORTS_DAC; @@ -2589,6 +2570,7 @@ void TailCallStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) DAC_ENUM_VTHIS(); EMEM_OUT(("MEM: %p TailCallStubManager\n", dac_cast(this))); } +#endif #endif // #ifdef DACCESS_COMPILE diff --git a/src/coreclr/src/vm/stubmgr.h b/src/coreclr/src/vm/stubmgr.h index 5e1fe2291e6f89..409bb88cc2b3a0 100644 --- a/src/coreclr/src/vm/stubmgr.h +++ b/src/coreclr/src/vm/stubmgr.h @@ -838,6 +838,7 @@ class DelegateInvokeStubManager : public StubManager #endif }; +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) //--------------------------------------------------------------------------------------- // // This is the stub manager to help the managed debugger step into a tail call. @@ -878,6 +879,20 @@ class TailCallStubManager : public StubManager virtual LPCWSTR GetStubManagerName(PCODE addr) {LIMITED_METHOD_CONTRACT; return W("TailCallStub");} #endif // !DACCESS_COMPILE }; +#else // TARGET_X86 && UNIX_X86_ABI +class TailCallStubManager +{ +public: + static void Init() + { + } + + static bool IsTailCallJitHelper(PCODE code) + { + return false; + } +}; +#endif // TARGET_X86 && UNIX_X86_ABI // // Helpers for common value locations in stubs to make stub managers more portable diff --git a/src/coreclr/src/zap/zapinfo.cpp b/src/coreclr/src/zap/zapinfo.cpp index 48d17e84121248..d16f4a1d5ca0ee 100644 --- a/src/coreclr/src/zap/zapinfo.cpp +++ b/src/coreclr/src/zap/zapinfo.cpp @@ -1717,16 +1717,6 @@ void ZapInfo::embedGenericSignature(CORINFO_LOOKUP * pLookup) } } -void* ZapInfo::getTailCallCopyArgsThunk ( - CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags) -{ - void * pStub = m_pEEJitInfo->getTailCallCopyArgsThunk(pSig, flags); - if (pStub == NULL) - return NULL; - return m_pImage->GetWrappers()->GetStub(pStub); -} - bool ZapInfo::getTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, diff --git a/src/coreclr/src/zap/zapinfo.h b/src/coreclr/src/zap/zapinfo.h index 3212d1489d8e8c..6079f3291c6ea3 100644 --- a/src/coreclr/src/zap/zapinfo.h +++ b/src/coreclr/src/zap/zapinfo.h @@ -351,10 +351,6 @@ class ZapInfo void * getHelperFtn (CorInfoHelpFunc ftnNum, void** ppIndirection); - void* getTailCallCopyArgsThunk ( - CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags); - virtual bool getTailCallHelpers( CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, From f37b69191cddf27b410348d4fa5ca899b262ca21 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 27 Apr 2020 22:00:52 -0700 Subject: [PATCH 2/2] Fix ARM build break --- src/coreclr/src/vm/arm/stubs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/src/vm/arm/stubs.cpp b/src/coreclr/src/vm/arm/stubs.cpp index ce4cedb7538fd7..caa80afc9831d9 100644 --- a/src/coreclr/src/vm/arm/stubs.cpp +++ b/src/coreclr/src/vm/arm/stubs.cpp @@ -1725,7 +1725,7 @@ VOID StubLinkerCPU::EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, s ThumbEmitProlog(1, 0, FALSE); } - ThumbEmitCallManagedMethod(pSharedMD, true); + ThumbEmitTailCallManagedMethod(pSharedMD); if (isRelative) {