From b497f76f9ab6a4f351bc9ec24437b0e2c5e4a1af Mon Sep 17 00:00:00 2001 From: David Mason Date: Tue, 25 Jun 2019 20:13:31 -0700 Subject: [PATCH] emit rundown event for generic methods in R2R images (#25371) * emit rundown event for generic methods in R2R images * fix mac build * Code Review Feedback --- src/vm/eventtrace.cpp | 11 ++++++ src/vm/nativeformatreader.h | 60 ++++++++++++++++++++++++++++- src/vm/readytoruninfo.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++ src/vm/readytoruninfo.h | 30 ++++++++++++++- 4 files changed, 190 insertions(+), 3 deletions(-) diff --git a/src/vm/eventtrace.cpp b/src/vm/eventtrace.cpp index c314375..da3bc0d 100644 --- a/src/vm/eventtrace.cpp +++ b/src/vm/eventtrace.cpp @@ -6845,6 +6845,17 @@ VOID ETW::MethodLog::SendEventsForNgenMethods(Module *pModule, DWORD dwEventOpti } } + ReadyToRunInfo::GenericMethodIterator gmi(pModule->GetReadyToRunInfo()); + while (gmi.Next()) + { + // Call GetMethodDesc_NoRestore instead of GetMethodDesc to avoid restoring methods at shutdown. + MethodDesc *hotDesc = (MethodDesc *)gmi.GetMethodDesc_NoRestore(); + if (hotDesc != NULL) + { + ETW::MethodLog::SendMethodEvent(hotDesc, dwEventOptions, FALSE); + } + } + return; } #endif // FEATURE_READYTORUN diff --git a/src/vm/nativeformatreader.h b/src/vm/nativeformatreader.h index c97f324..34f46a6 100644 --- a/src/vm/nativeformatreader.h +++ b/src/vm/nativeformatreader.h @@ -42,7 +42,9 @@ namespace NativeFormat { class NativeReader; - typedef DPTR(NativeReader) PTR_NativeReader; + class NativeHashtable; + typedef DPTR(NativeReader) PTR_NativeReader; + typedef DPTR(NativeHashtable) PTR_NativeHashtable; class NativeReader { @@ -275,6 +277,8 @@ namespace NativeFormat _offset = offset; } + bool IsNull() { return _pReader == NULL; } + NativeReader * GetNativeReader() { return _pReader; } uint GetOffset() { return _offset; } @@ -482,6 +486,60 @@ namespace NativeFormat bool IsNull() { return _pReader == NULL; } + class AllEntriesEnumerator + { + PTR_NativeHashtable _table; + NativeParser _parser; + uint _currentBucket; + uint _endOffset; + + public: + AllEntriesEnumerator() : + _table(dac_cast(nullptr)), + _parser(), + _currentBucket(0), + _endOffset(0) + { + + } + + AllEntriesEnumerator(PTR_NativeHashtable table) + { + _table = table; + _currentBucket = 0; + if (_table != NULL) + { + _parser = _table->GetParserForBucket(_currentBucket, &_endOffset); + } + } + + NativeParser GetNext() + { + if (_table == NULL) + { + return NativeParser(); + } + + for (; ; ) + { + if (_parser.GetOffset() < _endOffset) + { + // Skip hashcode to get to the offset + _parser.GetUInt8(); + return _parser.GetParserFromRelativeOffset(); + } + + if (_currentBucket >= _table->_bucketMask) + { + return NativeParser(); + } + + _currentBucket++; + _parser = _table->GetParserForBucket(_currentBucket, &_endOffset); + } + } + }; + // // The enumerator does not conform to the regular C# enumerator pattern to avoid paying // its performance penalty (allocation, multiple calls per iteration) diff --git a/src/vm/readytoruninfo.cpp b/src/vm/readytoruninfo.cpp index e0eebb4..f995193 100644 --- a/src/vm/readytoruninfo.cpp +++ b/src/vm/readytoruninfo.cpp @@ -890,6 +890,98 @@ PCODE ReadyToRunInfo::MethodIterator::GetMethodStartAddress() return ret; } +BOOL ReadyToRunInfo::GenericMethodIterator::Next() +{ + m_current = m_enum.GetNext(); + return !m_current.IsNull(); +} + +MethodDesc *ReadyToRunInfo::GenericMethodIterator::GetMethodDesc_NoRestore() +{ + _ASSERTE(!m_current.IsNull()); + + HRESULT hr = S_OK; + + PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)m_current.GetBlob(); + SigPointer sig(pBlob); + + DWORD methodFlags = 0; + // Skip the signature so we can get to the offset + hr = sig.GetData(&methodFlags); + if (FAILED(hr)) + { + return NULL; + } + + if (methodFlags & ENCODE_METHOD_SIG_OwnerType) + { + hr = sig.SkipExactlyOne(); + if (FAILED(hr)) + { + return NULL; + } + } + + _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0); + _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0); + + RID rid; + hr = sig.GetData(&rid); + if (FAILED(hr)) + { + return NULL; + } + + if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) + { + DWORD numGenericArgs; + hr = sig.GetData(&numGenericArgs); + if (FAILED(hr)) + { + return NULL; + } + + for (DWORD i = 0; i < numGenericArgs; i++) + { + hr = sig.SkipExactlyOne(); + if (FAILED(hr)) + { + return NULL; + } + } + } + + // Now that we have the size of the signature we can grab the offset and decode it + PCCOR_SIGNATURE pSigNew; + DWORD cbSigNew; + sig.GetSignature(&pSigNew, &cbSigNew); + uint offset = m_current.GetOffset() + (uint)(pSigNew - pBlob); + + uint id; + offset = m_pInfo->m_nativeReader.DecodeUnsigned(offset, &id); + + if (id & 1) + { + if (id & 2) + { + uint val; + m_pInfo->m_nativeReader.DecodeUnsigned(offset, &val); + offset -= val; + } + + id >>= 2; + } + else + { + id >>= 1; + } + + _ASSERTE(id < m_pInfo->m_nRuntimeFunctions); + PCODE pEntryPoint = dac_cast(m_pInfo->m_pLayout->GetBase()) + m_pInfo->m_pRuntimeFunctions[id].BeginAddress; + + return m_pInfo->GetMethodDescForEntryPoint(pEntryPoint); +} + DWORD ReadyToRunInfo::GetFieldBaseOffset(MethodTable * pMT) { STANDARD_VM_CONTRACT; diff --git a/src/vm/readytoruninfo.h b/src/vm/readytoruninfo.h index 65b49a6..597bf68 100644 --- a/src/vm/readytoruninfo.h +++ b/src/vm/readytoruninfo.h @@ -118,8 +118,9 @@ public: int m_methodDefIndex; public: - MethodIterator(ReadyToRunInfo * pInfo) - : m_pInfo(pInfo), m_methodDefIndex(-1) + MethodIterator(ReadyToRunInfo * pInfo) : + m_pInfo(pInfo), + m_methodDefIndex(-1) { } @@ -130,6 +131,31 @@ public: PCODE GetMethodStartAddress(); }; + class GenericMethodIterator + { + ReadyToRunInfo *m_pInfo; + NativeFormat::NativeHashtable::AllEntriesEnumerator m_enum; + NativeFormat::NativeParser m_current; + + public: + GenericMethodIterator(ReadyToRunInfo *pInfo) : + m_pInfo(pInfo), + m_enum(), + m_current() + { + NativeFormat::PTR_NativeHashtable pHash = NULL; + if (!pInfo->m_instMethodEntryPoints.IsNull()) + { + pHash = NativeFormat::PTR_NativeHashtable(&pInfo->m_instMethodEntryPoints); + } + + m_enum = NativeFormat::NativeHashtable::AllEntriesEnumerator(pHash); + } + + BOOL Next(); + MethodDesc * GetMethodDesc_NoRestore(); + }; + static DWORD GetFieldBaseOffset(MethodTable * pMT); PTR_PersistentInlineTrackingMapR2R GetInlineTrackingMap() -- 2.7.4