From b7a3590e9906a9e889cb645b82d526eccc8b02dc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 07:43:57 -0700 Subject: [PATCH] [release/8.0] Events for IL methods without IL headers (#90844) * Events for IL methods without IL headers Dynamically generated methods like UnsafeAccessor functions are marked as IL, but don't contain an IL header. The lack of header is an indication the IL must be generated at runtime. * Debugger check for no IL header * Update src/coreclr/debug/daccess/stack.cpp Co-authored-by: Tlakaelel Axayakatl Ceja * Review feedback * Remove redundent calls and another spot to check. * Move header include --------- Co-authored-by: Aaron R Robinson Co-authored-by: Tlakaelel Axayakatl Ceja --- src/coreclr/debug/daccess/stack.cpp | 9 ++- src/coreclr/inc/eventtracebase.h | 6 +- src/coreclr/utilcode/stresslog.cpp | 2 +- src/coreclr/vm/eventtrace.cpp | 21 ++--- src/coreclr/vm/jitinterface.cpp | 2 +- src/coreclr/vm/method.hpp | 2 +- src/coreclr/vm/prestub.cpp | 116 ++++++++++++++-------------- src/coreclr/vm/versionresilienthashcode.cpp | 8 +- 8 files changed, 90 insertions(+), 76 deletions(-) diff --git a/src/coreclr/debug/daccess/stack.cpp b/src/coreclr/debug/daccess/stack.cpp index 9402d52..6b9f1a4 100644 --- a/src/coreclr/debug/daccess/stack.cpp +++ b/src/coreclr/debug/daccess/stack.cpp @@ -1253,14 +1253,19 @@ ClrDataFrame::GetLocalSig(MetaSig** sig, { // It turns out we cannot really get rid of this check. Dynamic methods // (including IL stubs) do not have their local sig's available after JIT time. - if (!m_methodDesc->IsIL()) + // IL methods with dynamically generated IL (for example, UnsafeAccessors) may + // not have an IL header. + COR_ILMETHOD* ilHeader = m_methodDesc->IsIL() + ? m_methodDesc->GetILHeader() + : NULL; + if (ilHeader == NULL) { *sig = NULL; *count = 0; return E_FAIL; } - COR_ILMETHOD_DECODER methodDecoder(m_methodDesc->GetILHeader()); + COR_ILMETHOD_DECODER methodDecoder(ilHeader); mdSignature localSig = methodDecoder.GetLocalVarSigTok() ? methodDecoder.GetLocalVarSigTok() : mdSignatureNil; if (localSig == mdSignatureNil) diff --git a/src/coreclr/inc/eventtracebase.h b/src/coreclr/inc/eventtracebase.h index 97c3135..3648b1f 100644 --- a/src/coreclr/inc/eventtracebase.h +++ b/src/coreclr/inc/eventtracebase.h @@ -905,7 +905,7 @@ namespace ETW BOOL fSendRichDebugInfoEvent, BOOL fGetCodeIds); static VOID SendEventsForNgenMethods(Module *pModule, DWORD dwEventOptions); - static VOID SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL); + static VOID SendMethodJitStartEvent(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL); static VOID SendMethodILToNativeMapEvent(MethodDesc * pMethodDesc, DWORD dwEventOptions, PCODE pNativeCodeStartAddress, DWORD nativeCodeId, ReJITID ilCodeId); static VOID SendMethodRichDebugInfo(MethodDesc * pMethodDesc, PCODE pNativeCodeStartAddress, DWORD nativeCodeId, ReJITID ilCodeId, MethodDescSet* sentMethodDetailsSet); static VOID SendMethodEvent(MethodDesc *pMethodDesc, DWORD dwEventOptions, BOOL bIsJit, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL, PCODE pNativeCodeStartAddress = 0, PrepareCodeConfig *pConfig = NULL, MethodDescSet* sentMethodDetailsSet = NULL); @@ -938,7 +938,7 @@ namespace ETW static VOID GetR2RGetEntryPointStart(MethodDesc *pMethodDesc); static VOID GetR2RGetEntryPoint(MethodDesc *pMethodDesc, PCODE pEntryPoint); - static VOID MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); + static VOID MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); static VOID MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, PCODE pNativeCodeStartAddress, PrepareCodeConfig *pConfig); static VOID SendMethodDetailsEvent(MethodDesc *pMethodDesc); static VOID SendNonDuplicateMethodDetailsEvent(MethodDesc* pMethodDesc, MethodDescSet* set); @@ -952,7 +952,7 @@ namespace ETW public: static VOID GetR2RGetEntryPointStart(MethodDesc *pMethodDesc) {}; static VOID GetR2RGetEntryPoint(MethodDesc *pMethodDesc, PCODE pEntryPoint) {}; - static VOID MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); + static VOID MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); static VOID MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, PCODE pNativeCodeStartAddress, PrepareCodeConfig *pConfig); static VOID StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pHelperName) {}; static VOID StubsInitialized(PVOID *pHelperStartAddress, PVOID *pHelperNames, LONG ulNoOfHelpers) {}; diff --git a/src/coreclr/utilcode/stresslog.cpp b/src/coreclr/utilcode/stresslog.cpp index c55c5af..90ad590 100644 --- a/src/coreclr/utilcode/stresslog.cpp +++ b/src/coreclr/utilcode/stresslog.cpp @@ -12,9 +12,9 @@ #include "switches.h" #include "stresslog.h" #include "clrhost.h" +#include "ex.h" #define DONOT_DEFINE_ETW_CALLBACK #include "eventtracebase.h" -#include "ex.h" #if !defined(STRESS_LOG_READONLY) #ifdef HOST_WINDOWS diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index b9a82cf..9498f00 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -3555,7 +3555,7 @@ VOID ETW::MethodLog::MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrC /*************************************************/ /* This is called by the runtime when method jitting started */ /*************************************************/ -VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) +VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) { CONTRACTL { NOTHROW; @@ -3570,7 +3570,7 @@ VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOr CLR_JIT_KEYWORD)) { pMethodDesc->GetMethodInfo(*namespaceOrClassName, *methodName, *methodSignature); - ETW::MethodLog::SendMethodJitStartEvent(pMethodDesc, namespaceOrClassName, methodName, methodSignature); + ETW::MethodLog::SendMethodJitStartEvent(pMethodDesc, methodDecoder, namespaceOrClassName, methodName, methodSignature); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -4528,7 +4528,12 @@ VOID ETW::MethodLog::SendNonDuplicateMethodDetailsEvent(MethodDesc* pMethodDesc, /*****************************************************************/ /* This routine is used to send an ETW event just before a method starts jitting*/ /*****************************************************************/ -VOID ETW::MethodLog::SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) +VOID ETW::MethodLog::SendMethodJitStartEvent( + MethodDesc *pMethodDesc, + COR_ILMETHOD_DECODER* methodDecoder, + SString *namespaceOrClassName, + SString *methodName, + SString *methodSignature) { CONTRACTL { THROWS; @@ -4566,15 +4571,13 @@ VOID ETW::MethodLog::SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *n ulMethodToken = (ULONG)0; } else - ulMethodToken = (ULONG)pMethodDesc->GetMemberDef(); - - if(pMethodDesc->IsIL()) { - COR_ILMETHOD_DECODER::DecoderStatus decoderstatus = COR_ILMETHOD_DECODER::FORMAT_ERROR; - COR_ILMETHOD_DECODER ILHeader(pMethodDesc->GetILHeader(), pMethodDesc->GetMDImport(), &decoderstatus); - ulMethodILSize = (ULONG)ILHeader.GetCodeSize(); + ulMethodToken = (ULONG)pMethodDesc->GetMemberDef(); } + if (methodDecoder != NULL) + ulMethodILSize = methodDecoder->GetCodeSize(); + SString tNamespace, tMethodName, tMethodSignature; if(!namespaceOrClassName|| !methodName|| !methodSignature || (methodName->IsEmpty() && namespaceOrClassName->IsEmpty() && methodSignature->IsEmpty())) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 1a3439b..74ee2f7 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -12286,7 +12286,7 @@ static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr, SString namespaceOrClassName, methodName, methodSignature; // Fire an ETW event to mark the beginning of JIT'ing - ETW::MethodLog::MethodJitting(reinterpret_cast(info->ftn), &namespaceOrClassName, &methodName, &methodSignature); + ETW::MethodLog::MethodJitting(reinterpret_cast(info->ftn), NULL, &namespaceOrClassName, &methodName, &methodSignature); CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 4b34045..e51d9f7 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1819,7 +1819,7 @@ private: PCODE GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0); PCODE JitCompileCode(PrepareCodeConfig* pConfig); PCODE JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry); - PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode); + PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pilHeader, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode); public: bool TryGenerateUnsafeAccessor(DynamicResolver** resolver, COR_ILMETHOD_DECODER** methodILDecoder); diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 174e485..3294495 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -709,6 +709,53 @@ PCODE MethodDesc::JitCompileCode(PrepareCodeConfig* pConfig) } } +namespace +{ + COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pDecoderMemory) + { + STANDARD_VM_CONTRACT; + _ASSERTE(pMD != NULL); + _ASSERTE(!pMD->IsNoMetadata()); + _ASSERTE(pConfig != NULL); + _ASSERTE(pDecoderMemory != NULL); + + COR_ILMETHOD_DECODER* pHeader = NULL; + COR_ILMETHOD* ilHeader = pConfig->GetILHeader(); + if (ilHeader == NULL) + return NULL; + + COR_ILMETHOD_DECODER::DecoderStatus status = COR_ILMETHOD_DECODER::FORMAT_ERROR; + { + // Decoder ctor can AV on a malformed method header + AVInRuntimeImplOkayHolder AVOkay; + pHeader = new (pDecoderMemory) COR_ILMETHOD_DECODER(ilHeader, pMD->GetMDImport(), &status); + } + + if (status == COR_ILMETHOD_DECODER::FORMAT_ERROR) + COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL); + + return pHeader; + } + + COR_ILMETHOD_DECODER* GetAndVerifyILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory) + { + STANDARD_VM_CONTRACT; + _ASSERTE(pMD != NULL); + if (pMD->IsIL()) + { + return GetAndVerifyMetadataILHeader(pMD, pConfig, pIlDecoderMemory); + } + else if (pMD->IsILStub()) + { + ILStubResolver* pResolver = pMD->AsDynamicMethodDesc()->GetILStubResolver(); + return pResolver->GetILHeader(); + } + + _ASSERTE(pMD->IsNoMetadata()); + return NULL; + } +} + PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry) { STANDARD_VM_CONTRACT; @@ -759,11 +806,18 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J } #endif // PROFILING_SUPPORTED + // The profiler may have changed the code on the callback. Need to + // pick up the new code. + // + // (don't want this for OSR, need to see how it works) + COR_ILMETHOD_DECODER ilDecoderTemp; + COR_ILMETHOD_DECODER* pilHeader = GetAndVerifyILHeader(this, pConfig, &ilDecoderTemp); + if (!ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, TRACE_LEVEL_VERBOSE, CLR_JIT_KEYWORD)) { - pCode = JitCompileCodeLocked(pConfig, pEntry, &sizeOfCode); + pCode = JitCompileCodeLocked(pConfig, pilHeader, pEntry, &sizeOfCode); } else { @@ -778,12 +832,13 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J // a small stub of native code but no native-IL mapping. #ifndef FEATURE_INTERPRETER ETW::MethodLog::MethodJitting(this, + pilHeader, &namespaceOrClassName, &methodName, &methodSignature); #endif - pCode = JitCompileCodeLocked(pConfig, pEntry, &sizeOfCode); + pCode = JitCompileCodeLocked(pConfig, pilHeader, pEntry, &sizeOfCode); // Interpretted methods skip this notification #ifdef FEATURE_INTERPRETER @@ -869,66 +924,11 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J return pCode; } -namespace -{ - COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pDecoderMemory) - { - STANDARD_VM_CONTRACT; - _ASSERTE(pMD != NULL); - _ASSERTE(!pMD->IsNoMetadata()); - _ASSERTE(pConfig != NULL); - _ASSERTE(pDecoderMemory != NULL); - - COR_ILMETHOD_DECODER* pHeader = NULL; - COR_ILMETHOD* ilHeader = pConfig->GetILHeader(); - if (ilHeader == NULL) - return NULL; - - COR_ILMETHOD_DECODER::DecoderStatus status = COR_ILMETHOD_DECODER::FORMAT_ERROR; - { - // Decoder ctor can AV on a malformed method header - AVInRuntimeImplOkayHolder AVOkay; - pHeader = new (pDecoderMemory) COR_ILMETHOD_DECODER(ilHeader, pMD->GetMDImport(), &status); - } - - if (status == COR_ILMETHOD_DECODER::FORMAT_ERROR) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL); - - return pHeader; - } - - COR_ILMETHOD_DECODER* GetAndVerifyILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory) - { - STANDARD_VM_CONTRACT; - _ASSERTE(pMD != NULL); - if (pMD->IsIL()) - { - return GetAndVerifyMetadataILHeader(pMD, pConfig, pIlDecoderMemory); - } - else if (pMD->IsILStub()) - { - ILStubResolver* pResolver = pMD->AsDynamicMethodDesc()->GetILStubResolver(); - return pResolver->GetILHeader(); - } - - _ASSERTE(pMD->IsNoMetadata()); - return NULL; - } -} - -PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry, ULONG* pSizeOfCode) +PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pilHeader, JitListLockEntry* pEntry, ULONG* pSizeOfCode) { STANDARD_VM_CONTRACT; PCODE pCode = NULL; - - // The profiler may have changed the code on the callback. Need to - // pick up the new code. - // - // (don't want this for OSR, need to see how it works) - COR_ILMETHOD_DECODER ilDecoderTemp; - COR_ILMETHOD_DECODER* pilHeader = GetAndVerifyILHeader(this, pConfig, &ilDecoderTemp); - CORJIT_FLAGS jitFlags; PCODE pOtherCode = NULL; diff --git a/src/coreclr/vm/versionresilienthashcode.cpp b/src/coreclr/vm/versionresilienthashcode.cpp index b3ba764..85bd146 100644 --- a/src/coreclr/vm/versionresilienthashcode.cpp +++ b/src/coreclr/vm/versionresilienthashcode.cpp @@ -286,7 +286,7 @@ bool AddVersionResilientHashCodeForInstruction(ILInstructionParser *parser, xxHa hash->Add(varValue); break; } - + case InlineVar: // 2 byte value which is token change resilient { uint16_t varValue; @@ -388,6 +388,12 @@ bool GetVersionResilientILCodeHashCode(MethodDesc *pMD, int* hashCode, unsigned* initLocals = (options & CORINFO_OPT_INIT_LOCALS) == CORINFO_OPT_INIT_LOCALS; } + else if (!pMD->HasILHeader()) + { + // Dynamically generated IL methods like UnsafeAccessors may not have + // an IL header. + return false; + } else { COR_ILMETHOD_DECODER header(pMD->GetILHeader(TRUE), pMD->GetMDImport(), NULL); -- 2.7.4