From 3ebe805fdf3c3a86e280c4a56437ae776be0e199 Mon Sep 17 00:00:00 2001 From: Steven He Date: Sat, 5 Oct 2024 13:47:31 +0900 Subject: [PATCH] Prototype a simple inter-procedural escape analysis --- src/coreclr/inc/corinfo.h | 4 ++ src/coreclr/inc/icorjitinfoimpl_generated.h | 8 +++ src/coreclr/inc/jiteeversionguid.h | 10 ++-- src/coreclr/jit/ICorJitInfo_names_generated.h | 2 + .../jit/ICorJitInfo_wrapper_generated.hpp | 19 ++++++ src/coreclr/jit/compiler.cpp | 2 +- src/coreclr/jit/objectalloc.cpp | 33 ++++++++--- .../tools/Common/JitInterface/CorInfoImpl.cs | 9 +++ .../JitInterface/CorInfoImpl_generated.cs | 33 ++++++++++- .../ThunkGenerator/ThunkInput.txt | 2 + .../aot/jitinterface/jitinterface_generated.h | 21 +++++++ .../tools/superpmi/superpmi-shared/agnostic.h | 6 ++ .../tools/superpmi/superpmi-shared/lwmlist.h | 1 + .../superpmi-shared/methodcontext.cpp | 59 +++++++++++++++++++ .../superpmi/superpmi-shared/methodcontext.h | 9 +++ .../superpmi-shim-collector/icorjitinfo.cpp | 15 +++++ .../icorjitinfo_generated.cpp | 16 +++++ .../icorjitinfo_generated.cpp | 14 +++++ .../tools/superpmi/superpmi/icorjitinfo.cpp | 13 ++++ src/coreclr/vm/jitinterface.cpp | 36 +++++++++++ src/coreclr/vm/method.hpp | 36 +++++++++++ 21 files changed, 333 insertions(+), 15 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 2eb4669781d14..a35359231a106 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -3307,6 +3307,10 @@ class ICorDynamicInfo : public ICorStaticInfo virtual void updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) = 0; virtual CORINFO_METHOD_HANDLE getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) = 0; + + virtual bool getIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) = 0; + + virtual void setIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) = 0; }; /**********************************************************************************/ diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index fa242d2979339..27bf1a06198a5 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -742,6 +742,14 @@ uint32_t getJitFlags( CORINFO_METHOD_HANDLE getSpecialCopyHelper( CORINFO_CLASS_HANDLE type) override; +bool getIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) override; + +void setIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) override; + /**********************************************************************************/ // clang-format on /**********************************************************************************/ diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 977ba815a18a9..039d1e3dc5164 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 9b8ef809-94d4-41b6-9d4c-dd61379abbe0 */ - 0x9b8ef809, - 0x94d4, - 0x41b6, - {0x9d, 0x4c, 0xdd, 0x61, 0x37, 0x9a, 0xbb, 0xe0} +constexpr GUID JITEEVersionIdentifier = { /* 1512fc24-7751-4eb7-97ad-d8ec80571897 */ + 0x1512fc24, + 0x7751, + 0x4eb7, + {0x97, 0xad, 0xd8, 0xec, 0x80, 0x57, 0x18, 0x97} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 0d21b1b92cf5a..a6bf37008ce49 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -180,5 +180,7 @@ DEF_CLR_API(getRelocTypeHint) DEF_CLR_API(getExpectedTargetArchitecture) DEF_CLR_API(getJitFlags) DEF_CLR_API(getSpecialCopyHelper) +DEF_CLR_API(getIsLocalNonEscapes) +DEF_CLR_API(setIsLocalNonEscapes) #undef DEF_CLR_API diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 9283effbb7428..091e0480ef36a 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1742,6 +1742,25 @@ CORINFO_METHOD_HANDLE WrapICorJitInfo::getSpecialCopyHelper( return temp; } +bool WrapICorJitInfo::getIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) +{ + API_ENTER(getIsLocalNonEscapes); + bool temp = wrapHnd->getIsLocalNonEscapes(method, lclNum); + API_LEAVE(getIsLocalNonEscapes); + return temp; +} + +void WrapICorJitInfo::setIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) +{ + API_ENTER(setIsLocalNonEscapes); + wrapHnd->setIsLocalNonEscapes(method, lclNum); + API_LEAVE(setIsLocalNonEscapes); +} + /**********************************************************************************/ // clang-format on /**********************************************************************************/ diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 3b111c4572b97..f840d71b7563a 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -4660,7 +4660,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // local variable allocation on the stack. ObjectAllocator objectAllocator(this); // PHASE_ALLOCATE_OBJECTS - if (compObjectStackAllocation() && opts.OptimizationEnabled()) + if (compObjectStackAllocation()) { objectAllocator.EnableObjectStackAllocation(); } diff --git a/src/coreclr/jit/objectalloc.cpp b/src/coreclr/jit/objectalloc.cpp index 89e28c5978c6d..1bb6e38dd5f33 100644 --- a/src/coreclr/jit/objectalloc.cpp +++ b/src/coreclr/jit/objectalloc.cpp @@ -30,12 +30,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // PhaseStatus ObjectAllocator::DoPhase() { - if ((comp->optMethodFlags & OMF_HAS_NEWOBJ) == 0) - { - JITDUMP("no newobjs in this method; punting\n"); - return PhaseStatus::MODIFIED_NOTHING; - } - bool enabled = IsObjectStackAllocationEnabled(); const char* disableReason = ": global config"; @@ -63,6 +57,12 @@ PhaseStatus ObjectAllocator::DoPhase() m_IsObjectStackAllocationEnabled = false; } + if ((comp->optMethodFlags & OMF_HAS_NEWOBJ) == 0) + { + JITDUMP("no newobjs in this method; punting\n"); + return PhaseStatus::MODIFIED_NOTHING; + } + const bool didStackAllocate = MorphAllocObjNodes(); if (didStackAllocate) @@ -134,7 +134,6 @@ void ObjectAllocator::AddConnGraphEdge(unsigned int sourceLclNum, unsigned int t void ObjectAllocator::DoAnalysis() { - assert(m_IsObjectStackAllocationEnabled); assert(!m_AnalysisDone); if (comp->lvaCount > 0) @@ -144,6 +143,15 @@ void ObjectAllocator::DoAnalysis() MarkEscapingVarsAndBuildConnGraph(); ComputeEscapingNodes(&m_bitVecTraits, m_EscapingPointers); + + for (unsigned int lclNum = 0; lclNum < comp->lvaCount; ++lclNum) + { + if (!CanLclVarEscape(lclNum)) + { + comp->info.compCompHnd->setIsLocalNonEscapes(comp->info.compMethodHnd, lclNum); + JITDUMP("V%02u does not escape\n", lclNum); + } + } } m_AnalysisDone = true; @@ -719,13 +727,22 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack* parent case GT_CALL: { - GenTreeCall* asCall = parent->AsCall(); + GenTreeCall* asCall = parent->AsCall(); + CallArg* callArg = asCall->gtArgs.FindByNode(tree); if (asCall->IsHelperCall()) { canLclVarEscapeViaParentStack = !Compiler::s_helperCallProperties.IsNoEscape(comp->eeGetHelperNum(asCall->gtCallMethHnd)); } + else if (asCall->gtCallType == gtCallTypes::CT_USER_FUNC && callArg != nullptr) + { + uint32_t argIndex = asCall->gtArgs.GetIndex(callArg); + if (comp->info.compCompHnd->getIsLocalNonEscapes(asCall->gtCallMethHnd, argIndex)) + { + canLclVarEscapeViaParentStack = false; + } + } break; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 5038448f8cafc..7d11afdddf627 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1635,6 +1635,15 @@ private void setPatchpointInfo(PatchpointInfo* patchpointInfo) private PatchpointInfo* getOSRInfo(ref uint ilOffset) { throw new NotImplementedException("getOSRInfo"); } +#pragma warning disable CA1822 // Mark members as static + private bool getIsLocalNonEscapes(CORINFO_METHOD_STRUCT_* method, uint lclNum) + { + return false; + } + + private void setIsLocalNonEscapes(CORINFO_METHOD_STRUCT_* method, uint lclNum) { } +#pragma warning restore CA1822 // Mark members as static + #pragma warning disable CA1822 // Mark members as static private void methodMustBeLoadedBeforeCodeIsRun(CORINFO_METHOD_STRUCT_* method) #pragma warning restore CA1822 // Mark members as static diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 11dad67fc416f..a396ad98d5fb0 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2605,10 +2605,39 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ } } + [UnmanagedCallersOnly] + private static byte _getIsLocalNonEscapes(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, uint lclNum) + { + var _this = GetThis(thisHandle); + try + { + return _this.getIsLocalNonEscapes(method, lclNum) ? (byte)1 : (byte)0; + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + + [UnmanagedCallersOnly] + private static void _setIsLocalNonEscapes(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, uint lclNum) + { + var _this = GetThis(thisHandle); + try + { + _this.setIsLocalNonEscapes(method, lclNum); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 176); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 178); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2786,6 +2815,8 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[173] = (delegate* unmanaged)&_getExpectedTargetArchitecture; callbacks[174] = (delegate* unmanaged)&_getJitFlags; callbacks[175] = (delegate* unmanaged)&_getSpecialCopyHelper; + callbacks[176] = (delegate* unmanaged)&_getIsLocalNonEscapes; + callbacks[177] = (delegate* unmanaged)&_setIsLocalNonEscapes; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index fd3e2961ed1dd..103d5b6793e31 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -339,3 +339,5 @@ FUNCTIONS uint32_t getExpectedTargetArchitecture() uint32_t getJitFlags(CORJIT_FLAGS* flags, uint32_t sizeInBytes) CORINFO_METHOD_HANDLE getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) = 0; + bool getIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum); + void setIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 414beda8c9890..5671a120c666e 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -187,6 +187,8 @@ struct JitInterfaceCallbacks uint32_t (* getExpectedTargetArchitecture)(void * thisHandle, CorInfoExceptionClass** ppException); uint32_t (* getJitFlags)(void * thisHandle, CorInfoExceptionClass** ppException, CORJIT_FLAGS* flags, uint32_t sizeInBytes); CORINFO_METHOD_HANDLE (* getSpecialCopyHelper)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE type); + bool (* getIsLocalNonEscapes)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, uint32_t lclNum); + void (* setIsLocalNonEscapes)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, uint32_t lclNum); }; @@ -1919,4 +1921,23 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; return temp; } + + virtual bool getIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) +{ + CorInfoExceptionClass* pException = nullptr; + bool temp = _callbacks->getIsLocalNonEscapes(_thisHandle, &pException, method, lclNum); + if (pException != nullptr) throw pException; + return temp; +} + + virtual void setIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) +{ + CorInfoExceptionClass* pException = nullptr; + _callbacks->setIsLocalNonEscapes(_thisHandle, &pException, method, lclNum); + if (pException != nullptr) throw pException; +} }; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index a0138db26532b..c6f03c0ecaa3f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -609,6 +609,12 @@ struct Agnostic_ConfigIntInfo DWORD defaultValue; }; +struct Agnostic_LocalNonEscapes +{ + DWORDLONG method; + DWORD lclNum; +}; + // SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR struct Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 7994772771b69..61daf8a5b0ef1 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -131,6 +131,7 @@ LWM(GetFpStructLowering, DWORDLONG, Agnostic_GetFpStructLowering) LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) LWM(UpdateEntryPointForTailCall, Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP) LWM(GetSpecialCopyHelper, DWORDLONG, DWORDLONG) +LWM(GetIsLocalNonEscapes, Agnostic_LocalNonEscapes, DWORD) LWM(GetThreadTLSIndex, DWORD, DLD) LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG) LWM(GetTypeForBox, DWORDLONG, DWORDLONG) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 8455abdb80d61..b1a061696ec61 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -7216,6 +7216,65 @@ CORINFO_METHOD_HANDLE MethodContext::repGetSpecialCopyHelper(CORINFO_CLASS_HANDL return (CORINFO_METHOD_HANDLE)value; } + +void MethodContext::recGetIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum, bool result) +{ + if (GetIsLocalNonEscapes == nullptr) + GetIsLocalNonEscapes = new LightWeightMap(); + + Agnostic_LocalNonEscapes key; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.method = CastHandle(method); + key.lclNum = lclNum; + + DWORD value = result ? 1 : 0; + GetIsLocalNonEscapes->Add(key, value); + DEBUG_REC(dmpGetIsLocalNonEscapes(key, value)); +} + +void MethodContext::dmpGetIsLocalNonEscapes(const Agnostic_LocalNonEscapes& key, bool result) +{ + printf("getIsLocalNonEscapes key { method = %016" PRIX64 ", lclNum=%16X }, value %d" PRIX64 "", key.method, + key.lclNum, (DWORD)result); +} + +bool MethodContext::repGetIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + Agnostic_LocalNonEscapes key; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.method = CastHandle(method); + key.lclNum = lclNum; + DWORD value = + LookupByKeyOrMiss(GetIsLocalNonEscapes, key, ": key { method = %016" PRIX64 ", lclNum = %016X }", + key.method, key.lclNum); + DEBUG_REP(dmpGetIsLocalNonEscapes(key, value)); + return value == 0 ? false : true; +} + +void MethodContext::recSetIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + Agnostic_LocalNonEscapes key; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.method = CastHandle(method); + key.lclNum = lclNum; + + DEBUG_REC(dmpSetSpecialCopyHelper(key)); +} + +void MethodContext::dmpSetIsLocalNonEscapes(const Agnostic_LocalNonEscapes& key) +{ + printf("setIsLocalNonEscapes key { method = %016" PRIX64 ", lclNum = %016X }", key.method, key.lclNum); +} + +void MethodContext::repSetIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + Agnostic_LocalNonEscapes key; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.method = CastHandle(method); + key.lclNum = lclNum; + DEBUG_REP(dmpSetIsLocalNonEscapes(key, value)); +} + void MethodContext::dmpSigInstHandleMap(DWORD key, DWORDLONG value) { printf("SigInstHandleMap key %u, value %016" PRIX64 "", key, value); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 7ac90cce89793..385e3c484494a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -897,6 +897,14 @@ class MethodContext void recGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type, CORINFO_METHOD_HANDLE helper); void dmpGetSpecialCopyHelper(DWORDLONG key, DWORDLONG value); CORINFO_METHOD_HANDLE repGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type); + + void recGetIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum, bool result); + void dmpGetIsLocalNonEscapes(const Agnostic_LocalNonEscapes& key, bool result); + bool repGetIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum); + + void recSetIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum); + void dmpSetIsLocalNonEscapes(const Agnostic_LocalNonEscapes& key); + void repSetIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum); void dmpSigInstHandleMap(DWORD key, DWORDLONG value); @@ -1192,6 +1200,7 @@ enum mcPackets Packet_GetSpecialCopyHelper = 224, Packet_GetClassAssemblyName = 225, Packet_GetSZArrayHelperEnumeratorClass = 226, + Packet_GetIsLocalNonEscapes = 227, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index f48e29362d18d..dbf72ced81801 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -2029,3 +2029,18 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper(CORINFO_CLASS_HANDL mc->recGetSpecialCopyHelper(type, temp); return temp; } + +bool interceptor_ICJI::getIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + mc->cr->AddCall("getIsLocalNonEscapes"); + bool result = original_ICorJitInfo->getIsLocalNonEscapes(method, lclNum); + mc->recGetIsLocalNonEscapes(method, lclNum, result); + return result; +} + +void interceptor_ICJI::setIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + mc->cr->AddCall("setIsLocalNonEscapes"); + original_ICorJitInfo->setIsLocalNonEscapes(method, lclNum); + mc->recSetIsLocalNonEscapes(method, lclNum); +} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index b548b1fb1c2bf..58e7b68fe8ad6 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1437,3 +1437,19 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper( return original_ICorJitInfo->getSpecialCopyHelper(type); } +bool interceptor_ICJI::getIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) +{ + mcs->AddCall("getIsLocalNonEscapes"); + return original_ICorJitInfo->getIsLocalNonEscapes(method, lclNum); +} + +void interceptor_ICJI::setIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) +{ + mcs->AddCall("setIsLocalNonEscapes"); + original_ICorJitInfo->setIsLocalNonEscapes(method, lclNum); +} + diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 5e4e57b7ba637..c2924957263f8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1261,3 +1261,17 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper( return original_ICorJitInfo->getSpecialCopyHelper(type); } +bool interceptor_ICJI::getIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) +{ + return original_ICorJitInfo->getIsLocalNonEscapes(method, lclNum); +} + +void interceptor_ICJI::setIsLocalNonEscapes( + CORINFO_METHOD_HANDLE method, + uint32_t lclNum) +{ + original_ICorJitInfo->setIsLocalNonEscapes(method, lclNum); +} + diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 0c18e39ebe971..61666c1729687 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1867,3 +1867,16 @@ CORINFO_METHOD_HANDLE MyICJI::getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) CORINFO_METHOD_HANDLE result = jitInstance->mc->repGetSpecialCopyHelper(type); return result; } + +bool MyICJI::getIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + jitInstance->mc->cr->AddCall("getIsLocalNonEscapes"); + bool result = jitInstance->mc->repGetIsLocalNonEscapes(method, lclNum); + return result; +} + +void MyICJI::setIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + jitInstance->mc->cr->AddCall("setIsLocalNonEscapes"); + jitInstance->mc->repGetIsLocalNonEscapes(method, lclNum); +} diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 28d95e523f6cd..7439fb55e0f1a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10031,6 +10031,42 @@ CORINFO_METHOD_HANDLE CEEInfo::getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) return result; } +bool CEEInfo::getIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + bool result = true; + + JIT_TO_EE_TRANSITION(); + + MethodDesc* ftn = GetMethod(method); + result = ftn->GetLocalNonEscapes(lclNum); + + EE_TO_JIT_TRANSITION(); + + return result; +} + +void CEEInfo::setIsLocalNonEscapes(CORINFO_METHOD_HANDLE method, uint32_t lclNum) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION(); + + MethodDesc* ftn = GetMethod(method); + ftn->SetLocalNonEscapes(lclNum); + + EE_TO_JIT_TRANSITION(); +} + /*********************************************************************/ CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle( CORINFO_METHOD_HANDLE method, diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 956765b76ff05..d7adc4e3f6b5f 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -932,6 +932,38 @@ class MethodDesc LIMITED_METHOD_DAC_CONTRACT; return (m_wFlags & mdfSynchronized) != 0; } + + inline bool GetLocalNonEscapes(uint32_t lclNum) + { + LIMITED_METHOD_DAC_CONTRACT; + if (lclNum < 64) + { + return (m_localNonEscapeData.low & (1ULL << lclNum)) != 0; + } + if (lclNum < 128) + { + return (m_localNonEscapeData.high & (1ULL << (lclNum - 64))) != 0; + } + + return false; + } + + inline void SetLocalNonEscapes(uint32_t lclNum) + { + LIMITED_METHOD_DAC_CONTRACT; + if (lclNum >= 128) + { + return; + } + if (lclNum >= 64) + { + m_localNonEscapeData.high |= (1ULL << (lclNum - 64)); + } + else + { + m_localNonEscapeData.low |= (1ULL << lclNum); + } + } //================================================================== // The MethodDesc in relation to the VTable it is associated with. @@ -1709,6 +1741,10 @@ class MethodDesc WORD m_wSlotNumber; // The slot number of this MethodDesc in the vtable array. WORD m_wFlags; // See MethodDescFlags PTR_MethodDescCodeData m_codeData; + struct { + uint64_t low; + uint64_t high; + } m_localNonEscapeData; public: #ifdef DACCESS_COMPILE