From a6cdae6ad3619db3ad108b9246b22bcacbadbc46 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 9 Oct 2025 16:31:37 -0700 Subject: [PATCH 01/15] Remove usage of Precode::GetPrecodeFromEntryPoint in WASM. --- src/coreclr/clrdefinitions.cmake | 2 +- src/coreclr/vm/appdomain.cpp | 2 + src/coreclr/vm/ceeload.cpp | 13 +++++ src/coreclr/vm/ceeload.h | 6 +++ src/coreclr/vm/ceeload.inl | 2 + src/coreclr/vm/ceemain.cpp | 5 ++ src/coreclr/vm/codeversion.h | 2 +- src/coreclr/vm/comdelegate.cpp | 3 +- .../vm/datadescriptor/datadescriptor.inc | 8 +++ src/coreclr/vm/dllimport.cpp | 4 ++ src/coreclr/vm/dllimportcallback.h | 11 ++-- src/coreclr/vm/interpexec.cpp | 17 ++++--- src/coreclr/vm/jitinterface.cpp | 5 ++ src/coreclr/vm/method.cpp | 34 ++++++++++--- src/coreclr/vm/method.hpp | 50 +++++++++++++------ src/coreclr/vm/methodtablebuilder.cpp | 1 - src/coreclr/vm/precode_portable.cpp | 7 --- src/coreclr/vm/precode_portable.hpp | 2 - src/coreclr/vm/prestub.cpp | 28 ++++++++--- src/coreclr/vm/proftoeeinterfaceimpl.cpp | 6 +++ src/coreclr/vm/stubmgr.cpp | 4 ++ src/coreclr/vm/stubmgr.h | 2 + 22 files changed, 163 insertions(+), 51 deletions(-) diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index e5278d53388834..707359a3b9a0db 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -60,7 +60,6 @@ if(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64) add_compile_definitions(OUT_OF_PROCESS_SETTHREADCONTEXT) endif(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64) -add_compile_definitions(FEATURE_CODE_VERSIONING) add_definitions(-DFEATURE_COLLECTIBLE_TYPES) if(CLR_CMAKE_TARGET_WIN32) @@ -176,6 +175,7 @@ endif(NOT CLR_CMAKE_HOST_ANDROID) add_definitions(-DFEATURE_SYMDIFF) if (FEATURE_TIERED_COMPILATION) + add_compile_definitions(FEATURE_CODE_VERSIONING) add_compile_definitions(FEATURE_TIERED_COMPILATION) endif(FEATURE_TIERED_COMPILATION) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 23d205e26c1717..862f1c8ff64a70 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -719,7 +719,9 @@ void SystemDomain::Attach() CONTRACTL_END; // Initialize stub managers +#ifndef FEATURE_PORTABLE_ENTRYPOINTS PrecodeStubManager::Init(); +#endif // !FEATURE_PORTABLE_ENTRYPOINTS JumpStubStubManager::Init(); RangeSectionStubManager::Init(); ILStubManager::Init(); diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index bb0f2037816852..9ba258b07be214 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -1319,7 +1319,9 @@ void Module::AllocateMaps() m_TypeRefToMethodTableMap.dwCount = TYPEREF_MAP_INITIAL_SIZE; m_MemberRefMap.dwCount = MEMBERREF_MAP_INITIAL_SIZE; m_MethodDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE; +#ifdef FEATURE_CODE_VERSIONING m_ILCodeVersioningStateMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE; +#endif // FEATURE_CODE_VERSIONING m_FieldDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE; m_GenericParamToDescMap.dwCount = GENERICPARAM_MAP_INITIAL_SIZE; m_ManifestModuleReferencesMap.dwCount = ASSEMBLYREFERENCES_MAP_INITIAL_SIZE; @@ -1340,8 +1342,10 @@ void Module::AllocateMaps() // Get # MethodDefs m_MethodDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtMethodDef)+1; +#ifdef FEATURE_CODE_VERSIONING // IL code versions are relatively rare so keep small. m_ILCodeVersioningStateMap.dwCount = 1; +#endif // FEATURE_CODE_VERSIONING // Get # FieldDefs m_FieldDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtFieldDef)+1; @@ -1359,7 +1363,9 @@ void Module::AllocateMaps() nTotal += m_TypeRefToMethodTableMap.dwCount; nTotal += m_MemberRefMap.dwCount; nTotal += m_MethodDefToDescMap.dwCount; +#ifdef FEATURE_CODE_VERSIONING nTotal += m_ILCodeVersioningStateMap.dwCount; +#endif // FEATURE_CODE_VERSIONING nTotal += m_FieldDefToDescMap.dwCount; nTotal += m_GenericParamToDescMap.dwCount; nTotal += m_ManifestModuleReferencesMap.dwCount; @@ -1386,13 +1392,20 @@ void Module::AllocateMaps() m_MethodDefToDescMap.supportedFlags = METHOD_DEF_MAP_ALL_FLAGS; m_MethodDefToDescMap.pTable = &m_MemberRefMap.pTable[m_MemberRefMap.dwCount]; +#ifdef FEATURE_CODE_VERSIONING m_ILCodeVersioningStateMap.pNext = NULL; m_ILCodeVersioningStateMap.supportedFlags = METHOD_DEF_MAP_ALL_FLAGS; m_ILCodeVersioningStateMap.pTable = &m_MethodDefToDescMap.pTable[m_MethodDefToDescMap.dwCount]; +#endif // FEATURE_CODE_VERSIONING m_FieldDefToDescMap.pNext = NULL; m_FieldDefToDescMap.supportedFlags = FIELD_DEF_MAP_ALL_FLAGS; + +#ifdef FEATURE_CODE_VERSIONING m_FieldDefToDescMap.pTable = &m_ILCodeVersioningStateMap.pTable[m_ILCodeVersioningStateMap.dwCount]; +#else // !FEATURE_CODE_VERSIONING + m_FieldDefToDescMap.pTable = NULL; +#endif // FEATURE_CODE_VERSIONING m_GenericParamToDescMap.pNext = NULL; m_GenericParamToDescMap.supportedFlags = GENERIC_PARAM_MAP_ALL_FLAGS; diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index c4d02b6e02dbb6..3171a83687c23e 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -740,9 +740,11 @@ class Module : public ModuleBase // For generic methods, IsGenericTypeDefinition() is true i.e. instantiation at formals LookupMap m_MethodDefToDescMap; +#ifdef FEATURE_CODE_VERSIONING // Linear mapping from MethodDef token to ILCodeVersioningState * // This is used for Code Versioning logic LookupMap m_ILCodeVersioningStateMap; +#endif // FEATURE_CODE_VERSIONING // Linear mapping from FieldDef token to FieldDesc* LookupMap m_FieldDefToDescMap; @@ -1252,6 +1254,7 @@ class Module : public ModuleBase } #endif // !DACCESS_COMPILE +#ifdef FEATURE_CODE_VERSIONING PTR_ILCodeVersioningState LookupILCodeVersioningState(mdMethodDef token); #ifndef DACCESS_COMPILE @@ -1270,6 +1273,7 @@ class Module : public ModuleBase m_ILCodeVersioningStateMap.SetElement(RidFromToken(token), value); } #endif // !DACCESS_COMPILE +#endif // FEATURE_CODE_VERSIONING #ifndef DACCESS_COMPILE FieldDesc *LookupFieldDef(mdFieldDef token) @@ -1714,7 +1718,9 @@ struct cdac_data static constexpr size_t MethodDefToDescMap = offsetof(Module, m_MethodDefToDescMap); static constexpr size_t TypeDefToMethodTableMap = offsetof(Module, m_TypeDefToMethodTableMap); static constexpr size_t TypeRefToMethodTableMap = offsetof(Module, m_TypeRefToMethodTableMap); +#ifdef FEATURE_CODE_VERSIONING static constexpr size_t MethodDefToILCodeVersioningStateMap = offsetof(Module, m_ILCodeVersioningStateMap); +#endif // FEATURE_CODE_VERSIONING static constexpr size_t DynamicILBlobTable = offsetof(Module, m_debuggerSpecificData.m_pDynamicILBlobTable); }; diff --git a/src/coreclr/vm/ceeload.inl b/src/coreclr/vm/ceeload.inl index 2067de38088fd9..fe7ad7c7a9a09f 100644 --- a/src/coreclr/vm/ceeload.inl +++ b/src/coreclr/vm/ceeload.inl @@ -274,6 +274,7 @@ inline PTR_MethodDesc Module::LookupMethodDef(mdMethodDef token) return m_MethodDefToDescMap.GetElement(RidFromToken(token)); } +#ifdef FEATURE_CODE_VERSIONING inline PTR_ILCodeVersioningState Module::LookupILCodeVersioningState(mdMethodDef token) { CONTRACTL @@ -288,6 +289,7 @@ inline PTR_ILCodeVersioningState Module::LookupILCodeVersioningState(mdMethodDef _ASSERTE(TypeFromToken(token) == mdtMethodDef); return m_ILCodeVersioningStateMap.GetElement(RidFromToken(token)); } +#endif // FEATURE_CODE_VERSIONING inline MethodDesc *Module::LookupMemberRefAsMethod(mdMemberRef token) { diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index fb59a8eb5903f6..8a7315add3bdcb 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -669,11 +669,16 @@ void EEStartupHelper() JITInlineTrackingMap::StaticInitialize(); MethodDescBackpatchInfoTracker::StaticInitialize(); + +#ifdef FEATURE_CODE_VERSIONING CodeVersionManager::StaticInitialize(); +#endif // FEATURE_CODE_VERSIONING + #ifdef FEATURE_TIERED_COMPILATION TieredCompilationManager::StaticInitialize(); CallCountingManager::StaticInitialize(); #endif // FEATURE_TIERED_COMPILATION + OnStackReplacementManager::StaticInitialize(); MethodTable::InitMethodDataCache(); diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 33700718aad612..7a42d2ba247960 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -29,7 +29,7 @@ typedef DPTR(class ILCodeVersioningState) PTR_ILCodeVersioningState; class CodeVersionManager; typedef DPTR(class CodeVersionManager) PTR_CodeVersionManager; -#endif +#endif // FEATURE_CODE_VERSIONING #ifdef HAVE_GCCOVER class GCCoverageInfo; diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 5d59f3298e9a18..fd5fae87439767 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -1433,6 +1433,7 @@ OBJECTREF COMDelegate::ConvertToDelegate(LPVOID pCallback, MethodTable* pMT) UMEntryThunk* pUMEntryThunk = NULL; +#ifndef FEATURE_PORTABLE_ENTRYPOINTS auto stubKind = RangeSectionStubManager::GetStubKind((PCODE)pCallback); if (stubKind == STUB_CODE_BLOCK_STUBPRECODE) { @@ -1442,7 +1443,7 @@ OBJECTREF COMDelegate::ConvertToDelegate(LPVOID pCallback, MethodTable* pMT) pUMEntryThunk = pPrecode->AsUMEntryThunk(); } } - +#endif // !FEATURE_PORTABLE_ENTRYPOINTS // Lookup the callsite in the hash, if found, we can map this call back to its managed function. // Otherwise, we'll treat this as an unmanaged callsite. diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index e54560e22ee228..e84411a6fc338b 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -183,7 +183,9 @@ CDAC_TYPE_FIELD(Module, /*pointer*/, MemberRefToDescMap, cdac_data::Memb CDAC_TYPE_FIELD(Module, /*pointer*/, MethodDefToDescMap, cdac_data::MethodDefToDescMap) CDAC_TYPE_FIELD(Module, /*pointer*/, TypeDefToMethodTableMap, cdac_data::TypeDefToMethodTableMap) CDAC_TYPE_FIELD(Module, /*pointer*/, TypeRefToMethodTableMap, cdac_data::TypeRefToMethodTableMap) +#ifdef FEATURE_CODE_VERSIONING CDAC_TYPE_FIELD(Module, /*pointer*/, MethodDefToILCodeVersioningStateMap, cdac_data::MethodDefToILCodeVersioningStateMap) +#endif // FEATURE_CODE_VERSIONING CDAC_TYPE_FIELD(Module, /*pointer*/, DynamicILBlobTable, cdac_data::DynamicILBlobTable) CDAC_TYPE_END(Module) @@ -499,14 +501,18 @@ CDAC_TYPE_END(CodePointer) CDAC_TYPE_BEGIN(MethodDescCodeData) CDAC_TYPE_INDETERMINATE(MethodDescCodeData) CDAC_TYPE_FIELD(MethodDescCodeData, /*CodePointer*/, TemporaryEntryPoint, offsetof(MethodDescCodeData,TemporaryEntryPoint)) +#ifdef FEATURE_CODE_VERSIONING CDAC_TYPE_FIELD(MethodDescCodeData, /*pointer*/, VersioningState, offsetof(MethodDescCodeData,VersioningState)) +#endif // FEATURE_CODE_VERSIONING CDAC_TYPE_END(MethodDescCodeData) +#ifdef FEATURE_CODE_VERSIONING CDAC_TYPE_BEGIN(MethodDescVersioningState) CDAC_TYPE_INDETERMINATE(MethodDescVersioningState) CDAC_TYPE_FIELD(MethodDescVersioningState, /*pointer*/, NativeCodeVersionNode, cdac_data::NativeCodeVersionNode) CDAC_TYPE_FIELD(MethodDescVersioningState, /*uint8*/, Flags, cdac_data::Flags) CDAC_TYPE_END(MethodDescVersioningState) +#endif // FEATURE_CODE_VERSIONING #ifndef FEATURE_PORTABLE_ENTRYPOINTS CDAC_TYPE_BEGIN(PrecodeMachineDescriptor) @@ -677,6 +683,7 @@ CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, MapBase, offsetof(HeapList, mapBa CDAC_TYPE_FIELD(CodeHeapListNode, /*pointer*/, HeaderMap, offsetof(HeapList, pHdrMap)) CDAC_TYPE_END(CodeHeapListNode) +#ifdef FEATURE_CODE_VERSIONING CDAC_TYPE_BEGIN(ILCodeVersioningState) CDAC_TYPE_INDETERMINATE(ILCodeVersioningState) CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, FirstVersionNode, cdac_data::FirstVersionNode) @@ -705,6 +712,7 @@ CDAC_TYPE_FIELD(ILCodeVersionNode, /*pointer*/, Next, cdac_data::RejitState) CDAC_TYPE_FIELD(ILCodeVersionNode, /*pointer*/, ILAddress, cdac_data::ILAddress) CDAC_TYPE_END(ILCodeVersionNode) +#endif // FEATURE_CODE_VERSIONING CDAC_TYPE_BEGIN(ProfControlBlock) CDAC_TYPE_FIELD(ProfControlBlock, /*uint64*/, GlobalEventMask, offsetof(ProfControlBlock, globalEventMask)) diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 9bf757b3ba0750..37b4eb3fdf14f0 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -5650,6 +5650,9 @@ PCODE PInvoke::GetStubForILStub(PInvokeMethodDesc* pNMD, MethodDesc** ppStubMD, { CONSISTENCY_CHECK(pNMD->IsVarArgs()); +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + _ASSERTE(false && "Vararg P/Invoke is not supported with portable entrypoints"); +#else // !FEATURE_PORTABLE_ENTRYPOINTS // // varargs goes through vararg PInvoke stub // @@ -5657,6 +5660,7 @@ PCODE PInvoke::GetStubForILStub(PInvokeMethodDesc* pNMD, MethodDesc** ppStubMD, // Only vararg P/Invoke use shared stubs, they need a precode to push the hidden argument. (void)pNMD->GetOrCreatePrecode(); +#endif // FEATURE_PORTABLE_ENTRYPOINTS } if (pNMD->IsEarlyBound()) diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h index eedf953b0ff394..4c9785eed266a9 100644 --- a/src/coreclr/vm/dllimportcallback.h +++ b/src/coreclr/vm/dllimportcallback.h @@ -247,7 +247,8 @@ class UMEntryThunkData PCODE entryPoint = m_pUMThunkMarshInfo->GetExecStubEntryPoint(); -#ifdef FEATURE_INTERPRETER + bool nullEntryPoint; +#if defined(FEATURE_INTERPRETER) && !defined(FEATURE_PORTABLE_ENTRYPOINTS) // For interpreted stubs we need to ensure that TheUMEntryPrestubWorker runs for every // unmanaged-to-managed invocation in order to populate the TLS variable every time. auto stubKind = RangeSectionStubManager::GetStubKind(entryPoint); @@ -260,9 +261,13 @@ class UMEntryThunkData entryPoint = (PCODE)0; } } + nullEntryPoint = entryPoint == (PCODE)0; +#else // !FEATURE_INTERPRETER || FEATURE_PORTABLE_ENTRYPOINTS + nullEntryPoint = false; + _ASSERTE(entryPoint != (PCODE)0); +#endif // FEATURE_INTERPRETER && !FEATURE_PORTABLE_ENTRYPOINTS - if (entryPoint != (PCODE)0) -#endif // FEATURE_INTERPRETER + if (!nullEntryPoint) { m_pUMEntryThunk->SetTargetUnconditional(entryPoint); } diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 2bb77033da0b6d..baaf5990da7b74 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -679,10 +679,15 @@ static void CallPreStub(MethodDesc *pMD) STATIC_STANDARD_VM_CONTRACT; _ASSERTE(pMD != NULL); - if (!pMD->IsPointingToPrestub() && - pMD->GetTemporaryEntryPoint() && // The prestub may not yet be ready to be used, so force temporary entry point creation, and check again. - !pMD->IsPointingToPrestub()) - return; + // The prestub may not yet be ready to be used, so force temporary entry point creation, and check again. + if (!pMD->IsPointingToPrestub()) + { + PCODE entryPoint = pMD->GetTemporaryEntryPoint(); + if (entryPoint != NULL && !pMD->IsPointingToPrestub()) + { + return; + } + } struct Param { @@ -2541,10 +2546,10 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr break; } } - + OBJECTREF targetMethodObj = (*delegateObj)->GetTarget(); LOCAL_VAR(callArgsOffset, OBJECTREF) = targetMethodObj; - + if ((targetMethod = NonVirtualEntry2MethodDesc(targetAddress)) != NULL) { // In this case targetMethod holds a pointer to the MethodDesc that will be called by using targetMethodObj as diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index b6186a7382abc3..e99c360a8b9413 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9124,17 +9124,22 @@ void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd, { // FCalls can be called directly ret = (void*)ECall::GetFCallImpl(ftn, false /* throwForInvalidFCall */); +#ifndef FEATURE_PORTABLE_ENTRYPOINTS if (ret == NULL) { ret = ((FixupPrecode*)ftn->GetOrCreatePrecode())->GetTargetSlot(); accessType = IAT_PVALUE; } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS + _ASSERTE(ret != NULL); } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS else if (ftn->IsVersionableWithPrecode() && (ftn->GetPrecodeType() == PRECODE_FIXUP) && !ftn->IsPointingToStableNativeCode()) { ret = ((FixupPrecode*)ftn->GetOrCreatePrecode())->GetTargetSlot(); accessType = IAT_PVALUE; } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS else { ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags); diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 6eb4204c1630f0..8ee338c45297b9 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -239,6 +239,7 @@ HRESULT MethodDesc::EnsureCodeDataExists(AllocMemTracker *pamTracker) return S_OK; } +#ifdef FEATURE_CODE_VERSIONING HRESULT MethodDesc::SetMethodDescVersionState(PTR_MethodDescVersioningState state) { WRAPPER_NO_CONTRACT; @@ -252,6 +253,7 @@ HRESULT MethodDesc::SetMethodDescVersionState(PTR_MethodDescVersioningState stat return S_OK; } +#endif // FEATURE_CODE_VERSIONING #ifdef FEATURE_INTERPRETER // Set the call stub for the interpreter to JIT/AOT calls @@ -279,6 +281,7 @@ CallStubHeader *MethodDesc::GetCallStub() #endif //!DACCESS_COMPILE +#ifdef FEATURE_CODE_VERSIONING PTR_MethodDescVersioningState MethodDesc::GetMethodDescVersionState() { WRAPPER_NO_CONTRACT; @@ -287,6 +290,7 @@ PTR_MethodDescVersioningState MethodDesc::GetMethodDescVersionState() return NULL; return VolatileLoadWithoutBarrier(&codeData->VersioningState); } +#endif // FEATURE_CODE_VERSIONING //******************************************************************************* LPCUTF8 MethodDesc::GetNameThrowing() @@ -1057,7 +1061,7 @@ PCODE MethodDesc::GetNativeCodeAnyVersion() { return pDefaultCode; } - +#ifdef FEATURE_CODE_VERSIONING else { CodeVersionManager *pCodeVersionManager = GetCodeVersionManager(); @@ -1075,8 +1079,10 @@ PCODE MethodDesc::GetNativeCodeAnyVersion() } } } - return (PCODE)NULL; } +#endif // FEATURE_CODE_VERSIONING + + return (PCODE)NULL; } //******************************************************************************* @@ -2386,10 +2392,15 @@ BOOL MethodDesc::IsPointingToPrestub() return TRUE; } +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + return FALSE; + +#else // !FEATURE_PORTABLE_ENTRYPOINTS if (!HasPrecode()) return FALSE; return GetPrecode()->IsPointingToPrestub(); +#endif // FEATURE_PORTABLE_ENTRYPOINTS } //******************************************************************************* @@ -2408,11 +2419,13 @@ void MethodDesc::Reset() // Reset any flags relevant to the old code ClearFlagsOnUpdate(); +#ifndef FEATURE_PORTABLE_ENTRYPOINTS if (HasPrecode()) { GetPrecode()->Reset(); } else +#endif // !FEATURE_PORTABLE_ENTRYPOINTS { // We should go here only for the rental methods _ASSERTE(GetLoaderModule()->IsReflectionEmit()); @@ -2861,8 +2874,7 @@ void MethodDescChunk::DetermineAndSetIsEligibleForTieredCompilation() } } - -//******************************************************************************* +#ifndef FEATURE_PORTABLE_ENTRYPOINTS Precode* MethodDesc::GetOrCreatePrecode() { WRAPPER_NO_CONTRACT; @@ -2883,11 +2895,9 @@ Precode* MethodDesc::GetOrCreatePrecode() PTR_PCODE pSlot = GetAddrOfSlot(); _ASSERTE(*pSlot != (PCODE)NULL); _ASSERTE(*pSlot == tempEntry); -#ifndef FEATURE_PORTABLE_ENTRYPOINTS PrecodeType requiredType = GetPrecodeType(); PrecodeType availableType = Precode::GetPrecodeFromEntryPoint(tempEntry)->GetType(); _ASSERTE(requiredType == availableType); -#endif // !FEATURE_PORTABLE_ENTRYPOINTS #endif // _DEBUG // Set the flags atomically @@ -2895,6 +2905,7 @@ Precode* MethodDesc::GetOrCreatePrecode() return Precode::GetPrecodeFromEntryPoint(tempEntry); } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS void MethodDesc::MarkPrecodeAsStableEntrypoint() { @@ -3125,6 +3136,7 @@ FORCEINLINE bool MethodDesc::TryBackpatchEntryPointSlots( return true; } +#ifdef FEATURE_CODE_VERSIONING void MethodDesc::TrySetInitialCodeEntryPointForVersionableMethod( PCODE entryPoint, bool mayHaveEntryPointSlotsToBackpatch) @@ -3144,6 +3156,7 @@ void MethodDesc::TrySetInitialCodeEntryPointForVersionableMethod( GetOrCreatePrecode()->SetTargetInterlocked(entryPoint, TRUE /* fOnlyRedirectFromPrestub */); } } +#endif // FEATURE_CODE_VERSIONING void MethodDesc::SetCodeEntryPoint(PCODE entryPoint) { @@ -3185,6 +3198,7 @@ void MethodDesc::SetCodeEntryPoint(PCODE entryPoint) } } +#ifdef FEATURE_TIERED_COMPILATION void MethodDesc::ResetCodeEntryPoint() { WRAPPER_NO_CONTRACT; @@ -3202,6 +3216,7 @@ void MethodDesc::ResetCodeEntryPoint() GetPrecode()->ResetTargetInterlocked(); } } +#endif // FEATURE_TIERED_COMPILATION void MethodDesc::ResetCodeEntryPointForEnC() { @@ -3221,12 +3236,15 @@ void MethodDesc::ResetCodeEntryPointForEnC() return; } - LOG((LF_ENC, LL_INFO100000, "MD::RCEPFENC: this:%p - %s::%s - HasPrecode():%s, HasNativeCodeSlot():%s\n", - this, m_pszDebugClassName, m_pszDebugMethodName, (HasPrecode() ? "true" : "false"), (HasNativeCodeSlot() ? "true" : "false"))); + LOG((LF_ENC, LL_INFO100000, "MD::RCEPFENC: this:%p - %s::%s\n", this, m_pszDebugClassName, m_pszDebugMethodName)); +#ifndef FEATURE_PORTABLE_ENTRYPOINTS + LOG((LF_ENC, LL_INFO100000, "MD::RCEPFENC: HasPrecode():%s, HasNativeCodeSlot():%s\n", + (HasPrecode() ? "true" : "false"), (HasNativeCodeSlot() ? "true" : "false"))); if (HasPrecode()) { GetPrecode()->ResetTargetInterlocked(); } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS if (HasNativeCodeSlot()) { diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index f56eddccf9012d..fb95fdabf25d25 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -234,7 +234,9 @@ enum MethodDescFlags // Used for storing additional items related to native code struct MethodDescCodeData final { +#ifdef FEATURE_CODE_VERSIONING PTR_MethodDescVersioningState VersioningState; +#endif // FEATURE_CODE_VERSIONING PCODE TemporaryEntryPoint; #ifdef FEATURE_INTERPRETER CallStubHeader *CallStub; @@ -379,6 +381,7 @@ class MethodDesc return (m_wFlags3AndTokenRemainder & enum_flag3_HasPrecode) != 0; } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS inline Precode* GetPrecode() { LIMITED_METHOD_DAC_CONTRACT; @@ -388,6 +391,7 @@ class MethodDesc _ASSERTE(pPrecode != NULL); return pPrecode; } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS inline bool MayHavePrecode() { @@ -412,7 +416,9 @@ class MethodDesc return result; } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS Precode* GetOrCreatePrecode(); +#endif // !FEATURE_PORTABLE_ENTRYPOINTS void MarkPrecodeAsStableEntrypoint(); static MethodDesc * GetMethodDescFromPrecode(PCODE addr, BOOL fSpeculative = FALSE); @@ -1412,9 +1418,13 @@ class MethodDesc bool TryBackpatchEntryPointSlots(PCODE entryPoint, bool isPrestubEntryPoint, bool onlyFromPrestubEntryPoint); public: +#ifdef FEATURE_CODE_VERSIONING void TrySetInitialCodeEntryPointForVersionableMethod(PCODE entryPoint, bool mayHaveEntryPointSlotsToBackpatch); +#endif // FEATURE_CODE_VERSIONING void SetCodeEntryPoint(PCODE entryPoint); +#ifdef FEATURE_TIERED_COMPILATION void ResetCodeEntryPoint(); +#endif // FEATURE_TIERED_COMPILATION void ResetCodeEntryPointForEnC(); @@ -1443,17 +1453,6 @@ class MethodDesc return !IsVersionable() && !InEnCEnabledModule(); } - //Is this method currently pointing to native code that will never change? - BOOL IsPointingToStableNativeCode() - { - LIMITED_METHOD_DAC_CONTRACT; - - if (!IsNativeCodeStableAfterInit()) - return FALSE; - - return IsPointingToNativeCode(); - } - // Note: We are skipping the prestub based on addition information from the JIT. // (e.g. that the call is on same this ptr or that the this ptr is not null). // Thus we can end up with a running NGENed method for which IsPointingToNativeCode is false! @@ -1461,6 +1460,10 @@ class MethodDesc { LIMITED_METHOD_DAC_CONTRACT; +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + return FALSE; + +#else // !FEATURE_PORTABLE_ENTRYPOINTS if (!HasStableEntryPoint()) return FALSE; @@ -1468,6 +1471,23 @@ class MethodDesc return TRUE; return GetPrecode()->IsPointingToNativeCode(GetNativeCode()); +#endif // FEATURE_PORTABLE_ENTRYPOINTS + } + + //Is this method currently pointing to native code that will never change? + BOOL IsPointingToStableNativeCode() + { + LIMITED_METHOD_DAC_CONTRACT; + +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + return FALSE; + +#else // !FEATURE_PORTABLE_ENTRYPOINTS + if (!IsNativeCodeStableAfterInit()) + return FALSE; + + return IsPointingToNativeCode(); +#endif // FEATURE_PORTABLE_ENTRYPOINTS } // Be careful about races with profiler when using this method. The profiler can @@ -1746,7 +1766,7 @@ class MethodDesc // Return value: // stable entry point (code:MethodDesc::GetStableEntryPoint()) // - PCODE DoBackpatch(MethodTable * pMT, MethodTable * pDispatchingMT, BOOL fFullBackPatch); + PCODE DoBackpatch(MethodTable * pMT, MethodTable * pDispatchingMT, bool fFullBackPatch); PCODE DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMode = CallerGCMode::Unknown); @@ -1867,7 +1887,11 @@ class MethodDesc // OR must be set to point to the same AllocMemTracker that controls allocation of the MethodDesc HRESULT EnsureCodeDataExists(AllocMemTracker *pamTracker); +#ifdef FEATURE_CODE_VERSIONING HRESULT SetMethodDescVersionState(PTR_MethodDescVersioningState state); + PTR_MethodDescVersioningState GetMethodDescVersionState(); +#endif // FEATURE_CODE_VERSIONING + #ifdef FEATURE_INTERPRETER bool SetCallStub(CallStubHeader *pHeader); CallStubHeader *GetCallStub(); @@ -1875,8 +1899,6 @@ class MethodDesc #endif //!DACCESS_COMPILE - PTR_MethodDescVersioningState GetMethodDescVersionState(); - public: inline DWORD GetClassification() const { diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 7070a5a3054a2c..e13efdcf4d392f 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -1365,7 +1365,6 @@ MethodTableBuilder::BuildMethodTableThrowing( if (g_pConfig->ShouldBreakOnClassBuild(className)) { - CONSISTENCY_CHECK_MSGF(false, ("BreakOnClassBuild: typename '%s' ", className)); GetHalfBakedClass()->m_fDebuggingClass = TRUE; } diff --git a/src/coreclr/vm/precode_portable.cpp b/src/coreclr/vm/precode_portable.cpp index b5ef68ecb105fe..04378748810f81 100644 --- a/src/coreclr/vm/precode_portable.cpp +++ b/src/coreclr/vm/precode_portable.cpp @@ -164,13 +164,6 @@ Precode* Precode::Allocate(PrecodeType t, MethodDesc* pMD, return NULL; } -Precode* Precode::GetPrecodeFromEntryPoint(PCODE addr, BOOL fSpeculative) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Precode::GetPrecodeFromEntryPoint is not supported with Portable EntryPoints"); - return NULL; -} - PrecodeType Precode::GetType() { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/precode_portable.hpp b/src/coreclr/vm/precode_portable.hpp index 57cf812e7186ae..aba0642a4d5229 100644 --- a/src/coreclr/vm/precode_portable.hpp +++ b/src/coreclr/vm/precode_portable.hpp @@ -114,8 +114,6 @@ class Precode static Precode* Allocate(PrecodeType t, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker); - static Precode* GetPrecodeFromEntryPoint(PCODE addr, BOOL fSpeculative = FALSE); - public: PrecodeType GetType(); diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index dab4dc040f892b..36557ae4e223a4 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -66,7 +66,7 @@ void MethodDesc::Init() //========================================================================== -PCODE MethodDesc::DoBackpatch(MethodTable * pMT, MethodTable *pDispatchingMT, BOOL fFullBackPatch) +PCODE MethodDesc::DoBackpatch(MethodTable * pMT, MethodTable *pDispatchingMT, bool fFullBackPatch) { CONTRACTL { @@ -138,8 +138,10 @@ PCODE MethodDesc::DoBackpatch(MethodTable * pMT, MethodTable *pDispatchingMT, BO } } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS // Patch the fake entrypoint if necessary Precode::GetPrecodeFromEntryPoint(pExpected)->SetTargetInterlocked(pTarget); +#endif // !FEATURE_PORTABLE_ENTRYPOINTS } if (HasNonVtableSlot()) @@ -363,6 +365,8 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig) shouldTier = false; } #endif // FEATURE_TIERED_COMPILATION + +#ifdef FEATURE_CODE_VERSIONING NativeCodeVersion nativeCodeVersion = pConfig->GetCodeVersion(); if (shouldTier && !nativeCodeVersion.IsDefaultVersion()) { @@ -372,6 +376,7 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig) shouldTier = false; } } +#endif // FEATURE_CODE_VERSIONING if (pConfig->MayUsePrecompiledCode()) { @@ -743,6 +748,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J // JITCompilationStarted. It isn't clear if this is the ideal policy for these // notifications yet. NativeCodeVersion nativeCodeVersion = pConfig->GetCodeVersion(); +#ifdef FEATURE_CODE_VERSIONING ReJITID rejitId = nativeCodeVersion.GetILCodeVersionId(); if (rejitId != 0) { @@ -752,14 +758,14 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J TRUE); } else +#endif // FEATURE_CODE_VERSIONING + { // If profiling, need to give a chance for a tool to examine and modify // the IL before it gets to the JIT. This allows one to add probe calls for // things like code coverage, performance, or whatever. - { if (!IsNoMetadata()) { (&g_profControlBlock)->JITCompilationStarted((FunctionID)this, TRUE); - } else { @@ -770,10 +776,12 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J (&g_profControlBlock)->DynamicMethodJITCompilationStarted((FunctionID)this, TRUE, ilHeaderPointer, ilSize); } +#ifdef FEATURE_CODE_VERSIONING if (nativeCodeVersion.IsDefaultVersion()) { pConfig->SetProfilerMayHaveActivatedNonDefaultCodeVersion(); } +#endif // FEATURE_CODE_VERSIONING } END_PROFILER_CALLBACK(); } @@ -833,6 +841,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J // JITCompilationFinished. It isn't clear if this is the ideal policy for these // notifications yet. NativeCodeVersion nativeCodeVersion = pConfig->GetCodeVersion(); +#ifdef FEATURE_CODE_VERSIONING ReJITID rejitId = nativeCodeVersion.GetILCodeVersionId(); if (rejitId != 0) { @@ -843,10 +852,11 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J TRUE); } else +#endif // FEATURE_CODE_VERSIONING + { // Notify the profiler that JIT completed. // Must do this after the address has been set. // @ToDo: Why must we set the address before notifying the profiler ?? - { if (!IsNoMetadata()) { (&g_profControlBlock)-> @@ -859,10 +869,12 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J (&g_profControlBlock)->DynamicMethodJITCompilationFinished((FunctionID)this, pEntry->m_hrResultCode, TRUE); } +#ifdef FEATURE_CODE_VERSIONING if (nativeCodeVersion.IsDefaultVersion()) { pConfig->SetProfilerMayHaveActivatedNonDefaultCodeVersion(); } +#endif // FEATURE_CODE_VERSIONING } END_PROFILER_CALLBACK(); } @@ -2253,14 +2265,14 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo _ASSERTE(pCode != (PCODE)NULL); goto Return; } -#endif +#endif // FEATURE_CODE_VERSIONING if (!IsPointingToPrestub()) { LOG((LF_CLASSLOADER, LL_INFO10000, " In PreStubWorker, method already jitted, backpatching call point\n")); - pCode = DoBackpatch(pMT, pDispatchingMT, TRUE); + pCode = DoBackpatch(pMT, pDispatchingMT, true /* doFullBackpatch */); goto Return; } @@ -2277,10 +2289,12 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo #endif // defined(FEATURE_SHARE_GENERIC_CODE) else if (IsIL() || IsNoMetadata()) { +#ifndef FEATURE_PORTABLE_ENTRYPOINTS if (!IsNativeCodeStableAfterInit()) { GetOrCreatePrecode(); } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS pCode = PrepareInitialCode(callerGCMode); } // end else if (IsIL() || IsNoMetadata()) else if (IsPInvoke()) @@ -2418,7 +2432,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo _ASSERTE(!IsPointingToPrestub()); _ASSERTE(HasStableEntryPoint()); - pCode = DoBackpatch(pMT, pDispatchingMT, FALSE); + pCode = DoBackpatch(pMT, pDispatchingMT, false /* doFullBackpatch */); Return: // Interpreter-FIXME: Call stubs are not yet supported on WASM diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index c1ad32fdb03401..e9b57d15af94af 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -2535,6 +2535,7 @@ HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId, if (SUCCEEDED(hr)) { PCODE pCodeStart = (PCODE)NULL; +#ifdef FEATURE_CODE_VERSIONING CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager(); { ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMethodDesc, reJitId); @@ -2549,6 +2550,7 @@ HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId, break; } } +#endif // FEATURE_CODE_VERSIONING hr = GetCodeInfoFromCodeStart(pCodeStart, cCodeInfos, @@ -4919,6 +4921,7 @@ HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId, else { PCODE pCodeStart = (PCODE)NULL; +#ifdef FEATURE_CODE_VERSIONING CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager(); ILCodeVersion ilCodeVersion = NULL; { @@ -4934,6 +4937,7 @@ HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId, break; } } +#endif // FEATURE_CODE_VERSIONING hr = GetILToNativeMapping3(pCodeStart, cMap, pcMap, map); } @@ -6439,6 +6443,7 @@ HRESULT ProfToEEInterfaceImpl::GetNativeCodeStartAddresses(FunctionID functionID ULONG32 trueLen = 0; StackSArray addresses; +#ifdef FEATURE_CODE_VERSIONING CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager(); ILCodeVersion ilCodeVersion = NULL; @@ -6459,6 +6464,7 @@ HRESULT ProfToEEInterfaceImpl::GetNativeCodeStartAddresses(FunctionID functionID } } } +#endif // FEATURE_CODE_VERSIONING if (pcCodeStartAddresses != NULL) { diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index f225baea1cba9f..5b5cd3908ccb35 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -971,6 +971,7 @@ BOOL ThePreStubManager::CheckIsStub_Internal(PCODE stubStartAddress) // Stub manager functions & globals // ------------------------------------------------------- +#ifndef FEATURE_PORTABLE_ENTRYPOINTS SPTR_IMPL(PrecodeStubManager, PrecodeStubManager, g_pManager); #ifndef DACCESS_COMPILE @@ -1159,6 +1160,7 @@ BOOL PrecodeStubManager::TraceManager(Thread *thread, return FALSE; } #endif +#endif // !FEATURE_PORTABLE_ENTRYPOINTS // ------------------------------------------------------- // StubLinkStubManager @@ -2146,6 +2148,7 @@ BOOL TailCallStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestination * #ifdef DACCESS_COMPILE +#ifndef FEATURE_PORTABLE_ENTRYPOINTS void PrecodeStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) { @@ -2154,6 +2157,7 @@ PrecodeStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) DAC_ENUM_VTHIS(); EMEM_OUT(("MEM: %p PrecodeStubManager\n", dac_cast(this))); } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS void StubLinkStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) diff --git a/src/coreclr/vm/stubmgr.h b/src/coreclr/vm/stubmgr.h index d1a71ca46f83db..c5d9495dff5bcd 100644 --- a/src/coreclr/vm/stubmgr.h +++ b/src/coreclr/vm/stubmgr.h @@ -392,6 +392,7 @@ class ThePreStubManager : public StubManager // frame-pushing, StubLinker created stubs // ------------------------------------------------------- +#ifndef FEATURE_PORTABLE_ENTRYPOINTS typedef VPTR(class PrecodeStubManager) PTR_PrecodeStubManager; class PrecodeStubManager : public StubManager @@ -434,6 +435,7 @@ class PrecodeStubManager : public StubManager { LIMITED_METHOD_CONTRACT; return W("MethodDescPrestub"); } #endif }; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS // Note that this stub was written by a debugger guy, and thus when he refers to 'multicast' // stub, he really means multi or single cast stub. This was done b/c the same stub From 5288fdfc3e42a2f8db74a7649fda2514e11b5c75 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 10 Oct 2025 10:06:01 -0700 Subject: [PATCH 02/15] Feedback - part1 --- src/coreclr/vm/ceeload.cpp | 43 +++++++++++++----------------- src/coreclr/vm/ceeload.h | 12 ++++----- src/coreclr/vm/dllimport.cpp | 2 +- src/coreclr/vm/dllimportcallback.h | 8 +++--- src/coreclr/vm/jitinterface.cpp | 11 ++++---- 5 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 9ba258b07be214..9243a05061b172 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -1319,12 +1319,12 @@ void Module::AllocateMaps() m_TypeRefToMethodTableMap.dwCount = TYPEREF_MAP_INITIAL_SIZE; m_MemberRefMap.dwCount = MEMBERREF_MAP_INITIAL_SIZE; m_MethodDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE; -#ifdef FEATURE_CODE_VERSIONING - m_ILCodeVersioningStateMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE; -#endif // FEATURE_CODE_VERSIONING m_FieldDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE; m_GenericParamToDescMap.dwCount = GENERICPARAM_MAP_INITIAL_SIZE; m_ManifestModuleReferencesMap.dwCount = ASSEMBLYREFERENCES_MAP_INITIAL_SIZE; +#ifdef FEATURE_CODE_VERSIONING + m_ILCodeVersioningStateMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE; +#endif // FEATURE_CODE_VERSIONING } else { @@ -1342,11 +1342,6 @@ void Module::AllocateMaps() // Get # MethodDefs m_MethodDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtMethodDef)+1; -#ifdef FEATURE_CODE_VERSIONING - // IL code versions are relatively rare so keep small. - m_ILCodeVersioningStateMap.dwCount = 1; -#endif // FEATURE_CODE_VERSIONING - // Get # FieldDefs m_FieldDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtFieldDef)+1; @@ -1355,6 +1350,11 @@ void Module::AllocateMaps() // Get the number of AssemblyReferences in the map m_ManifestModuleReferencesMap.dwCount = pImport->GetCountWithTokenKind(mdtAssemblyRef)+1; + +#ifdef FEATURE_CODE_VERSIONING + // IL code versions are relatively rare so keep small. + m_ILCodeVersioningStateMap.dwCount = 1; +#endif // FEATURE_CODE_VERSIONING } S_SIZE_T nTotal; @@ -1363,12 +1363,12 @@ void Module::AllocateMaps() nTotal += m_TypeRefToMethodTableMap.dwCount; nTotal += m_MemberRefMap.dwCount; nTotal += m_MethodDefToDescMap.dwCount; -#ifdef FEATURE_CODE_VERSIONING - nTotal += m_ILCodeVersioningStateMap.dwCount; -#endif // FEATURE_CODE_VERSIONING nTotal += m_FieldDefToDescMap.dwCount; nTotal += m_GenericParamToDescMap.dwCount; nTotal += m_ManifestModuleReferencesMap.dwCount; +#ifdef FEATURE_CODE_VERSIONING + nTotal += m_ILCodeVersioningStateMap.dwCount; +#endif // FEATURE_CODE_VERSIONING _ASSERTE (m_pAssembly && m_pAssembly->GetLowFrequencyHeap()); pTable = (PTR_TADDR)(void*)m_pAssembly->GetLowFrequencyHeap()->AllocMem(nTotal * S_SIZE_T(sizeof(TADDR))); @@ -1382,7 +1382,7 @@ void Module::AllocateMaps() m_TypeRefToMethodTableMap.pNext = NULL; m_TypeRefToMethodTableMap.supportedFlags = TYPE_REF_MAP_ALL_FLAGS; - m_TypeRefToMethodTableMap.pTable = &pTable[m_TypeDefToMethodTableMap.dwCount]; + m_TypeRefToMethodTableMap.pTable = &m_TypeDefToMethodTableMap.pTable[m_TypeDefToMethodTableMap.dwCount]; m_MemberRefMap.pNext = NULL; m_MemberRefMap.supportedFlags = MEMBER_REF_MAP_ALL_FLAGS; @@ -1392,20 +1392,9 @@ void Module::AllocateMaps() m_MethodDefToDescMap.supportedFlags = METHOD_DEF_MAP_ALL_FLAGS; m_MethodDefToDescMap.pTable = &m_MemberRefMap.pTable[m_MemberRefMap.dwCount]; -#ifdef FEATURE_CODE_VERSIONING - m_ILCodeVersioningStateMap.pNext = NULL; - m_ILCodeVersioningStateMap.supportedFlags = METHOD_DEF_MAP_ALL_FLAGS; - m_ILCodeVersioningStateMap.pTable = &m_MethodDefToDescMap.pTable[m_MethodDefToDescMap.dwCount]; -#endif // FEATURE_CODE_VERSIONING - m_FieldDefToDescMap.pNext = NULL; m_FieldDefToDescMap.supportedFlags = FIELD_DEF_MAP_ALL_FLAGS; - -#ifdef FEATURE_CODE_VERSIONING - m_FieldDefToDescMap.pTable = &m_ILCodeVersioningStateMap.pTable[m_ILCodeVersioningStateMap.dwCount]; -#else // !FEATURE_CODE_VERSIONING - m_FieldDefToDescMap.pTable = NULL; -#endif // FEATURE_CODE_VERSIONING + m_FieldDefToDescMap.pTable = &m_MethodDefToDescMap.pTable[m_MethodDefToDescMap.dwCount]; m_GenericParamToDescMap.pNext = NULL; m_GenericParamToDescMap.supportedFlags = GENERIC_PARAM_MAP_ALL_FLAGS; @@ -1414,6 +1403,12 @@ void Module::AllocateMaps() m_ManifestModuleReferencesMap.pNext = NULL; m_ManifestModuleReferencesMap.supportedFlags = MANIFEST_MODULE_MAP_ALL_FLAGS; m_ManifestModuleReferencesMap.pTable = &m_GenericParamToDescMap.pTable[m_GenericParamToDescMap.dwCount]; + +#ifdef FEATURE_CODE_VERSIONING + m_ILCodeVersioningStateMap.pNext = NULL; + m_ILCodeVersioningStateMap.supportedFlags = METHOD_DEF_MAP_ALL_FLAGS; + m_ILCodeVersioningStateMap.pTable = &m_ManifestModuleReferencesMap.pTable[m_ManifestModuleReferencesMap.dwCount]; +#endif // FEATURE_CODE_VERSIONING } diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 3171a83687c23e..39855e55cae7d2 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -740,18 +740,18 @@ class Module : public ModuleBase // For generic methods, IsGenericTypeDefinition() is true i.e. instantiation at formals LookupMap m_MethodDefToDescMap; -#ifdef FEATURE_CODE_VERSIONING - // Linear mapping from MethodDef token to ILCodeVersioningState * - // This is used for Code Versioning logic - LookupMap m_ILCodeVersioningStateMap; -#endif // FEATURE_CODE_VERSIONING - // Linear mapping from FieldDef token to FieldDesc* LookupMap m_FieldDefToDescMap; // Linear mapping from GenericParam token to TypeVarTypeDesc* LookupMap m_GenericParamToDescMap; +#ifdef FEATURE_CODE_VERSIONING + // Linear mapping from MethodDef token to ILCodeVersioningState * + // This is used for Code Versioning logic + LookupMap m_ILCodeVersioningStateMap; +#endif // FEATURE_CODE_VERSIONING + // IL stub cache with fabricated MethodTable parented by this module. ILStubCache *m_pILStubCache; diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 37b4eb3fdf14f0..1c43d927815938 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -5651,7 +5651,7 @@ PCODE PInvoke::GetStubForILStub(PInvokeMethodDesc* pNMD, MethodDesc** ppStubMD, CONSISTENCY_CHECK(pNMD->IsVarArgs()); #ifdef FEATURE_PORTABLE_ENTRYPOINTS - _ASSERTE(false && "Vararg P/Invoke is not supported with portable entrypoints"); + COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED); #else // !FEATURE_PORTABLE_ENTRYPOINTS // // varargs goes through vararg PInvoke stub diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h index 4c9785eed266a9..e548aa87e297ca 100644 --- a/src/coreclr/vm/dllimportcallback.h +++ b/src/coreclr/vm/dllimportcallback.h @@ -248,7 +248,7 @@ class UMEntryThunkData PCODE entryPoint = m_pUMThunkMarshInfo->GetExecStubEntryPoint(); bool nullEntryPoint; -#if defined(FEATURE_INTERPRETER) && !defined(FEATURE_PORTABLE_ENTRYPOINTS) +#if defined(FEATURE_INTERPRETER) // For interpreted stubs we need to ensure that TheUMEntryPrestubWorker runs for every // unmanaged-to-managed invocation in order to populate the TLS variable every time. auto stubKind = RangeSectionStubManager::GetStubKind(entryPoint); @@ -262,10 +262,10 @@ class UMEntryThunkData } } nullEntryPoint = entryPoint == (PCODE)0; -#else // !FEATURE_INTERPRETER || FEATURE_PORTABLE_ENTRYPOINTS - nullEntryPoint = false; +#else // !FEATURE_INTERPRETER _ASSERTE(entryPoint != (PCODE)0); -#endif // FEATURE_INTERPRETER && !FEATURE_PORTABLE_ENTRYPOINTS + nullEntryPoint = false; +#endif // FEATURE_INTERPRETER if (!nullEntryPoint) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index e99c360a8b9413..01c501cbc3e8a9 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9112,6 +9112,11 @@ void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd, JIT_TO_EE_TRANSITION(); +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + PORTABILITY_ASSERT("NYI: getFunctionEntryPoint for FEATURE_PORTABLE_ENTRYPOINTS"); + +#else // !FEATURE_PORTABLE_ENTRYPOINTS + MethodDesc * ftn = GetMethod(ftnHnd); #if defined(FEATURE_GDBJIT) MethodDesc * orig_ftn = ftn; @@ -9124,22 +9129,17 @@ void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd, { // FCalls can be called directly ret = (void*)ECall::GetFCallImpl(ftn, false /* throwForInvalidFCall */); -#ifndef FEATURE_PORTABLE_ENTRYPOINTS if (ret == NULL) { ret = ((FixupPrecode*)ftn->GetOrCreatePrecode())->GetTargetSlot(); accessType = IAT_PVALUE; } -#endif // !FEATURE_PORTABLE_ENTRYPOINTS - _ASSERTE(ret != NULL); } -#ifndef FEATURE_PORTABLE_ENTRYPOINTS else if (ftn->IsVersionableWithPrecode() && (ftn->GetPrecodeType() == PRECODE_FIXUP) && !ftn->IsPointingToStableNativeCode()) { ret = ((FixupPrecode*)ftn->GetOrCreatePrecode())->GetTargetSlot(); accessType = IAT_PVALUE; } -#endif // !FEATURE_PORTABLE_ENTRYPOINTS else { ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags); @@ -9160,6 +9160,7 @@ void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd, CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods); m_pCalledMethods = pCM; #endif +#endif // FEATURE_PORTABLE_ENTRYPOINTS EE_TO_JIT_TRANSITION(); From 662769a2c3d25a71fcf7d89ea76653bf42d6fb77 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 10 Oct 2025 13:31:15 -0700 Subject: [PATCH 03/15] Feedback part 2 --- src/coreclr/vm/assembly.cpp | 4 ++ src/coreclr/vm/assembly.hpp | 2 + src/coreclr/vm/ceeload.cpp | 9 +++-- src/coreclr/vm/ceeload.h | 2 + src/coreclr/vm/comdelegate.cpp | 15 ++++--- src/coreclr/vm/corelib.cpp | 1 + src/coreclr/vm/corhost.cpp | 10 +++-- src/coreclr/vm/dllimport.cpp | 10 +++++ src/coreclr/vm/dllimportcallback.cpp | 42 ++++++++++---------- src/coreclr/vm/dllimportcallback.h | 12 ++++-- src/coreclr/vm/interpexec.cpp | 8 ++-- src/coreclr/vm/jithelpers.cpp | 59 ++++++++++++++++------------ src/coreclr/vm/loaderallocator.cpp | 16 +++++--- src/coreclr/vm/loaderallocator.hpp | 2 + src/coreclr/vm/prestub.cpp | 7 +++- src/coreclr/vm/qcallentrypoints.cpp | 1 + src/coreclr/vm/stubmgr.cpp | 5 +++ src/coreclr/vm/syncblk.cpp | 4 ++ src/coreclr/vm/syncblk.h | 14 +++++-- 19 files changed, 150 insertions(+), 73 deletions(-) diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index 7ec8d6b0db16e0..90f7b35c1aeafd 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -2127,9 +2127,11 @@ BOOL Assembly::DoIncrementalLoad(FileLoadLevel level) DeliverSyncEvents(); break; +#ifdef FEATURE_IJW case FILE_LOAD_VTABLE_FIXUPS: VtableFixups(); break; +#endif // FEATURE_IJW case FILE_LOADED: FinishLoad(); @@ -2206,12 +2208,14 @@ void Assembly::EagerFixups() #endif // FEATURE_READYTORUN } +#ifdef FEATURE_IJW void Assembly::VtableFixups() { WRAPPER_NO_CONTRACT; GetModule()->FixupVTables(); } +#endif // FEATURE_IJW void Assembly::FinishLoad() { diff --git a/src/coreclr/vm/assembly.hpp b/src/coreclr/vm/assembly.hpp index 9d6bf377e0c523..3edb4c0b3e1570 100644 --- a/src/coreclr/vm/assembly.hpp +++ b/src/coreclr/vm/assembly.hpp @@ -126,7 +126,9 @@ class Assembly void Begin(); void BeforeTypeLoad(); void EagerFixups(); +#ifdef FEATURE_IJW void VtableFixups(); +#endif // FEATURE_IJW void DeliverSyncEvents(); void DeliverAsyncEvents(); void FinishLoad(); diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 9243a05061b172..b0b0b61cee54f5 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -3145,16 +3145,18 @@ BYTE * GetTargetForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry) return *ppVTEntry; } +#ifdef FEATURE_IJW //====================================================================================== // Fixup vtables stored in the header to contain pointers to method desc // prestubs rather than metadata method tokens. void Module::FixupVTables() { - CONTRACTL{ + CONTRACTL + { INSTANCE_CHECK; STANDARD_VM_CHECK; - } CONTRACTL_END; - + } + CONTRACTL_END; // If we've already fixed up, or this is not an IJW module, just return. // NOTE: This relies on ILOnly files not having fixups. If this changes, @@ -3414,6 +3416,7 @@ void Module::FixupVTables() SetIsIJWFixedUp(); // On the module } // End of Stage 3 } +#endif // FEATURE_IJW ModuleBase *Module::GetModuleFromIndex(DWORD ix) { diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 39855e55cae7d2..f3db489f9e52dc 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -873,7 +873,9 @@ class Module : public ModuleBase void ApplyMetaData(); +#ifdef FEATURE_IJW void FixupVTables(); +#endif // FEATURE_IJW void FreeClassTables(); diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index fd5fae87439767..339161d0f6e9ca 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -1344,6 +1344,10 @@ LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj) } else { +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + COMPlusThrow(kNotSupportedException); + +#else // !FEATURE_PORTABLE_ENTRYPOINTS UMEntryThunkData* pUMEntryThunk = NULL; SyncBlock* pSyncBlock = pDelegate->GetSyncBlock(); @@ -1407,6 +1411,7 @@ LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj) } pCode = (PCODE)pUMEntryThunk->GetCode(); +#endif // !FEATURE_PORTABLE_ENTRYPOINTS } GCPROTECT_END(); @@ -1431,9 +1436,9 @@ OBJECTREF COMDelegate::ConvertToDelegate(LPVOID pCallback, MethodTable* pMT) // Check if this callback was originally a managed method passed out to unmanaged code. // +#ifndef FEATURE_PORTABLE_ENTRYPOINTS UMEntryThunk* pUMEntryThunk = NULL; -#ifndef FEATURE_PORTABLE_ENTRYPOINTS auto stubKind = RangeSectionStubManager::GetStubKind((PCODE)pCallback); if (stubKind == STUB_CODE_BLOCK_STUBPRECODE) { @@ -1443,20 +1448,20 @@ OBJECTREF COMDelegate::ConvertToDelegate(LPVOID pCallback, MethodTable* pMT) pUMEntryThunk = pPrecode->AsUMEntryThunk(); } } -#endif // !FEATURE_PORTABLE_ENTRYPOINTS // Lookup the callsite in the hash, if found, we can map this call back to its managed function. // Otherwise, we'll treat this as an unmanaged callsite. // Make sure that the pointer doesn't have the value of 1 which is our hash table deleted item marker. - OBJECTHANDLE DelegateHnd = (pUMEntryThunk != NULL) + OBJECTHANDLE delegateHnd = (pUMEntryThunk != NULL) ? pUMEntryThunk->GetData()->GetObjectHandle() : (OBJECTHANDLE)NULL; - if (DelegateHnd != (OBJECTHANDLE)NULL) + if (delegateHnd != (OBJECTHANDLE)NULL) { // Found a managed callsite - return ObjectFromHandle(DelegateHnd); + return ObjectFromHandle(delegateHnd); } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS // Validate the MethodTable is a delegate type // See Marshal.GetDelegateForFunctionPointer() for exception details. diff --git a/src/coreclr/vm/corelib.cpp b/src/coreclr/vm/corelib.cpp index 75f5dd62da82ea..9e89019b200780 100644 --- a/src/coreclr/vm/corelib.cpp +++ b/src/coreclr/vm/corelib.cpp @@ -14,6 +14,7 @@ // #include "arraynative.h" #include "objectnative.h" +#include "dllimport.h" #include "comdelegate.h" #include "customattribute.h" #include "comdynamic.h" diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp index a2369f89695cfe..4f1c5afdd4bc1b 100644 --- a/src/coreclr/vm/corhost.cpp +++ b/src/coreclr/vm/corhost.cpp @@ -682,7 +682,6 @@ HRESULT CorHost2::CreateDelegate( LPCWSTR wszMethodName, INT_PTR* fnPtr) { - CONTRACTL { NOTHROW; @@ -691,8 +690,6 @@ HRESULT CorHost2::CreateDelegate( } CONTRACTL_END; - HRESULT hr=S_OK; - EMPTY_STRING_TO_NULL(wszAssemblyName); EMPTY_STRING_TO_NULL(wszClassName); EMPTY_STRING_TO_NULL(wszMethodName); @@ -714,7 +711,13 @@ HRESULT CorHost2::CreateDelegate( if (appDomainID != DefaultADID) return HOST_E_INVALIDOPERATION; + HRESULT hr = S_OK; BEGIN_EXTERNAL_ENTRYPOINT(&hr); + +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + hr = E_NOTIMPL; + +#else // !FEATURE_PORTABLE_ENTRYPOINTS GCX_COOP_THREAD_EXISTS(GET_THREAD()); MAKE_UTF8PTR_FROMWIDE(szClassName, wszClassName); @@ -759,6 +762,7 @@ HRESULT CorHost2::CreateDelegate( *fnPtr = (INT_PTR)pUMEntryThunk->GetCode(); } } +#endif // FEATURE_PORTABLE_ENTRYPOINTS END_EXTERNAL_ENTRYPOINT; diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 1c43d927815938..c15d7de00d239a 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -2014,6 +2014,10 @@ void PInvokeStubLinker::Begin(DWORD dwStubFlags) { if (SF_IsDelegateStub(dwStubFlags)) { +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + COMPlusThrow(kNotSupportedException); + +#else // !FEATURE_PORTABLE_ENTRYPOINTS // // recover delegate object from UMEntryThunk @@ -2024,6 +2028,7 @@ void PInvokeStubLinker::Begin(DWORD dwStubFlags) m_pcsDispatch->EmitLDIND_I(); // get OBJECTHANDLE m_pcsDispatch->EmitLDIND_REF(); // get Delegate object m_pcsDispatch->EmitLDFLD(GetToken(CoreLibBinder::GetField(FIELD__DELEGATE__TARGET))); +#endif // FEATURE_PORTABLE_ENTRYPOINTS } } @@ -2186,6 +2191,10 @@ void PInvokeStubLinker::DoPInvoke(ILCodeStream *pcsEmit, DWORD dwStubFlags, Meth } else // native-to-managed { +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + COMPlusThrow(kNotSupportedException); + +#else // !FEATURE_PORTABLE_ENTRYPOINTS if (SF_IsDelegateStub(dwStubFlags)) // reverse P/Invoke via delegate { int tokDelegate_methodPtr = pcsEmit->GetToken(CoreLibBinder::GetField(FIELD__DELEGATE__METHOD_PTR)); @@ -2212,6 +2221,7 @@ void PInvokeStubLinker::DoPInvoke(ILCodeStream *pcsEmit, DWORD dwStubFlags, Meth // pcsEmit->EmitADD(); pcsEmit->EmitLDIND_I(); // Get UMEntryThunk::m_pManagedTarget } +#endif // FEATURE_PORTABLE_ENTRYPOINTS } // For managed-to-native calls, the rest of the work is done by the JIT. It will diff --git a/src/coreclr/vm/dllimportcallback.cpp b/src/coreclr/vm/dllimportcallback.cpp index 341a538e9fd185..b873cd4d968a9b 100644 --- a/src/coreclr/vm/dllimportcallback.cpp +++ b/src/coreclr/vm/dllimportcallback.cpp @@ -4,8 +4,7 @@ // File: DllImportCallback.cpp // -// - +#ifndef FEATURE_PORTABLE_ENTRYPOINTS #include "common.h" @@ -164,20 +163,6 @@ UMEntryThunkData *UMEntryThunkCache::GetUMEntryThunk(MethodDesc *pMD) RETURN pThunk; } -// FailFast if a method marked UnmanagedCallersOnlyAttribute is -// invoked directly from managed code. UMThunkStub.asm check the -// mode and call this function to failfast. -extern "C" VOID STDCALL ReversePInvokeBadTransition() -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - // Fail - EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE( - COR_E_EXECUTIONENGINE, - W("Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code.") - ); -} - //------------------------------------------------------------------------- // This function is used to report error when we call collected delegate. // But memory that was allocated for thunk can be reused, due to it this @@ -210,20 +195,20 @@ VOID CallbackOnCollectedDelegate(UMEntryThunkData* pEntryThunkData) EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_FAILFAST, message.GetUnicode()); } -#ifdef FEATURE_INTERPRETER +#if defined(FEATURE_INTERPRETER) PLATFORM_THREAD_LOCAL UMEntryThunkData * t_MostRecentUMEntryThunkData; -UMEntryThunkData * GetMostRecentUMEntryThunkData() +UMEntryThunkData* GetMostRecentUMEntryThunkData() { LIMITED_METHOD_CONTRACT; - UMEntryThunkData * result = t_MostRecentUMEntryThunkData; + UMEntryThunkData* result = t_MostRecentUMEntryThunkData; t_MostRecentUMEntryThunkData = nullptr; return result; } -#endif +#endif // FEATURE_INTERPRETER -PCODE TheUMEntryPrestubWorker(UMEntryThunkData * pUMEntryThunkData) +PCODE TheUMEntryPrestubWorker(UMEntryThunkData* pUMEntryThunkData) { STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_TRIGGERS; @@ -449,3 +434,18 @@ VOID UMThunkMarshInfo::RunTimeInit() // Must be the last thing we set! InterlockedCompareExchangeT(&m_pILStub, pFinalILStub, (PCODE)1); } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS + +// FailFast if a method marked UnmanagedCallersOnlyAttribute is +// invoked directly from managed code. UMThunkStub.asm check the +// mode and call this function to failfast. +VOID STDCALL ReversePInvokeBadTransition() +{ + STATIC_CONTRACT_THROWS; + STATIC_CONTRACT_GC_TRIGGERS; + // Fail + EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE( + COR_E_EXECUTIONENGINE, + W("Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code.") + ); +} diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h index e548aa87e297ca..f2297358192024 100644 --- a/src/coreclr/vm/dllimportcallback.h +++ b/src/coreclr/vm/dllimportcallback.h @@ -4,12 +4,11 @@ // File: DllImportCallback.h // -// - - #ifndef __dllimportcallback_h__ #define __dllimportcallback_h__ +#ifndef FEATURE_PORTABLE_ENTRYPOINTS + #include "object.h" #include "stublink.h" #include "ceeload.h" @@ -428,4 +427,11 @@ EXCEPTION_HANDLER_DECL(FastNExportExceptHandler); extern "C" void TheUMEntryPrestub(void); extern "C" PCODE TheUMEntryPrestubWorker(UMEntryThunkData * pUMEntryThunk); +#if defined(FEATURE_INTERPRETER) +UMEntryThunkData* GetMostRecentUMEntryThunkData(); +#endif // FEATURE_INTERPRETER +#endif // !FEATURE_PORTABLE_ENTRYPOINTS + +VOID STDCALL ReversePInvokeBadTransition(); + #endif //__dllimportcallback_h__ diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index baaf5990da7b74..392e8b7dc7dd01 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -714,8 +714,6 @@ static void CallPreStub(MethodDesc *pMD) PAL_ENDTRY } -UMEntryThunkData * GetMostRecentUMEntryThunkData(); - void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFrame *pFrame, InterpThreadContext *pThreadContext, ExceptionClauseArgs *pExceptionClauseArgs) { CONTRACTL @@ -801,10 +799,14 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr break; case INTOP_STORESTUBCONTEXT: { - void *thunkData = GetMostRecentUMEntryThunkData(); +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + COMPlusThrow(kNotSupportedException); +#else // !FEATURE_PORTABLE_ENTRYPOINTS + UMEntryThunkData* thunkData = GetMostRecentUMEntryThunkData(); assert(thunkData); LOCAL_VAR(ip[1], void*) = thunkData; ip += 2; +#endif // FEATURE_PORTABLE_ENTRYPOINTS break; } case INTOP_LDC_I4: diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 58b418fe5fb309..8ef1b29284f416 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2295,15 +2295,35 @@ Thread * JIT_InitPInvokeFrame(InlinedCallFrame *pFrame) EXTERN_C void JIT_PInvokeBegin(InlinedCallFrame* pFrame); EXTERN_C void JIT_PInvokeEnd(InlinedCallFrame* pFrame); -// Forward declaration -EXTERN_C void STDCALL ReversePInvokeBadTransition(); - #ifndef FEATURE_EH_FUNCLETS EXCEPTION_HANDLER_DECL(FastNExportExceptHandler); #endif +#ifdef DEBUGGING_SUPPORTED +static void DebuggerTraceCall(void* returnAddr, void* thunkDataMaybe) +{ + _ASSERTE(CORDebuggerTraceCall()); + _ASSERTE(returnAddr != NULL); + + const BYTE* addr; +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + addr = (const BYTE*)returnAddr; + _ASSERTE(thunkDataMaybe == NULL); // Should not be used with portable entrypoints +#else // !FEATURE_PORTABLE_ENTRYPOINTS + addr = (thunkDataMaybe != NULL) ? (const BYTE*)((UMEntryThunkData*)thunkDataMaybe)->GetManagedTarget() : (const BYTE*)returnAddr; +#endif // FEATURE_PORTABLE_ENTRYPOINTS + + // If the debugger is attached, we use this opportunity to see if + // we're disabling preemptive GC on the way into the runtime from + // unmanaged code. We end up here because + // Increment/DecrementTraceCallCount() will bump + // g_TrapReturningThreads for us. + g_pDebugInterface->TraceCall(addr); +} +#endif // DEBUGGING_SUPPORTED + // This is a slower version of the reverse PInvoke enter function. -NOINLINE static void JIT_ReversePInvokeEnterRare(ReversePInvokeFrame* frame, void* returnAddr, UMEntryThunkData* pUMEntryThunkData = NULL) +NOINLINE static void JIT_ReversePInvokeEnterRare(ReversePInvokeFrame* frame, void* returnAddr, void* thunkDataMaybe = NULL) { _ASSERTE(frame != NULL); @@ -2326,27 +2346,17 @@ NOINLINE static void JIT_ReversePInvokeEnterRare(ReversePInvokeFrame* frame, voi thread->DisablePreemptiveGC(); #ifdef DEBUGGING_SUPPORTED - // If the debugger is attached, we use this opportunity to see if - // we're disabling preemptive GC on the way into the runtime from - // unmanaged code. We end up here because - // Increment/DecrementTraceCallCount() will bump - // g_TrapReturningThreads for us. if (CORDebuggerTraceCall()) - g_pDebugInterface->TraceCall(pUMEntryThunkData ? (const BYTE*)pUMEntryThunkData->GetManagedTarget() : (const BYTE*)returnAddr); + DebuggerTraceCall(returnAddr, thunkDataMaybe); #endif // DEBUGGING_SUPPORTED } -NOINLINE static void JIT_ReversePInvokeEnterRare2(ReversePInvokeFrame* frame, void* returnAddr, UMEntryThunkData* pUMEntryThunkData = NULL) +NOINLINE static void JIT_ReversePInvokeEnterRare2(ReversePInvokeFrame* frame, void* returnAddr, void* thunkDataMaybe = NULL) { frame->currentThread->RareDisablePreemptiveGC(); #ifdef DEBUGGING_SUPPORTED - // If the debugger is attached, we use this opportunity to see if - // we're disabling preemptive GC on the way into the runtime from - // unmanaged code. We end up here because - // Increment/DecrementTraceCallCount() will bump - // g_TrapReturningThreads for us. if (CORDebuggerTraceCall()) - g_pDebugInterface->TraceCall(pUMEntryThunkData ? (const BYTE*)pUMEntryThunkData->GetManagedTarget() : (const BYTE*)returnAddr); + DebuggerTraceCall(returnAddr, thunkDataMaybe); #endif // DEBUGGING_SUPPORTED } @@ -2355,15 +2365,14 @@ NOINLINE static void JIT_ReversePInvokeEnterRare2(ReversePInvokeFrame* frame, vo // We may not have a managed thread set up in JIT_ReversePInvokeEnter, and the GC mode may be incorrect. // On x86, SEH handlers are set up and torn down explicitly, so we avoid using dynamic contracts. // This method uses the correct calling convention and argument layout manually, without relying on standard macros or contracts. -HCIMPL3_RAW(void, JIT_ReversePInvokeEnterTrackTransitions, ReversePInvokeFrame* frame, MethodDesc* pMD, UMEntryThunkData* pUMEntryThunkData) +HCIMPL3_RAW(void, JIT_ReversePInvokeEnterTrackTransitions, ReversePInvokeFrame* frame, MethodDesc* pMD, void* thunkDataMaybe) { _ASSERTE(frame != NULL && pMD != NULL); - _ASSERTE(!pMD->IsILStub() || pUMEntryThunkData != NULL); + _ASSERTE(!pMD->IsILStub() || thunkDataMaybe != NULL); - if (pUMEntryThunkData != NULL) - { - pMD = pUMEntryThunkData->GetMethod(); - } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS + pMD = (thunkDataMaybe != NULL) ? ((UMEntryThunkData*)thunkDataMaybe)->GetMethod() : pMD; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS frame->pMD = pMD; Thread* thread = GetThreadNULLOk(); @@ -2388,14 +2397,14 @@ HCIMPL3_RAW(void, JIT_ReversePInvokeEnterTrackTransitions, ReversePInvokeFrame* { // If we're in an IL stub, we want to trace the address of the target method, // not the next instruction in the stub. - JIT_ReversePInvokeEnterRare2(frame, _ReturnAddress(), pUMEntryThunkData); + JIT_ReversePInvokeEnterRare2(frame, _ReturnAddress(), thunkDataMaybe); } } else { // If we're in an IL stub, we want to trace the address of the target method, // not the next instruction in the stub. - JIT_ReversePInvokeEnterRare(frame, _ReturnAddress(), pUMEntryThunkData); + JIT_ReversePInvokeEnterRare(frame, _ReturnAddress(), thunkDataMaybe); } #if defined(TARGET_X86) && defined(TARGET_WINDOWS) diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index f33bd9de06e62e..14fbb00a8d744f 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -83,15 +83,17 @@ LoaderAllocator::LoaderAllocator(bool collectible) : #ifdef FEATURE_COMINTEROP m_pComCallWrapperCache = NULL; -#endif +#endif // FEATURE_COMINTEROP +#ifndef FEATURE_PORTABLE_ENTRYPOINTS m_pUMEntryThunkCache = NULL; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS m_nLoaderAllocator = InterlockedIncrement64((LONGLONG *)&LoaderAllocator::cLoaderAllocatorsCreated); #ifdef FEATURE_PGO m_pgoManager = NULL; -#endif +#endif // FEATURE_PGO } LoaderAllocator::~LoaderAllocator() @@ -1384,14 +1386,16 @@ void LoaderAllocator::Terminate() m_fGCPressure = false; } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS delete m_pUMEntryThunkCache; m_pUMEntryThunkCache = NULL; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS m_crstLoaderAllocator.Destroy(); #ifdef FEATURE_COMINTEROP m_ComCallWrapperCrst.Destroy(); m_InteropDataCrst.Destroy(); -#endif +#endif // FEATURE_COMINTEROP m_LoaderAllocatorReferences.RemoveAll(); #ifdef FEATURE_TIERED_COMPILATION @@ -1400,7 +1404,7 @@ void LoaderAllocator::Terminate() delete m_callCountingManager; m_callCountingManager = NULL; } -#endif +#endif // FEATURE_TIERED_COMPILATION #ifdef FEATURE_ON_STACK_REPLACEMENT if (m_onStackReplacementManager != NULL) @@ -1408,7 +1412,7 @@ void LoaderAllocator::Terminate() delete m_onStackReplacementManager; m_onStackReplacementManager = NULL; } -#endif +#endif // FEATURE_ON_STACK_REPLACEMENT // In collectible types we merge the low frequency and high frequency heaps // So don't destroy them twice. @@ -2153,6 +2157,7 @@ ComCallWrapperCache * LoaderAllocator::GetComCallWrapperCache() } #endif // FEATURE_COMINTEROP +#ifndef FEATURE_PORTABLE_ENTRYPOINTS // U->M thunks created in this LoaderAllocator and not associated with a delegate. UMEntryThunkCache *LoaderAllocator::GetUMEntryThunkCache() { @@ -2178,6 +2183,7 @@ UMEntryThunkCache *LoaderAllocator::GetUMEntryThunkCache() _ASSERTE(m_pUMEntryThunkCache); return m_pUMEntryThunkCache; } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS /* static */ void LoaderAllocator::RemoveMemoryToLoaderAllocatorAssociation(LoaderAllocator* pLoaderAllocator) diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index eaf327588f9a99..41ca855f87e186 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -364,9 +364,11 @@ class LoaderAllocator BYTE * m_pVSDHeapInitialAlloc; BYTE * m_pCodeHeapInitialAlloc; +#ifndef FEATURE_PORTABLE_ENTRYPOINTS // U->M thunks that are not associated with a delegate. // The cache is keyed by MethodDesc pointers. UMEntryThunkCache * m_pUMEntryThunkCache; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS // IL stub cache with fabricated MethodTable parented by a random module in this LoaderAllocator. ILStubCache m_ILStubCache; diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 36557ae4e223a4..5e1f7f89a6978e 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2039,8 +2039,6 @@ static InterpThreadContext* GetInterpThreadContext() return threadContext; } -EXTERN_C void STDCALL ReversePInvokeBadTransition(); - extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, void* retBuff) { // Argument registers are in the TransitionBlock @@ -2481,7 +2479,12 @@ PCODE TheUMThunkPreStub() { LIMITED_METHOD_CONTRACT; +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + PORTABILITY_ASSERT("TheUMThunkPreStub not supported with FEATURE_PORTABLE_ENTRYPOINTS"); + return (PCODE)0; +#else // !FEATURE_PORTABLE_ENTRYPOINTS return GetEEFuncEntryPoint(TheUMEntryPrestub); +#endif // FEATURE_PORTABLE_ENTRYPOINTS } PCODE TheVarargPInvokeStub(BOOL hasRetBuffArg) diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 256182b0c1aac6..11e57f6663e15c 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -9,6 +9,7 @@ // #include "arraynative.h" #include "objectnative.h" +#include "dllimport.h" #include "comdelegate.h" #include "customattribute.h" #include "comdynamic.h" diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 5b5cd3908ccb35..0904b2f502e9cf 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1739,6 +1739,10 @@ BOOL ILStubManager::TraceManager(Thread *thread, } else if (pStubMD->IsReverseStub()) { +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + PORTABILITY_ASSERT("NYI: Reverse P/Invoke stubs with FEATURE_PORTABLE_ENTRYPOINTS."); + return FALSE; +#else // !FEATURE_PORTABLE_ENTRYPOINTS if (pStubMD->IsStatic()) { // This is reverse P/Invoke stub, the argument is UMEntryThunkData @@ -1753,6 +1757,7 @@ BOOL ILStubManager::TraceManager(Thread *thread, LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: COM-to-CLR case %p\n", target)); } trace->InitForManaged(target); +#endif // FEATURE_PORTABLE_ENTRYPOINTS } else if (pStubMD->IsPInvokeDelegateStub()) { diff --git a/src/coreclr/vm/syncblk.cpp b/src/coreclr/vm/syncblk.cpp index 55c7f39fe48904..c47011789f3e29 100644 --- a/src/coreclr/vm/syncblk.cpp +++ b/src/coreclr/vm/syncblk.cpp @@ -64,9 +64,12 @@ InteropSyncBlockInfo::~InteropSyncBlockInfo() } CONTRACTL_END; +#ifndef FEATURE_PORTABLE_ENTRYPOINTS FreeUMEntryThunk(); +#endif // !FEATURE_PORTABLE_ENTRYPOINTS } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS void InteropSyncBlockInfo::FreeUMEntryThunk() { CONTRACTL @@ -85,6 +88,7 @@ void InteropSyncBlockInfo::FreeUMEntryThunk() m_pUMEntryThunk = NULL; } } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS #ifdef FEATURE_COMINTEROP // Returns either NULL or an RCW on which AcquireLock has been called. diff --git a/src/coreclr/vm/syncblk.h b/src/coreclr/vm/syncblk.h index 0e24261dd5be7b..31cf1809998765 100644 --- a/src/coreclr/vm/syncblk.h +++ b/src/coreclr/vm/syncblk.h @@ -602,7 +602,10 @@ class AwareLock } }; +#ifndef FEATURE_PORTABLE_ENTRYPOINTS class UMEntryThunkData; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS + #ifdef FEATURE_COMINTEROP class ComCallWrapper; class ComClassFactory; @@ -733,7 +736,7 @@ class InteropSyncBlockInfo #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION #endif // FEATURE_COMINTEROP -#if !defined(DACCESS_COMPILE) +#if !defined(DACCESS_COMPILE) && !defined(FEATURE_PORTABLE_ENTRYPOINTS) // set m_pUMEntryThunk if not already set - return true if not already set bool SetUMEntryThunk(UMEntryThunkData* pUMEntryThunk) { @@ -744,19 +747,24 @@ class InteropSyncBlockInfo } void FreeUMEntryThunk(); +#endif // !DACCESS_COMPILE && !FEATURE_PORTABLE_ENTRYPOINTS -#endif // DACCESS_COMPILE - +#ifndef FEATURE_PORTABLE_ENTRYPOINTS UMEntryThunkData* GetUMEntryThunk() { LIMITED_METHOD_CONTRACT; return m_pUMEntryThunk; } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS private: +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + void* m_pUMEntryThunk; // Dummy field +#else // !FEATURE_PORTABLE_ENTRYPOINTS // If this is a delegate marshalled out to unmanaged code, this points // to the thunk generated for unmanaged code to call back on. UMEntryThunkData* m_pUMEntryThunk; +#endif // FEATURE_PORTABLE_ENTRYPOINTS #ifdef FEATURE_COMINTEROP // If this object is being exposed to COM, it will have an associated CCW object From 30e10338ae54e7f2b5209d81457666c210896ecb Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 10 Oct 2025 14:06:25 -0700 Subject: [PATCH 04/15] Remove unused declarations in precode_portable.hpp --- src/coreclr/vm/codeman.cpp | 6 +- src/coreclr/vm/precode_portable.cpp | 95 ----------------------------- src/coreclr/vm/precode_portable.hpp | 42 ------------- 3 files changed, 3 insertions(+), 140 deletions(-) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index fae188a904282d..643b2f41d12017 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -3407,7 +3407,7 @@ TypeHandle InterpreterJitManager::ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClau _ASSERTE(!declaringType.IsNull()); SigTypeContext typeContext(pMD, declaringType); - + Module* pModule = pMD->GetModule(); thResolved = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, pEHClause->ClassToken, &typeContext, @@ -5127,7 +5127,7 @@ MethodDesc * ExecutionManager::GetCodeMethodDesc(PCODE currentPC) CONTRACTL_END ExecutionManager::ScanFlag scanFlag = ExecutionManager::GetScanFlags(); -#ifdef FEATURE_INTERPRETER +#if defined(FEATURE_INTERPRETER) && !defined(FEATURE_PORTABLE_ENTRYPOINTS) RangeSection * pRS = ExecutionManager::FindCodeRange(currentPC, scanFlag); if (pRS == NULL) return NULL; @@ -5143,7 +5143,7 @@ MethodDesc * ExecutionManager::GetCodeMethodDesc(PCODE currentPC) } } } -#endif // FEATURE_INTERPRETER +#endif // FEATURE_INTERPRETER && !FEATURE_PORTABLE_ENTRYPOINTS EECodeInfo codeInfo(currentPC, scanFlag); if (!codeInfo.IsValid()) diff --git a/src/coreclr/vm/precode_portable.cpp b/src/coreclr/vm/precode_portable.cpp index 04378748810f81..3ddac68386da64 100644 --- a/src/coreclr/vm/precode_portable.cpp +++ b/src/coreclr/vm/precode_portable.cpp @@ -109,53 +109,6 @@ void PortableEntryPoint::Init(void* nativeEntryPoint) InterleavedLoaderHeapConfig s_stubPrecodeHeapConfig; -void StubPrecode::Init(StubPrecode* pPrecodeRX, TADDR secretParam, LoaderAllocator *pLoaderAllocator, TADDR type, TADDR target) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"StubPrecode::Init is not supported with Portable EntryPoints"); -} - -BYTE StubPrecode::GetType() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"StubPrecode::GetType is not supported with Portable EntryPoints"); - return 0; -} - -void StubPrecode::SetTargetUnconditional(TADDR target) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"StubPrecode::SetTargetUnconditional is not supported with Portable EntryPoints"); -} - -TADDR StubPrecode::GetSecretParam() const -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"StubPrecode::GetSecretParam is not supported with Portable EntryPoints"); - return (TADDR)NULL; -} - -MethodDesc* StubPrecode::GetMethodDesc() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"StubPrecode::GetMethodDesc is not supported with Portable EntryPoints"); - return NULL; -} - -PCODE* FixupPrecode::GetTargetSlot() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"FixupPrecode::GetTargetSlot is not supported with Portable EntryPoints"); - return NULL; -} - -MethodDesc* FixupPrecode::GetMethodDesc() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"FixupPrecode::GetMethodDesc is not supported with Portable EntryPoints"); - return NULL; -} - Precode* Precode::Allocate(PrecodeType t, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker) { @@ -171,20 +124,6 @@ PrecodeType Precode::GetType() return (PrecodeType)0; } -UMEntryThunk* Precode::AsUMEntryThunk() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Precode::AsUMEntryThunk is not supported with Portable EntryPoints"); - return NULL; -} - -StubPrecode* Precode::AsStubPrecode() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Precode::AsStubPrecode is not supported with Portable EntryPoints"); - return NULL; -} - MethodDesc* Precode::GetMethodDesc(BOOL fSpeculative) { LIMITED_METHOD_CONTRACT; @@ -199,26 +138,6 @@ PCODE Precode::GetEntryPoint() return (PCODE)NULL; } -BOOL Precode::IsPointingToNativeCode(PCODE pNativeCode) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Precode::IsPointingToNativeCode is not supported with Portable EntryPoints"); - return FALSE; -} - -void Precode::Reset() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Precode::Reset is not supported with Portable EntryPoints"); -} - -PCODE Precode::GetTarget() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Precode::GetTarget is not supported with Portable EntryPoints"); - return (PCODE)NULL; -} - void Precode::ResetTargetInterlocked() { LIMITED_METHOD_CONTRACT; @@ -232,20 +151,6 @@ BOOL Precode::SetTargetInterlocked(PCODE target, BOOL fOnlyRedirectFromPrestub) return FALSE; } -BOOL Precode::IsPointingToPrestub() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Precode::IsPointingToPrestub is not supported with Portable EntryPoints"); - return FALSE; -} - -BOOL Precode::IsPointingToPrestub(PCODE target) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Precode::IsPointingToPrestub is not supported with Portable EntryPoints"); - return FALSE; -} - void FlushCacheForDynamicMappedStub(void* code, SIZE_T size) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/precode_portable.hpp b/src/coreclr/vm/precode_portable.hpp index aba0642a4d5229..0ec648b6b17ec4 100644 --- a/src/coreclr/vm/precode_portable.hpp +++ b/src/coreclr/vm/precode_portable.hpp @@ -78,36 +78,8 @@ enum PrecodeType class StubPrecode { -public: // static - static const BYTE Type = PRECODE_STUB; - -public: - void Init(StubPrecode* pPrecodeRX, TADDR secretParam, LoaderAllocator *pLoaderAllocator = NULL, TADDR type = StubPrecode::Type, TADDR target = 0); - - BYTE GetType(); - - void SetTargetUnconditional(TADDR target); - - TADDR GetSecretParam() const; - - MethodDesc* GetMethodDesc(); }; -typedef DPTR(StubPrecode) PTR_StubPrecode; - -class FixupPrecode final -{ -public: // static - static const int FixupCodeOffset = 0; - -public: - PCODE* GetTargetSlot(); - - MethodDesc* GetMethodDesc(); -}; - -class UMEntryThunk; - class Precode { public: // static @@ -117,27 +89,13 @@ class Precode public: PrecodeType GetType(); - UMEntryThunk* AsUMEntryThunk(); - - StubPrecode* AsStubPrecode(); - MethodDesc* GetMethodDesc(BOOL fSpeculative = FALSE); PCODE GetEntryPoint(); - BOOL IsPointingToNativeCode(PCODE pNativeCode); - - void Reset(); - - PCODE GetTarget(); - void ResetTargetInterlocked(); BOOL SetTargetInterlocked(PCODE target, BOOL fOnlyRedirectFromPrestub = TRUE); - - BOOL IsPointingToPrestub(); - - BOOL IsPointingToPrestub(PCODE target); }; void FlushCacheForDynamicMappedStub(void* code, SIZE_T size); From 47a9115593adcc067a00e2cf03df064c2828d45f Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 10 Oct 2025 14:14:26 -0700 Subject: [PATCH 05/15] Update incorrect comment --- src/coreclr/vm/comdelegate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 339161d0f6e9ca..5889d85084d9dd 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -1411,7 +1411,7 @@ LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj) } pCode = (PCODE)pUMEntryThunk->GetCode(); -#endif // !FEATURE_PORTABLE_ENTRYPOINTS +#endif // FEATURE_PORTABLE_ENTRYPOINTS } GCPROTECT_END(); From 06d2df3ab7f49560dd7abc228dd5621c9503a79f Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 10 Oct 2025 14:25:27 -0700 Subject: [PATCH 06/15] Remove enum value for vtable fixups. --- src/coreclr/vm/assemblyspec.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/vm/assemblyspec.hpp b/src/coreclr/vm/assemblyspec.hpp index 49446800fe7be2..8f21f9e010ed32 100644 --- a/src/coreclr/vm/assemblyspec.hpp +++ b/src/coreclr/vm/assemblyspec.hpp @@ -33,7 +33,9 @@ enum FileLoadLevel FILE_LOAD_BEFORE_TYPE_LOAD, FILE_LOAD_EAGER_FIXUPS, FILE_LOAD_DELIVER_EVENTS, +#ifdef FEATURE_IJW FILE_LOAD_VTABLE_FIXUPS, +#endif // FEATURE_IJW FILE_LOADED, // Loaded by not yet active FILE_ACTIVE // Fully active (constructors run & security checked) }; From d0b91684d592f4246f37ce469a2be126a425ab94 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 10 Oct 2025 16:11:44 -0700 Subject: [PATCH 07/15] Fix build --- src/coreclr/vm/codeversion.cpp | 2 +- src/coreclr/vm/codeversion.h | 6 +++--- src/coreclr/vm/method.hpp | 15 ++++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/coreclr/vm/codeversion.cpp b/src/coreclr/vm/codeversion.cpp index d1afe575a70c93..316376fe0bb918 100644 --- a/src/coreclr/vm/codeversion.cpp +++ b/src/coreclr/vm/codeversion.cpp @@ -320,7 +320,7 @@ MethodDescVersioningState* NativeCodeVersion::GetMethodDescVersioningState() CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager(); return pCodeVersionManager->GetMethodDescVersioningState(pMethodDesc); } -#endif +#endif // !DACCESS_COMPILE bool NativeCodeVersion::IsFinalTier() const { diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 7a42d2ba247960..0e55b7fc3d7e89 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -46,14 +46,14 @@ class NativeCodeVersion #ifdef FEATURE_CODE_VERSIONING friend class MethodDescVersioningState; friend class ILCodeVersion; -#endif +#endif // FEATURE_CODE_VERSIONING public: NativeCodeVersion(); NativeCodeVersion(const NativeCodeVersion & rhs); #ifdef FEATURE_CODE_VERSIONING NativeCodeVersion(PTR_NativeCodeVersionNode pVersionNode); -#endif +#endif // FEATURE_CODE_VERSIONING explicit NativeCodeVersion(PTR_MethodDesc pMethod); BOOL IsNull() const; @@ -65,7 +65,7 @@ class NativeCodeVersion #ifdef FEATURE_CODE_VERSIONING ILCodeVersion GetILCodeVersion() const; ReJITID GetILCodeVersionId() const; -#endif +#endif // FEATURE_CODE_VERSIONING #ifndef DACCESS_COMPILE BOOL SetNativeCodeInterlocked(PCODE pCode, PCODE pExpected = 0); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index fb95fdabf25d25..52ebe9ee397e68 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1886,19 +1886,20 @@ class MethodDesc // pamTracker must be NULL for a MethodDesc which cannot be freed by an external AllocMemTracker // OR must be set to point to the same AllocMemTracker that controls allocation of the MethodDesc HRESULT EnsureCodeDataExists(AllocMemTracker *pamTracker); +#endif //!DACCESS_COMPILE + +#if defined(FEATURE_INTERPRETER) && !defined(DACCESS_COMPILE) + bool SetCallStub(CallStubHeader *pHeader); + CallStubHeader *GetCallStub(); +#endif // FEATURE_INTERPRETER && !DACCESS_COMPILE #ifdef FEATURE_CODE_VERSIONING +#ifndef DACCESS_COMPILE HRESULT SetMethodDescVersionState(PTR_MethodDescVersioningState state); +#endif // !DACCESS_COMPILE PTR_MethodDescVersioningState GetMethodDescVersionState(); #endif // FEATURE_CODE_VERSIONING -#ifdef FEATURE_INTERPRETER - bool SetCallStub(CallStubHeader *pHeader); - CallStubHeader *GetCallStub(); -#endif // FEATURE_INTERPRETER - -#endif //!DACCESS_COMPILE - public: inline DWORD GetClassification() const { From 1d3ad91dd32934eaf5a565f609cd2c52ca03ec8b Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 10 Oct 2025 16:46:40 -0700 Subject: [PATCH 08/15] Build failure with GCC. --- src/coreclr/vm/interpexec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 392e8b7dc7dd01..7918f856f6f4fd 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -683,7 +683,7 @@ static void CallPreStub(MethodDesc *pMD) if (!pMD->IsPointingToPrestub()) { PCODE entryPoint = pMD->GetTemporaryEntryPoint(); - if (entryPoint != NULL && !pMD->IsPointingToPrestub()) + if (entryPoint != (PCODE)NULL && !pMD->IsPointingToPrestub()) { return; } From dc3d08fbafeae639a4786250456bc62eabd142b0 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Sat, 11 Oct 2025 09:24:59 -0700 Subject: [PATCH 09/15] Feedback. --- src/coreclr/vm/comdelegate.cpp | 2 +- src/coreclr/vm/dllimport.cpp | 1 - src/coreclr/vm/dllimportcallback.h | 10 +++------- src/coreclr/vm/interpexec.cpp | 6 ++---- src/coreclr/vm/method.hpp | 10 ++-------- src/coreclr/vm/prestub.cpp | 3 +-- src/coreclr/vm/stubmgr.cpp | 3 +-- src/coreclr/vm/syncblk.h | 2 +- 8 files changed, 11 insertions(+), 26 deletions(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 5889d85084d9dd..2d624e5beb0059 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -1345,7 +1345,7 @@ LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj) else { #ifdef FEATURE_PORTABLE_ENTRYPOINTS - COMPlusThrow(kNotSupportedException); + COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_DynamicEntrypoint")); #else // !FEATURE_PORTABLE_ENTRYPOINTS UMEntryThunkData* pUMEntryThunk = NULL; diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index c15d7de00d239a..24c40eb3bcf1cf 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -572,7 +572,6 @@ class ILStubState : public StubState { default: UNREACHABLE_MSG("Unexpected element type found on native return type."); - break; case ELEMENT_TYPE_VOID: _ASSERTE(retvalLocalNum == (DWORD)-1); pcsExceptionHandler->EmitPOP(); diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h index f2297358192024..f96064d173ba70 100644 --- a/src/coreclr/vm/dllimportcallback.h +++ b/src/coreclr/vm/dllimportcallback.h @@ -246,7 +246,7 @@ class UMEntryThunkData PCODE entryPoint = m_pUMThunkMarshInfo->GetExecStubEntryPoint(); - bool nullEntryPoint; + bool setTarget = true; #if defined(FEATURE_INTERPRETER) // For interpreted stubs we need to ensure that TheUMEntryPrestubWorker runs for every // unmanaged-to-managed invocation in order to populate the TLS variable every time. @@ -257,16 +257,12 @@ class UMEntryThunkData if (pPrecode->GetType() == PRECODE_INTERPRETER) { m_pInterpretedTarget = entryPoint; - entryPoint = (PCODE)0; + setTarget = false; } } - nullEntryPoint = entryPoint == (PCODE)0; -#else // !FEATURE_INTERPRETER - _ASSERTE(entryPoint != (PCODE)0); - nullEntryPoint = false; #endif // FEATURE_INTERPRETER - if (!nullEntryPoint) + if (setTarget) { m_pUMEntryThunk->SetTargetUnconditional(entryPoint); } diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 7918f856f6f4fd..15260861f221bf 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -797,18 +797,16 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr MemoryBarrier(); ip++; break; +#ifndef FEATURE_PORTABLE_ENTRYPOINTS case INTOP_STORESTUBCONTEXT: { -#ifdef FEATURE_PORTABLE_ENTRYPOINTS - COMPlusThrow(kNotSupportedException); -#else // !FEATURE_PORTABLE_ENTRYPOINTS UMEntryThunkData* thunkData = GetMostRecentUMEntryThunkData(); assert(thunkData); LOCAL_VAR(ip[1], void*) = thunkData; ip += 2; -#endif // FEATURE_PORTABLE_ENTRYPOINTS break; } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS case INTOP_LDC_I4: LOCAL_VAR(ip[1], int32_t) = ip[2]; ip += 3; diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 52ebe9ee397e68..65ee1779f20983 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1453,9 +1453,6 @@ class MethodDesc return !IsVersionable() && !InEnCEnabledModule(); } - // Note: We are skipping the prestub based on addition information from the JIT. - // (e.g. that the call is on same this ptr or that the this ptr is not null). - // Thus we can end up with a running NGENed method for which IsPointingToNativeCode is false! BOOL IsPointingToNativeCode() { LIMITED_METHOD_DAC_CONTRACT; @@ -1474,21 +1471,18 @@ class MethodDesc #endif // FEATURE_PORTABLE_ENTRYPOINTS } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS //Is this method currently pointing to native code that will never change? BOOL IsPointingToStableNativeCode() { LIMITED_METHOD_DAC_CONTRACT; -#ifdef FEATURE_PORTABLE_ENTRYPOINTS - return FALSE; - -#else // !FEATURE_PORTABLE_ENTRYPOINTS if (!IsNativeCodeStableAfterInit()) return FALSE; return IsPointingToNativeCode(); -#endif // FEATURE_PORTABLE_ENTRYPOINTS } +#endif // !FEATURE_PORTABLE_ENTRYPOINTS // Be careful about races with profiler when using this method. The profiler can // replace preimplemented code of the method with jitted code. diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 5e1f7f89a6978e..22d163637613e0 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2480,8 +2480,7 @@ PCODE TheUMThunkPreStub() LIMITED_METHOD_CONTRACT; #ifdef FEATURE_PORTABLE_ENTRYPOINTS - PORTABILITY_ASSERT("TheUMThunkPreStub not supported with FEATURE_PORTABLE_ENTRYPOINTS"); - return (PCODE)0; + UNREACHABLE_MSG("TheUMThunkPreStub not supported with FEATURE_PORTABLE_ENTRYPOINTS"); #else // !FEATURE_PORTABLE_ENTRYPOINTS return GetEEFuncEntryPoint(TheUMEntryPrestub); #endif // FEATURE_PORTABLE_ENTRYPOINTS diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 0904b2f502e9cf..267b6a509c7e27 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1740,8 +1740,7 @@ BOOL ILStubManager::TraceManager(Thread *thread, else if (pStubMD->IsReverseStub()) { #ifdef FEATURE_PORTABLE_ENTRYPOINTS - PORTABILITY_ASSERT("NYI: Reverse P/Invoke stubs with FEATURE_PORTABLE_ENTRYPOINTS."); - return FALSE; + UNREACHABLE_MSG("Reverse P/Invoke stubs not supported with FEATURE_PORTABLE_ENTRYPOINTS."); #else // !FEATURE_PORTABLE_ENTRYPOINTS if (pStubMD->IsStatic()) { diff --git a/src/coreclr/vm/syncblk.h b/src/coreclr/vm/syncblk.h index 31cf1809998765..45676d0e30266e 100644 --- a/src/coreclr/vm/syncblk.h +++ b/src/coreclr/vm/syncblk.h @@ -759,7 +759,7 @@ class InteropSyncBlockInfo private: #ifdef FEATURE_PORTABLE_ENTRYPOINTS - void* m_pUMEntryThunk; // Dummy field + void* m_pUMEntryThunk; // Dummy field to make using the C++ initializer list syntax easier to use. #else // !FEATURE_PORTABLE_ENTRYPOINTS // If this is a delegate marshalled out to unmanaged code, this points // to the thunk generated for unmanaged code to call back on. From 13a02921a7dc4a22a70e7fabbdd5f9647d8760d9 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Sat, 11 Oct 2025 20:32:17 -0700 Subject: [PATCH 10/15] Feedback --- src/coreclr/vm/dllimport.cpp | 4 ++-- src/coreclr/vm/encee.cpp | 2 +- src/coreclr/vm/method.hpp | 11 +++-------- src/coreclr/vm/stubmgr.cpp | 26 ++++++++++++-------------- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 24c40eb3bcf1cf..14d504199be7c1 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -2014,7 +2014,7 @@ void PInvokeStubLinker::Begin(DWORD dwStubFlags) if (SF_IsDelegateStub(dwStubFlags)) { #ifdef FEATURE_PORTABLE_ENTRYPOINTS - COMPlusThrow(kNotSupportedException); + _ASSERTE(!"Delegate reverse pinvoke stubs not supported with FEATURE_PORTABLE_ENTRYPOINTS"); #else // !FEATURE_PORTABLE_ENTRYPOINTS // @@ -2191,7 +2191,7 @@ void PInvokeStubLinker::DoPInvoke(ILCodeStream *pcsEmit, DWORD dwStubFlags, Meth else // native-to-managed { #ifdef FEATURE_PORTABLE_ENTRYPOINTS - COMPlusThrow(kNotSupportedException); + _ASSERTE(!"Delegate reverse pinvoke stubs not supported with FEATURE_PORTABLE_ENTRYPOINTS"); #else // !FEATURE_PORTABLE_ENTRYPOINTS if (SF_IsDelegateStub(dwStubFlags)) // reverse P/Invoke via delegate diff --git a/src/coreclr/vm/encee.cpp b/src/coreclr/vm/encee.cpp index 4959fde39cd43e..ba8e3cf738d54b 100644 --- a/src/coreclr/vm/encee.cpp +++ b/src/coreclr/vm/encee.cpp @@ -606,7 +606,7 @@ PCODE EditAndContinueModule::JitUpdatedFunction( MethodDesc *pMD, // get the code address (may jit the fcn if not already jitted) EX_TRY { - if (pMD->IsPointingToNativeCode()) + if (!pMD->IsPointingToPrestub()) { LOG((LF_ENC, LL_INFO100, "EACM::ResumeInUpdatedFunction %p already JITed\n", pMD)); } diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 65ee1779f20983..12c3f7dd810d02 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1453,14 +1453,11 @@ class MethodDesc return !IsVersionable() && !InEnCEnabledModule(); } +#ifndef FEATURE_PORTABLE_ENTRYPOINTS BOOL IsPointingToNativeCode() { LIMITED_METHOD_DAC_CONTRACT; -#ifdef FEATURE_PORTABLE_ENTRYPOINTS - return FALSE; - -#else // !FEATURE_PORTABLE_ENTRYPOINTS if (!HasStableEntryPoint()) return FALSE; @@ -1468,10 +1465,8 @@ class MethodDesc return TRUE; return GetPrecode()->IsPointingToNativeCode(GetNativeCode()); -#endif // FEATURE_PORTABLE_ENTRYPOINTS } -#ifndef FEATURE_PORTABLE_ENTRYPOINTS //Is this method currently pointing to native code that will never change? BOOL IsPointingToStableNativeCode() { @@ -2884,12 +2879,12 @@ class DynamicMethodDesc : public StoredSigMethodDesc m_dwExtendedFlags = (m_dwExtendedFlags & ~StackArgSizeMask) | ((DWORD)cbArgSize << 16); } - bool IsReverseStub() const + bool IsReversePInvokeStub() const { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); ILStubType type = GetILStubType(); - return type == StubCOMToCLRInterop || type == StubReversePInvoke; + return type == StubReversePInvoke; } bool IsStepThroughStub() const diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 267b6a509c7e27..8f8e2da1f2ae0f 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1737,27 +1737,25 @@ BOOL ILStubManager::TraceManager(Thread *thread, _ASSERTE(!"We should never get here. Multicast Delegates should not invoke TraceManager."); return FALSE; } - else if (pStubMD->IsReverseStub()) + else if (pStubMD->IsReversePInvokeStub()) { #ifdef FEATURE_PORTABLE_ENTRYPOINTS UNREACHABLE_MSG("Reverse P/Invoke stubs not supported with FEATURE_PORTABLE_ENTRYPOINTS."); #else // !FEATURE_PORTABLE_ENTRYPOINTS - if (pStubMD->IsStatic()) - { - // This is reverse P/Invoke stub, the argument is UMEntryThunkData - UMEntryThunkData *pEntryThunk = (UMEntryThunkData*)arg; - target = pEntryThunk->GetManagedTarget(); - LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Reverse P/Invoke case %p\n", target)); - } - else - { - // This is COM-to-CLR stub, the argument is the target - target = (PCODE)arg; - LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: COM-to-CLR case %p\n", target)); - } + // This is reverse P/Invoke stub, the argument is UMEntryThunkData + UMEntryThunkData *pEntryThunk = (UMEntryThunkData*)arg; + target = pEntryThunk->GetManagedTarget(); + LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Reverse P/Invoke case %p\n", target)); trace->InitForManaged(target); #endif // FEATURE_PORTABLE_ENTRYPOINTS } + else if (pStubMD->IsCOMToCLRStub()) + { + // This is COM-to-CLR stub, the argument is the target + target = (PCODE)arg; + LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: COM-to-CLR case %p\n", target)); + trace->InitForManaged(target); + } else if (pStubMD->IsPInvokeDelegateStub()) { // This is forward delegate P/Invoke stub, the argument is undefined From c1becd5ab0f11be96baf6f56e6e7f03ca00ebbb3 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Mon, 13 Oct 2025 09:03:12 -0700 Subject: [PATCH 11/15] Move ReversePInvokeBadTransition --- src/coreclr/vm/dllimportcallback.cpp | 14 -------------- src/coreclr/vm/dllimportcallback.h | 2 -- src/coreclr/vm/jithelpers.cpp | 14 ++++++++++++++ src/coreclr/vm/jitinterface.h | 4 +++- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/coreclr/vm/dllimportcallback.cpp b/src/coreclr/vm/dllimportcallback.cpp index b873cd4d968a9b..29409f8c1b63dc 100644 --- a/src/coreclr/vm/dllimportcallback.cpp +++ b/src/coreclr/vm/dllimportcallback.cpp @@ -435,17 +435,3 @@ VOID UMThunkMarshInfo::RunTimeInit() InterlockedCompareExchangeT(&m_pILStub, pFinalILStub, (PCODE)1); } #endif // !FEATURE_PORTABLE_ENTRYPOINTS - -// FailFast if a method marked UnmanagedCallersOnlyAttribute is -// invoked directly from managed code. UMThunkStub.asm check the -// mode and call this function to failfast. -VOID STDCALL ReversePInvokeBadTransition() -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - // Fail - EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE( - COR_E_EXECUTIONENGINE, - W("Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code.") - ); -} diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h index f96064d173ba70..ad34a04db45765 100644 --- a/src/coreclr/vm/dllimportcallback.h +++ b/src/coreclr/vm/dllimportcallback.h @@ -428,6 +428,4 @@ UMEntryThunkData* GetMostRecentUMEntryThunkData(); #endif // FEATURE_INTERPRETER #endif // !FEATURE_PORTABLE_ENTRYPOINTS -VOID STDCALL ReversePInvokeBadTransition(); - #endif //__dllimportcallback_h__ diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 8ef1b29284f416..98c05980f7bea1 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1035,6 +1035,20 @@ HCIMPL0(void, JIT_FailFast) } HCIMPLEND +// FailFast if a method marked UnmanagedCallersOnlyAttribute is +// invoked directly from managed code. UMThunkStub.asm check the +// mode and call this function to failfast. +VOID STDCALL ReversePInvokeBadTransition() +{ + STATIC_CONTRACT_THROWS; + STATIC_CONTRACT_GC_TRIGGERS; + // Fail + EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE( + COR_E_EXECUTIONENGINE, + W("Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code.") + ); +} + //======================================================================== // // DEBUGGER/PROFILER HELPERS diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 460c7e7f3fdd5a..c5011bcee2c46a 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -176,11 +176,13 @@ EXTERN_C FCDECL2(void, JITutil_MonReliableContention, AwareLock* awarelock, BYTE EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBase_Helper, MethodTable *pMT); EXTERN_C FCDECL1(void*, JIT_GetGCStaticBase_Helper, MethodTable *pMT); -EXTERN_C void DoJITFailFast (); +EXTERN_C void DoJITFailFast(); EXTERN_C FCDECL0(void, JIT_FailFast); FCDECL0(int, JIT_GetCurrentManagedThreadId); +EXTERN_C void ReversePInvokeBadTransition(); + #if !defined(FEATURE_USE_ASM_GC_WRITE_BARRIERS) && defined(FEATURE_COUNT_GC_WRITE_BARRIERS) // Extra argument for the classification of the checked barriers. extern "C" FCDECL3(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref, CheckedWriteBarrierKinds kind); From 197756f1f0d50aebe726796502eafad25dee0601 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Mon, 13 Oct 2025 10:33:27 -0700 Subject: [PATCH 12/15] Remove extra calling convention. --- src/coreclr/vm/jithelpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 98c05980f7bea1..fef3e6877b7000 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1038,7 +1038,7 @@ HCIMPLEND // FailFast if a method marked UnmanagedCallersOnlyAttribute is // invoked directly from managed code. UMThunkStub.asm check the // mode and call this function to failfast. -VOID STDCALL ReversePInvokeBadTransition() +void ReversePInvokeBadTransition() { STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_TRIGGERS; From 7c7383689cf0ff120e42c7b9d6d56a0a4e61d4e8 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Tue, 14 Oct 2025 15:54:47 -0700 Subject: [PATCH 13/15] Forcibly set entry point on PortableEntryPoint scenarios. --- src/coreclr/vm/method.cpp | 37 +++++++++++++++++++-------- src/coreclr/vm/method.hpp | 14 +++++++--- src/coreclr/vm/methodtablebuilder.cpp | 2 +- src/coreclr/vm/precode_portable.cpp | 7 +++++ src/coreclr/vm/precode_portable.hpp | 1 + src/coreclr/vm/prestub.cpp | 4 +-- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 8ee338c45297b9..88a0e6e59ff0dd 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -2382,18 +2382,22 @@ BOOL MethodDesc::IsPointingToPrestub() } CONTRACTL_END; + PCODE methodEntryPoint; if (!HasStableEntryPoint()) { if (IsVersionableWithVtableSlotBackpatch()) { - PCODE methodEntrypoint = GetMethodEntryPointIfExists(); - return methodEntrypoint == GetTemporaryEntryPointIfExists() && methodEntrypoint != (PCODE)NULL; + methodEntryPoint = GetMethodEntryPointIfExists(); + return methodEntryPoint == GetTemporaryEntryPointIfExists() && methodEntryPoint != (PCODE)NULL; } return TRUE; } #ifdef FEATURE_PORTABLE_ENTRYPOINTS - return FALSE; + methodEntryPoint = GetStableEntryPoint(); + return methodEntryPoint == (PCODE)NULL + || (!PortableEntryPoint::HasInterpreterData(methodEntryPoint) + && !PortableEntryPoint::HasNativeEntryPoint(methodEntryPoint)); #else // !FEATURE_PORTABLE_ENTRYPOINTS if (!HasPrecode()) @@ -2430,7 +2434,12 @@ void MethodDesc::Reset() // We should go here only for the rental methods _ASSERTE(GetLoaderModule()->IsReflectionEmit()); - InterlockedUpdateFlags3(enum_flag3_HasStableEntryPoint | enum_flag3_HasPrecode, FALSE); + DWORD flagsToSet = enum_flag3_HasStableEntryPoint; +#ifndef FEATURE_PORTABLE_ENTRYPOINTS + flagsToSet |= enum_flag3_HasPrecode; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS + + InterlockedUpdateFlags3(flagsToSet, FALSE); *GetAddrOfSlot() = GetTemporaryEntryPoint(); } @@ -2728,7 +2737,7 @@ void MethodDesc::SetTemporaryEntryPoint(AllocMemTracker *pamTracker) { // The rest of the system assumes that certain methods always have stable entrypoints. // Mark the precode as such - MarkPrecodeAsStableEntrypoint(); + MarkStableEntryPoint(); } } @@ -2907,7 +2916,7 @@ Precode* MethodDesc::GetOrCreatePrecode() } #endif // !FEATURE_PORTABLE_ENTRYPOINTS -void MethodDesc::MarkPrecodeAsStableEntrypoint() +void MethodDesc::MarkStableEntryPoint() { #if _DEBUG PCODE tempEntry = GetTemporaryEntryPointIfExists(); @@ -2918,12 +2927,17 @@ void MethodDesc::MarkPrecodeAsStableEntrypoint() PrecodeType requiredType = GetPrecodeType(); PrecodeType availableType = Precode::GetPrecodeFromEntryPoint(tempEntry)->GetType(); _ASSERTE(requiredType == availableType); + _ASSERTE(!HasPrecode()); #endif // FEATURE_PORTABLE_ENTRYPOINTS #endif // _DEBUG - _ASSERTE(!HasPrecode()); _ASSERTE(RequiresStableEntryPoint()); - InterlockedUpdateFlags3(enum_flag3_HasStableEntryPoint | enum_flag3_HasPrecode, TRUE); + DWORD flagsToSet = enum_flag3_HasStableEntryPoint; +#ifndef FEATURE_PORTABLE_ENTRYPOINTS + flagsToSet |= enum_flag3_HasPrecode; +#endif // !FEATURE_PORTABLE_ENTRYPOINTS + + InterlockedUpdateFlags3(flagsToSet, TRUE); } bool MethodDesc::DetermineIsEligibleForTieredCompilationInvariantForAllMethodsInChunk() @@ -3163,7 +3177,10 @@ void MethodDesc::SetCodeEntryPoint(PCODE entryPoint) WRAPPER_NO_CONTRACT; _ASSERTE(entryPoint != (PCODE)NULL); -#ifndef FEATURE_PORTABLE_ENTRYPOINTS +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + SetStableEntryPointInterlocked(entryPoint); + +#else // !FEATURE_PORTABLE_ENTRYPOINTS if (MayHaveEntryPointSlotsToBackpatch()) { BackpatchEntryPointSlots(entryPoint); @@ -3189,13 +3206,13 @@ void MethodDesc::SetCodeEntryPoint(PCODE entryPoint) GetOrCreatePrecode()->SetTargetInterlocked(entryPoint); return; } -#endif // !FEATURE_PORTABLE_ENTRYPOINTS if (!HasStableEntryPoint()) { SetStableEntryPointInterlocked(entryPoint); return; } +#endif // FEATURE_PORTABLE_ENTRYPOINTS } #ifdef FEATURE_TIERED_COMPILATION diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 12c3f7dd810d02..8f5d33f1dcc9cc 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -378,7 +378,11 @@ class MethodDesc { LIMITED_METHOD_DAC_CONTRACT; +#ifdef FEATURE_PORTABLE_ENTRYPOINTS + return FALSE; +#else // !FEATURE_PORTABLE_ENTRYPOINTS return (m_wFlags3AndTokenRemainder & enum_flag3_HasPrecode) != 0; +#endif // FEATURE_PORTABLE_ENTRYPOINTS } #ifndef FEATURE_PORTABLE_ENTRYPOINTS @@ -419,7 +423,7 @@ class MethodDesc #ifndef FEATURE_PORTABLE_ENTRYPOINTS Precode* GetOrCreatePrecode(); #endif // !FEATURE_PORTABLE_ENTRYPOINTS - void MarkPrecodeAsStableEntrypoint(); + void MarkStableEntryPoint(); static MethodDesc * GetMethodDescFromPrecode(PCODE addr, BOOL fSpeculative = FALSE); @@ -1784,15 +1788,17 @@ class MethodDesc // The actual data stored in a MethodDesc follows. protected: - enum { + enum + { // There are flags available for use here (currently 4 flags bits are available); however, new bits are hard to come by, so any new flags bits should // have a fairly strong justification for existence. enum_flag3_TokenRemainderMask = 0x0FFF, // This must equal METHOD_TOKEN_REMAINDER_MASK calculated higher in this file. // for this method. - // enum_flag3_HasPrecode implies that enum_flag3_HasStableEntryPoint is set. + // enum_flag3_HasPrecode implies that enum_flag3_HasStableEntryPoint is set in non-portable entrypoint scenarios. enum_flag3_HasStableEntryPoint = 0x1000, // The method entrypoint is stable (either precode or actual code) +#ifndef FEATURE_PORTABLE_ENTRYPOINTS enum_flag3_HasPrecode = 0x2000, // Precode has been allocated for this method - +#endif // !FEATURE_PORTABLE_ENTRYPOINTS enum_flag3_IsUnboxingStub = 0x4000, enum_flag3_IsEligibleForTieredCompilation = 0x8000, }; diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index e13efdcf4d392f..7726e70541c98e 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -11215,7 +11215,7 @@ MethodTableBuilder::SetupMethodTable2( { // The rest of the system assumes that certain methods always have stable entrypoints. // Create them now. - pMD->MarkPrecodeAsStableEntrypoint(); + pMD->MarkStableEntryPoint(); } } } diff --git a/src/coreclr/vm/precode_portable.cpp b/src/coreclr/vm/precode_portable.cpp index 3ddac68386da64..5b2b96c83271d4 100644 --- a/src/coreclr/vm/precode_portable.cpp +++ b/src/coreclr/vm/precode_portable.cpp @@ -20,6 +20,13 @@ bool PortableEntryPoint::HasNativeEntryPoint(PCODE addr) return portableEntryPoint->HasNativeCode(); } +bool PortableEntryPoint::HasInterpreterData(PCODE addr) +{ + LIMITED_METHOD_CONTRACT; + PortableEntryPoint* portableEntryPoint = ToPortableEntryPoint(addr); + return portableEntryPoint->HasInterpreterCode(); +} + void* PortableEntryPoint::GetActualCode(PCODE addr) { STANDARD_VM_CONTRACT; diff --git a/src/coreclr/vm/precode_portable.hpp b/src/coreclr/vm/precode_portable.hpp index 0ec648b6b17ec4..cae51ba32225b1 100644 --- a/src/coreclr/vm/precode_portable.hpp +++ b/src/coreclr/vm/precode_portable.hpp @@ -13,6 +13,7 @@ class PortableEntryPoint final { public: // static static bool HasNativeEntryPoint(PCODE addr); + static bool HasInterpreterData(PCODE addr); static void* GetActualCode(PCODE addr); static void SetActualCode(PCODE addr, PCODE actualCode); diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 22d163637613e0..b40d16641a9e44 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2404,7 +2404,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo _ASSERTE(ilStubInterpData != NULL); SetInterpreterCode((InterpByteCodeStart*)ilStubInterpData); SetCodeEntryPoint(pCode); -#else +#else // !FEATURE_PORTABLE_ENTRYPOINTS if (!GetOrCreatePrecode()->SetTargetInterlocked(pStub->GetEntryPoint())) { if (pStub->HasExternalEntryPoint()) @@ -2424,7 +2424,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo // need to free the Stub allocation now. pStub->DecRef(); } -#endif // !FEATURE_PORTABLE_ENTRYPOINTS +#endif // FEATURE_PORTABLE_ENTRYPOINTS } _ASSERTE(!IsPointingToPrestub()); From e510889d0253c5c0d6b49a05a4f395deeb580999 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 15 Oct 2025 09:27:06 +0200 Subject: [PATCH 14/15] Fix build --- src/coreclr/vm/method.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 88a0e6e59ff0dd..3efc5b923b42eb 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -2434,7 +2434,7 @@ void MethodDesc::Reset() // We should go here only for the rental methods _ASSERTE(GetLoaderModule()->IsReflectionEmit()); - DWORD flagsToSet = enum_flag3_HasStableEntryPoint; + WORD flagsToSet = enum_flag3_HasStableEntryPoint; #ifndef FEATURE_PORTABLE_ENTRYPOINTS flagsToSet |= enum_flag3_HasPrecode; #endif // !FEATURE_PORTABLE_ENTRYPOINTS @@ -2932,7 +2932,7 @@ void MethodDesc::MarkStableEntryPoint() #endif // _DEBUG _ASSERTE(RequiresStableEntryPoint()); - DWORD flagsToSet = enum_flag3_HasStableEntryPoint; + WORD flagsToSet = enum_flag3_HasStableEntryPoint; #ifndef FEATURE_PORTABLE_ENTRYPOINTS flagsToSet |= enum_flag3_HasPrecode; #endif // !FEATURE_PORTABLE_ENTRYPOINTS From 8c90518a6af531d562f5eaa16e1af1bafab32b24 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Wed, 15 Oct 2025 10:33:55 -0700 Subject: [PATCH 15/15] Rename MethodDesc::IsPointingToPrestub to ShouldCallPrestub. Update ShouldCallPrestub for NULL to return TRUE. --- src/coreclr/vm/codeversion.cpp | 2 +- src/coreclr/vm/encee.cpp | 2 +- src/coreclr/vm/interpexec.cpp | 11 ++--------- src/coreclr/vm/marshalnative.cpp | 2 +- src/coreclr/vm/method.cpp | 5 +++-- src/coreclr/vm/method.hpp | 2 +- src/coreclr/vm/precode.cpp | 11 ++++++++--- src/coreclr/vm/precode.h | 12 ++++-------- src/coreclr/vm/prestub.cpp | 8 ++++---- src/coreclr/vm/reflectioninvocation.cpp | 6 +++--- src/coreclr/vm/stubmgr.cpp | 6 ++---- 11 files changed, 30 insertions(+), 37 deletions(-) diff --git a/src/coreclr/vm/codeversion.cpp b/src/coreclr/vm/codeversion.cpp index 316376fe0bb918..1fdfa6f952f44e 100644 --- a/src/coreclr/vm/codeversion.cpp +++ b/src/coreclr/vm/codeversion.cpp @@ -1737,7 +1737,7 @@ PCODE CodeVersionManager::PublishVersionableCodeIfNecessary( break; } - if (!pMethodDesc->IsPointingToPrestub()) + if (!pMethodDesc->ShouldCallPrestub()) { *doFullBackpatchRef = true; return (PCODE)NULL; diff --git a/src/coreclr/vm/encee.cpp b/src/coreclr/vm/encee.cpp index ba8e3cf738d54b..025df8ac2aa77f 100644 --- a/src/coreclr/vm/encee.cpp +++ b/src/coreclr/vm/encee.cpp @@ -606,7 +606,7 @@ PCODE EditAndContinueModule::JitUpdatedFunction( MethodDesc *pMD, // get the code address (may jit the fcn if not already jitted) EX_TRY { - if (!pMD->IsPointingToPrestub()) + if (!pMD->ShouldCallPrestub()) { LOG((LF_ENC, LL_INFO100, "EACM::ResumeInUpdatedFunction %p already JITed\n", pMD)); } diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index d1c7d20871b005..8d6b8abed82e98 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -679,15 +679,8 @@ static void CallPreStub(MethodDesc *pMD) STATIC_STANDARD_VM_CONTRACT; _ASSERTE(pMD != NULL); - // The prestub may not yet be ready to be used, so force temporary entry point creation, and check again. - if (!pMD->IsPointingToPrestub()) - { - PCODE entryPoint = pMD->GetTemporaryEntryPoint(); - if (entryPoint != (PCODE)NULL && !pMD->IsPointingToPrestub()) - { - return; - } - } + if (!pMD->ShouldCallPrestub()) + return; struct Param { diff --git a/src/coreclr/vm/marshalnative.cpp b/src/coreclr/vm/marshalnative.cpp index f0e5d17c81963e..bd290844478af4 100644 --- a/src/coreclr/vm/marshalnative.cpp +++ b/src/coreclr/vm/marshalnative.cpp @@ -59,7 +59,7 @@ extern "C" VOID QCALLTYPE MarshalNative_Prelink(MethodDesc * pMD) // If the code is already ready, we are done. Else, we need to execute the prestub // This is a perf thing since it's always safe to execute the prestub twice. - if (!pMD->IsPointingToPrestub()) + if (!pMD->ShouldCallPrestub()) return; // Silently ignore if not PInvoke and not runtime generated. diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 3efc5b923b42eb..9a4ed1c3837b31 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -2372,7 +2372,7 @@ MethodReturnKind ClassifyMethodReturnKind(SigPointer sig, Module* pModule, ULONG } //******************************************************************************* -BOOL MethodDesc::IsPointingToPrestub() +BOOL MethodDesc::ShouldCallPrestub() { CONTRACTL { @@ -2388,7 +2388,8 @@ BOOL MethodDesc::IsPointingToPrestub() if (IsVersionableWithVtableSlotBackpatch()) { methodEntryPoint = GetMethodEntryPointIfExists(); - return methodEntryPoint == GetTemporaryEntryPointIfExists() && methodEntryPoint != (PCODE)NULL; + return methodEntryPoint == (PCODE)NULL + || methodEntryPoint == GetTemporaryEntryPointIfExists(); } return TRUE; } diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 8f5d33f1dcc9cc..c4566bd5e92422 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1174,7 +1174,7 @@ class MethodDesc // the table. void SetChunkIndex(MethodDescChunk *pChunk); - BOOL IsPointingToPrestub(); + BOOL ShouldCallPrestub(); public: diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp index 74f8082c1246a2..c063464443450b 100644 --- a/src/coreclr/vm/precode.cpp +++ b/src/coreclr/vm/precode.cpp @@ -215,6 +215,12 @@ BOOL Precode::IsPointingToPrestub(PCODE target) return FALSE; } +BOOL Precode::IsPointingToPrestub() +{ + WRAPPER_NO_CONTRACT; + return IsPointingToPrestub(GetTarget()); +} + #ifndef DACCESS_COMPILE void FlushCacheForDynamicMappedStub(void* code, SIZE_T size) @@ -380,12 +386,11 @@ BOOL Precode::SetTargetInterlocked(PCODE target, BOOL fOnlyRedirectFromPrestub) WRAPPER_NO_CONTRACT; _ASSERTE(!IsPointingToPrestub(target)); - PCODE expected = GetTarget(); BOOL ret = FALSE; - - if (fOnlyRedirectFromPrestub && !IsPointingToPrestub(expected)) + if (fOnlyRedirectFromPrestub && !IsPointingToPrestub()) return FALSE; + PCODE expected = GetTarget(); PrecodeType precodeType = GetType(); switch (precodeType) { diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index 75ba4094bd3570..b4a50b56afc023 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -633,6 +633,8 @@ class Precode { #endif } + BOOL IsPointingToPrestub(PCODE target); + public: PrecodeType GetType() { @@ -684,7 +686,7 @@ class Precode { // Note: This is immediate target of the precode. It does not follow jump stub if there is one. PCODE GetTarget(); - BOOL IsPointingTo(PCODE target, PCODE addr) + static BOOL IsPointingTo(PCODE target, PCODE addr) { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; @@ -712,13 +714,7 @@ class Precode { return IsPointingTo(GetTarget(), pNativeCode); } - BOOL IsPointingToPrestub(PCODE target); - - BOOL IsPointingToPrestub() - { - WRAPPER_NO_CONTRACT; - return IsPointingToPrestub(GetTarget()); - } + BOOL IsPointingToPrestub(); PCODE GetEntryPoint() { diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index b40d16641a9e44..fa63cb58f5da53 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2265,7 +2265,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo } #endif // FEATURE_CODE_VERSIONING - if (!IsPointingToPrestub()) + if (!ShouldCallPrestub()) { LOG((LF_CLASSLOADER, LL_INFO10000, " In PreStubWorker, method already jitted, backpatching call point\n")); @@ -2343,7 +2343,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo MethodDesc* helperMD = PortableEntryPoint::GetMethodDesc(pCode); // If the FCall implementation is managed, then we need to potentially set up the interpreter code for it as well. // This is because the FCall may have been compiled to an IL stub that needs to be interpreted. - if (helperMD->IsPointingToPrestub()) + if (helperMD->ShouldCallPrestub()) (void)helperMD->DoPrestub(NULL /* MethodTable */, CallerGCMode::Coop); void* ilStubInterpData = helperMD->GetInterpreterCode(); SetInterpreterCode((InterpByteCodeStart*)ilStubInterpData); @@ -2427,7 +2427,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo #endif // FEATURE_PORTABLE_ENTRYPOINTS } - _ASSERTE(!IsPointingToPrestub()); + _ASSERTE(!ShouldCallPrestub()); _ASSERTE(HasStableEntryPoint()); pCode = DoBackpatch(pMT, pDispatchingMT, false /* doFullBackpatch */); @@ -2851,7 +2851,7 @@ EXTERN_C PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBl #endif // _DEBUG // - // Note that we do not want to call code:MethodDesc::IsPointingToPrestub() here. It does not take remoting + // Note that we do not want to call code:MethodDesc::ShouldCallPrestub() here. It does not take remoting // interception into account and so it would cause otherwise intercepted methods to be JITed. It is a compat // issue if the JITing fails. // diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index 7477de9a20ecc9..a01c9820479469 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -1221,7 +1221,7 @@ extern "C" void QCALLTYPE ReflectionInvocation_CompileMethod(MethodDesc * pMD) // Argument is checked on the managed side PRECONDITION(pMD != NULL); - if (!pMD->IsPointingToPrestub()) + if (!pMD->ShouldCallPrestub()) return; BEGIN_QCALL; @@ -1270,13 +1270,13 @@ static void PrepareMethodHelper(MethodDesc * pMD) pMD->EnsureActive(); - if (pMD->IsPointingToPrestub()) + if (pMD->ShouldCallPrestub()) pMD->DoPrestub(NULL); if (pMD->IsWrapperStub()) { pMD = pMD->GetWrappedMethodDesc(); - if (pMD->IsPointingToPrestub()) + if (pMD->ShouldCallPrestub()) pMD->DoPrestub(NULL); } } diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 8f8e2da1f2ae0f..0d87bd838e9d41 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1106,12 +1106,10 @@ BOOL PrecodeStubManager::DoTraceStub(PCODE stubStartAddress, break; } - PCODE target = pPrecode->GetTarget(); - // check if the method has been jitted - if (!pPrecode->IsPointingToPrestub(target)) + if (!pPrecode->IsPointingToPrestub()) { - trace->InitForStub(target); + trace->InitForStub(pPrecode->GetTarget()); LOG_TRACE_DESTINATION(trace, stubStartAddress, "PrecodeStubManager::DoTraceStub - code"); return TRUE; }