Improve async stepping code.
authorMikhail Kurinnoi <m.kurinnoi@samsung.com>
Mon, 28 Mar 2022 16:10:01 +0000 (19:10 +0300)
committerAlexander Soldatov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Tue, 5 Apr 2022 14:54:54 +0000 (17:54 +0300)
src/managed/SymbolReader.cs
src/managed/interop.cpp
src/managed/interop.h
src/metadata/modules.cpp
src/metadata/modules.h

index 889bf28da436dd6fc819997e59c9516a05913697..2f8ec8ab3bf784674971b4058fcf8e4d4f916223 100644 (file)
@@ -344,45 +344,6 @@ namespace NetCoreDbg
             }
         }
 
-        /// <summary>
-        /// Find and return last method's offset for user code.
-        /// </summary>
-        /// <param name="assemblyPath">file path of the assembly or null if the module is in-memory or dynamic</param>
-        /// <param name="methodToken">method token</param>
-        /// <param name="LastIlOffset">return last found IL offset in user code</param>
-        /// <returns>"Ok" if last IL offset was found</returns>
-        internal static RetCode GetMethodLastIlOffset(IntPtr symbolReaderHandle, int methodToken, out uint LastIlOffset)
-        {
-            Debug.Assert(symbolReaderHandle != IntPtr.Zero);
-
-            LastIlOffset = 0;
-            bool foundOffset = false;
-
-            try
-            {
-                GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle);
-                MetadataReader reader = ((OpenedReader)gch.Target).Reader;
-
-                // We don't use LINQ in order to reduce memory consumption for managed part, so, Reverse() usage not an option here.
-                // Note, SequencePointCollection is IEnumerable based collections.
-                foreach (SequencePoint p in GetSequencePointCollection(methodToken, reader))
-                {
-                    if (p.StartLine == 0 || p.StartLine == SequencePoint.HiddenLine || p.Offset < 0)
-                        continue;
-
-                    // Method's IL start only from 0, use uint for IL offset.
-                    LastIlOffset = (uint)p.Offset;
-                    foundOffset = true;
-                }
-            }
-            catch
-            {
-                return RetCode.Exception;
-            }
-
-            return foundOffset ? RetCode.OK : RetCode.Fail;
-        }
-
         [StructLayout(LayoutKind.Sequential)]
         internal struct method_data_t
         {
@@ -1264,17 +1225,22 @@ namespace NetCoreDbg
         }
 
         /// <summary>
-        /// Helper method to return all async methods stepping information.
+        /// Helper method to return async method stepping information and return last method's offset for user code.
         /// </summary>
         /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
-        /// <param name="asyncInfo">array with all async methods stepping information</param>
+        /// <param name="methodToken">method token</param>
+        /// <param name="asyncInfo">array with all async method stepping information</param>
         /// <param name="asyncInfoCount">entry's count in asyncInfo</param>
-        internal static RetCode GetAsyncMethodsSteppingInfo(IntPtr symbolReaderHandle, out IntPtr asyncInfo, out int asyncInfoCount)
+        /// <param name="LastIlOffset">return last found IL offset in user code</param>
+        /// <returns>"Ok" if method have at least one await block and last IL offset was found</returns>
+        internal static RetCode GetAsyncMethodSteppingInfo(IntPtr symbolReaderHandle, int methodToken, out IntPtr asyncInfo, out int asyncInfoCount, out uint LastIlOffset)
         {
             Debug.Assert(symbolReaderHandle != IntPtr.Zero);
 
             asyncInfo = IntPtr.Zero;
             asyncInfoCount = 0;
+            LastIlOffset = 0;
+            bool foundOffset = false;
             var list = new List<AsyncAwaitInfoBlock>();
 
             try
@@ -1282,42 +1248,44 @@ namespace NetCoreDbg
                 GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle);
                 MetadataReader reader = ((OpenedReader)gch.Target).Reader;
 
+                Handle handle = MetadataTokens.Handle(methodToken);
+                if (handle.Kind != HandleKind.MethodDefinition)
+                    return RetCode.Fail;
+
+                MethodDebugInformationHandle methodDebugInformationHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle();
+                var entityHandle = MetadataTokens.EntityHandle(MetadataTokens.GetToken(methodDebugInformationHandle.ToDefinitionHandle()));
+
                 // Guid is taken from Roslyn source code:
                 // https://github.com/dotnet/roslyn/blob/afd10305a37c0ffb2cfb2c2d8446154c68cfa87a/src/Dependencies/CodeAnalysis.Debugging/PortableCustomDebugInfoKinds.cs#L13
                 Guid asyncMethodSteppingInformationBlob = new Guid("54FD2AC5-E925-401A-9C2A-F94F171072F8");
 
-                foreach (MethodDebugInformationHandle methodDebugInformationHandle in reader.MethodDebugInformation)
+                foreach (var cdiHandle in reader.GetCustomDebugInformation(entityHandle))
                 {
-                    var entityHandle = MetadataTokens.EntityHandle(MetadataTokens.GetToken(methodDebugInformationHandle.ToDefinitionHandle()));
+                    var cdi = reader.GetCustomDebugInformation(cdiHandle);
 
-                    foreach (var cdiHandle in reader.GetCustomDebugInformation(entityHandle))
+                    if (reader.GetGuid(cdi.Kind) == asyncMethodSteppingInformationBlob)
                     {
-                        var cdi = reader.GetCustomDebugInformation(cdiHandle);
-
-                        if (reader.GetGuid(cdi.Kind) == asyncMethodSteppingInformationBlob)
-                        {
-                            // Format of this blob is taken from Roslyn source code:
-                            // https://github.com/dotnet/roslyn/blob/afd10305a37c0ffb2cfb2c2d8446154c68cfa87a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs#L575
+                        // Format of this blob is taken from Roslyn source code:
+                        // https://github.com/dotnet/roslyn/blob/afd10305a37c0ffb2cfb2c2d8446154c68cfa87a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs#L575
 
-                            var blobReader = reader.GetBlobReader(cdi.Value);
-                            blobReader.ReadUInt32(); // skip catch_handler_offset
+                        var blobReader = reader.GetBlobReader(cdi.Value);
+                        blobReader.ReadUInt32(); // skip catch_handler_offset
 
-                            while (blobReader.Offset < blobReader.Length)
-                            {
-                                list.Add(new AsyncAwaitInfoBlock() {
-                                    yield_offset = blobReader.ReadUInt32(),
-                                    resume_offset = blobReader.ReadUInt32(),
-                                    // explicit conversion from int into uint here, see:
-                                    // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.metadata.blobreader.readcompressedinteger
-                                    token = (uint)blobReader.ReadCompressedInteger()
-                                });
-                            }
+                        while (blobReader.Offset < blobReader.Length)
+                        {
+                            list.Add(new AsyncAwaitInfoBlock() {
+                                yield_offset = blobReader.ReadUInt32(),
+                                resume_offset = blobReader.ReadUInt32(),
+                                // explicit conversion from int into uint here, see:
+                                // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.metadata.blobreader.readcompressedinteger
+                                token = (uint)blobReader.ReadCompressedInteger()
+                            });
                         }
                     }
                 }
 
                 if (list.Count == 0)
-                    return RetCode.OK;
+                    return RetCode.Fail;
 
                 int structSize = Marshal.SizeOf<AsyncAwaitInfoBlock>();
                 asyncInfo = Marshal.AllocCoTaskMem(list.Count * structSize);
@@ -1330,6 +1298,27 @@ namespace NetCoreDbg
                 }
 
                 asyncInfoCount = list.Count;
+
+                // We don't use LINQ in order to reduce memory consumption for managed part, so, Reverse() usage not an option here.
+                // Note, SequencePointCollection is IEnumerable based collections.
+                foreach (SequencePoint p in GetSequencePointCollection(methodToken, reader))
+                {
+                    if (p.StartLine == 0 || p.StartLine == SequencePoint.HiddenLine || p.Offset < 0)
+                        continue;
+
+                    // Method's IL start only from 0, use uint for IL offset.
+                    LastIlOffset = (uint)p.Offset;
+                    foundOffset = true;
+                }
+
+                if (!foundOffset)
+                {
+                    if (asyncInfo != IntPtr.Zero)
+                        Marshal.FreeCoTaskMem(asyncInfo);
+
+                    asyncInfo = IntPtr.Zero;
+                    return RetCode.Fail;
+                }
             }
             catch
             {
index e12387b6259e0df5c45a668788ade7e739978296..c652ecc2f05809b0e3fc6ccc87326094c975c9d5 100644 (file)
@@ -65,8 +65,7 @@ typedef  RetCode (*GetNextSequencePointByILOffsetDelegate)(PVOID, mdMethodDef, u
 typedef  RetCode (*GetStepRangesFromIPDelegate)(PVOID, int32_t, mdMethodDef, uint32_t*, uint32_t*);
 typedef  RetCode (*GetModuleMethodsRangesDelegate)(PVOID, int32_t, PVOID, int32_t, PVOID, PVOID*);
 typedef  RetCode (*ResolveBreakPointsDelegate)(PVOID, int32_t, PVOID, int32_t, int32_t, int32_t*, PVOID*);
-typedef  RetCode (*GetMethodLastIlOffsetDelegate)(PVOID, mdMethodDef, uint32_t*);
-typedef  RetCode (*GetAsyncMethodsSteppingInfoDelegate)(PVOID, PVOID*, int32_t*);
+typedef  RetCode (*GetAsyncMethodSteppingInfoDelegate)(PVOID, mdMethodDef, PVOID*, int32_t*, uint32_t*);
 typedef  RetCode (*GetSourceDelegate)(PVOID, const WCHAR*, int32_t*, PVOID*);
 typedef  RetCode (*CalculationDelegate)(PVOID, int32_t, PVOID, int32_t, int32_t, int32_t*, PVOID*, BSTR*);
 typedef  int (*GenerateStackMachineProgramDelegate)(const WCHAR*, PVOID*, BSTR*);
@@ -87,8 +86,7 @@ GetNextSequencePointByILOffsetDelegate getNextSequencePointByILOffsetDelegate =
 GetStepRangesFromIPDelegate getStepRangesFromIPDelegate = nullptr;
 GetModuleMethodsRangesDelegate getModuleMethodsRangesDelegate = nullptr;
 ResolveBreakPointsDelegate resolveBreakPointsDelegate = nullptr;
-GetMethodLastIlOffsetDelegate getMethodLastIlOffsetDelegate = nullptr;
-GetAsyncMethodsSteppingInfoDelegate getAsyncMethodsSteppingInfoDelegate = nullptr;
+GetAsyncMethodSteppingInfoDelegate getAsyncMethodSteppingInfoDelegate = nullptr;
 GetSourceDelegate getSourceDelegate = nullptr;
 GenerateStackMachineProgramDelegate generateStackMachineProgramDelegate = nullptr;
 ReleaseStackMachineProgramDelegate releaseStackMachineProgramDelegate = nullptr;
@@ -231,8 +229,7 @@ void Init(const std::string &coreClrPath)
         SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, SymbolReaderClassName, "GetStepRangesFromIP", (void **)&getStepRangesFromIPDelegate)) &&
         SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, SymbolReaderClassName, "GetModuleMethodsRanges", (void **)&getModuleMethodsRangesDelegate)) &&
         SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, SymbolReaderClassName, "ResolveBreakPoints", (void **)&resolveBreakPointsDelegate)) &&
-        SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, SymbolReaderClassName, "GetMethodLastIlOffset", (void **)&getMethodLastIlOffsetDelegate)) &&
-        SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, SymbolReaderClassName, "GetAsyncMethodsSteppingInfo", (void **)&getAsyncMethodsSteppingInfoDelegate)) &&
+        SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, SymbolReaderClassName, "GetAsyncMethodSteppingInfo", (void **)&getAsyncMethodSteppingInfoDelegate)) &&
         SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, SymbolReaderClassName, "GetSource", (void **)&getSourceDelegate)) &&
         SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "CalculationDelegate", (void **)&calculationDelegate)) &&
         SUCCEEDED(Status = createDelegate(hostHandle, domainId, ManagedPartDllName, EvaluationClassName, "GenerateStackMachineProgram", (void **)&generateStackMachineProgramDelegate)) &&
@@ -256,8 +253,7 @@ void Init(const std::string &coreClrPath)
                               getStepRangesFromIPDelegate &&
                               getModuleMethodsRangesDelegate &&
                               resolveBreakPointsDelegate &&
-                              getMethodLastIlOffsetDelegate &&
-                              getAsyncMethodsSteppingInfoDelegate &&
+                              getAsyncMethodSteppingInfoDelegate &&
                               getSourceDelegate &&
                               generateStackMachineProgramDelegate &&
                               releaseStackMachineProgramDelegate &&
@@ -295,8 +291,7 @@ void Shutdown()
     getStepRangesFromIPDelegate = nullptr;
     getModuleMethodsRangesDelegate = nullptr;
     resolveBreakPointsDelegate = nullptr;
-    getMethodLastIlOffsetDelegate = nullptr;
-    getAsyncMethodsSteppingInfoDelegate = nullptr;
+    getAsyncMethodSteppingInfoDelegate = nullptr;
     getSourceDelegate = nullptr;
     stringToUpperDelegate = nullptr;
     coTaskMemAllocDelegate = nullptr;
@@ -401,16 +396,6 @@ HRESULT CalculationDelegate(PVOID firstOp, int32_t firstType, PVOID secondOp, in
     return S_OK;
 }
 
-HRESULT GetMethodLastIlOffset(PVOID pSymbolReaderHandle, mdMethodDef methodToken, ULONG32 *ilOffset)
-{
-    std::unique_lock<Utility::RWLock::Reader> read_lock(CLRrwlock.reader);
-    if (!getMethodLastIlOffsetDelegate || !pSymbolReaderHandle || !ilOffset)
-        return E_FAIL;
-
-    RetCode retCode = getMethodLastIlOffsetDelegate(pSymbolReaderHandle, methodToken, ilOffset);
-    return retCode == RetCode::OK ? S_OK : E_FAIL;
-}
-
 HRESULT GetModuleMethodsRanges(PVOID pSymbolReaderHandle, int32_t constrTokensNum, PVOID constrTokens, int32_t normalTokensNum, PVOID normalTokens, PVOID *data)
 {
     std::unique_lock<Utility::RWLock::Reader> read_lock(CLRrwlock.reader);
@@ -431,16 +416,16 @@ HRESULT ResolveBreakPoints(PVOID pSymbolReaderHandle, int32_t tokenNum, PVOID To
     return retCode == RetCode::OK ? S_OK : E_FAIL;
 }
 
-HRESULT GetAsyncMethodsSteppingInfo(PVOID pSymbolReaderHandle, std::vector<AsyncAwaitInfoBlock> &AsyncAwaitInfo)
+HRESULT GetAsyncMethodSteppingInfo(PVOID pSymbolReaderHandle, mdMethodDef methodToken, std::vector<AsyncAwaitInfoBlock> &AsyncAwaitInfo, ULONG32 *ilOffset)
 {
     std::unique_lock<Utility::RWLock::Reader> read_lock(CLRrwlock.reader);
-    if (!getAsyncMethodsSteppingInfoDelegate || !pSymbolReaderHandle)
+    if (!getAsyncMethodSteppingInfoDelegate || !pSymbolReaderHandle || !ilOffset)
         return E_FAIL;
 
     AsyncAwaitInfoBlock *allocatedAsyncInfo = nullptr;
     int32_t asyncInfoCount = 0;
 
-    RetCode retCode = getAsyncMethodsSteppingInfoDelegate(pSymbolReaderHandle, (PVOID*)&allocatedAsyncInfo, &asyncInfoCount);
+    RetCode retCode = getAsyncMethodSteppingInfoDelegate(pSymbolReaderHandle, methodToken, (PVOID*)&allocatedAsyncInfo, &asyncInfoCount, ilOffset);
     read_lock.unlock();
 
     if (retCode != RetCode::OK)
index 20cd60235483702ebd6c34ed91a8ab4a8b5c2f54..2d530e1f7c32dcc65799aaebdd191948dce2d26b 100644 (file)
@@ -92,10 +92,9 @@ namespace Interop
                                           WCHAR *localName, ULONG localNameLen, ULONG32 *pIlStart, ULONG32 *pIlEnd);
     HRESULT GetHoistedLocalScopes(PVOID pSymbolReaderHandle, mdMethodDef methodToken, PVOID *data, int32_t &hoistedLocalScopesCount);
     HRESULT GetStepRangesFromIP(PVOID pSymbolReaderHandle, ULONG32 ip, mdMethodDef MethodToken, ULONG32 *ilStartOffset, ULONG32 *ilEndOffset);
-    HRESULT GetMethodLastIlOffset(PVOID pSymbolReaderHandle, mdMethodDef methodToken, ULONG32 *ilOffset);
     HRESULT GetModuleMethodsRanges(PVOID pSymbolReaderHandle, int32_t constrTokensNum, PVOID constrTokens, int32_t normalTokensNum, PVOID normalTokens, PVOID *data);
     HRESULT ResolveBreakPoints(PVOID pSymbolReaderHandle, int32_t tokenNum, PVOID Tokens, int32_t sourceLine, int32_t nestedToken, int32_t &Count, PVOID *data);
-    HRESULT GetAsyncMethodsSteppingInfo(PVOID pSymbolReaderHandle, std::vector<AsyncAwaitInfoBlock> &AsyncAwaitInfo);
+    HRESULT GetAsyncMethodSteppingInfo(PVOID pSymbolReaderHandle, mdMethodDef methodToken, std::vector<AsyncAwaitInfoBlock> &AsyncAwaitInfo, ULONG32 *ilOffset);
     HRESULT GetSource(PVOID symbolReaderHandle, const std::string fileName, PVOID *data, int32_t *length);
     HRESULT CalculationDelegate(PVOID firstOp, int32_t firstType, PVOID secondOp, int32_t secondType, int32_t operationType, int32_t &resultType, PVOID *data, std::string &errorText);
     HRESULT GenerateStackMachineProgram(const std::string &expr, PVOID *ppStackProgram, std::string &textOutput);
index 176a60084683da8265b7e5e24ed71ec17173f8b5..a8bf1e3d0aef73bf7c11a89d47d5a96e5a6b6dbb 100644 (file)
@@ -630,29 +630,37 @@ HRESULT GetModuleId(ICorDebugModule *pModule, std::string &id)
     return S_OK;
 }
 
-// Fill m_asyncMethodsSteppingInfo by data from module. Called on callback during module load.
-// [in] pModule - object that represents the CLR module;
-// [in] pSymbolReaderHandle - pointer to managed part GCHandle with preloaded PDB.
-HRESULT Modules::FillAsyncMethodsSteppingInfo(ICorDebugModule *pModule, PVOID pSymbolReaderHandle)
+// Caller must care about m_asyncMethodSteppingInfoMutex.
+HRESULT Modules::GetAsyncMethodSteppingInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToken)
 {
-    HRESULT Status;
-    CORDB_ADDRESS modAddress;
-    IfFailRet(pModule->GetBaseAddress(&modAddress));
+    if (asyncMethodSteppingInfo.modAddress == modAddress &&
+        asyncMethodSteppingInfo.methodToken == methodToken)
+        return S_OK;
 
-    std::vector<Interop::AsyncAwaitInfoBlock> AsyncAwaitInfo;
-    IfFailRet(Interop::GetAsyncMethodsSteppingInfo(pSymbolReaderHandle, AsyncAwaitInfo));
+    if (!asyncMethodSteppingInfo.awaits.empty())
+        asyncMethodSteppingInfo.awaits.clear();
 
-    const std::lock_guard<std::mutex> lock(m_asyncMethodsSteppingInfoMutex);
+    std::lock_guard<std::mutex> lock(m_modulesInfoMutex);
+    auto info_pair = m_modulesInfo.find(modAddress);
+    if (info_pair == m_modulesInfo.end())
+    {
+        return E_FAIL;
+    }
+
+    ModuleInfo &mdInfo = info_pair->second;
+
+    HRESULT Status;
+    std::vector<Interop::AsyncAwaitInfoBlock> AsyncAwaitInfo;
+    IfFailRet(Interop::GetAsyncMethodSteppingInfo(mdInfo.m_symbolReaderHandle, methodToken, AsyncAwaitInfo, &asyncMethodSteppingInfo.lastIlOffset));
 
     for (const auto &entry : AsyncAwaitInfo)
     {
-        mdMethodDef realToken = mdMethodDefNil + entry.token;
-        std::pair<CORDB_ADDRESS, mdMethodDef> newKey = std::make_pair(modAddress, realToken);
-        m_asyncMethodsSteppingInfo[newKey].awaits.emplace_back(entry.yield_offset, entry.resume_offset);
-
-        IfFailRet(Interop::GetMethodLastIlOffset(pSymbolReaderHandle, realToken, &m_asyncMethodsSteppingInfo[newKey].lastIlOffset));
+        asyncMethodSteppingInfo.awaits.emplace_back(entry.yield_offset, entry.resume_offset);
     }
 
+    asyncMethodSteppingInfo.modAddress = modAddress;
+    asyncMethodSteppingInfo.methodToken = methodToken;
+
     return S_OK;
 }
 
@@ -661,10 +669,9 @@ HRESULT Modules::FillAsyncMethodsSteppingInfo(ICorDebugModule *pModule, PVOID pS
 // [in] methodToken - method token (from module with address modAddress).
 bool Modules::IsMethodHaveAwait(CORDB_ADDRESS modAddress, mdMethodDef methodToken)
 {
-    const std::lock_guard<std::mutex> lock(m_asyncMethodsSteppingInfoMutex);
+    const std::lock_guard<std::mutex> lock(m_asyncMethodSteppingInfoMutex);
 
-    auto searchAsyncInfo = m_asyncMethodsSteppingInfo.find(std::make_pair(modAddress, methodToken));
-    return searchAsyncInfo != m_asyncMethodsSteppingInfo.end();
+    return SUCCEEDED(GetAsyncMethodSteppingInfo(modAddress, methodToken));
 }
 
 // Find await block after IL offset in particular async method and return await info, if present.
@@ -675,13 +682,12 @@ bool Modules::IsMethodHaveAwait(CORDB_ADDRESS modAddress, mdMethodDef methodToke
 // [out] awaitInfo - result, next await info.
 bool Modules::FindNextAwaitInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToken, ULONG32 ipOffset, AwaitInfo **awaitInfo)
 {
-    const std::lock_guard<std::mutex> lock(m_asyncMethodsSteppingInfoMutex);
+    const std::lock_guard<std::mutex> lock(m_asyncMethodSteppingInfoMutex);
 
-    auto searchAsyncInfo = m_asyncMethodsSteppingInfo.find(std::make_pair(modAddress, methodToken));
-    if (searchAsyncInfo == m_asyncMethodsSteppingInfo.end())
+    if (FAILED(GetAsyncMethodSteppingInfo(modAddress, methodToken)))
         return false;
 
-    for (auto &await : searchAsyncInfo->second.awaits)
+    for (auto &await : asyncMethodSteppingInfo.awaits)
     {
         if (ipOffset <= await.yield_offset)
         {
@@ -707,13 +713,12 @@ bool Modules::FindNextAwaitInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToke
 // [out] lastIlOffset - result, IL offset for last user code line in async method.
 bool Modules::FindLastIlOffsetAwaitInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToken, ULONG32 &lastIlOffset)
 {
-    const std::lock_guard<std::mutex> lock(m_asyncMethodsSteppingInfoMutex);
+    const std::lock_guard<std::mutex> lock(m_asyncMethodSteppingInfoMutex);
 
-    auto searchAsyncInfo = m_asyncMethodsSteppingInfo.find(std::make_pair(modAddress, methodToken));
-    if (searchAsyncInfo == m_asyncMethodsSteppingInfo.end())
+    if (FAILED(GetAsyncMethodSteppingInfo(modAddress, methodToken)))
         return false;
 
-    lastIlOffset = searchAsyncInfo->second.lastIlOffset;
+    lastIlOffset = asyncMethodSteppingInfo.lastIlOffset;
     return true;
 }
 
@@ -796,9 +801,6 @@ HRESULT Modules::TryLoadModuleSymbols(ICorDebugModule *pModule, Module &module,
 
         if (FAILED(FillSourcesCodeLinesForModule(pModule, pMDImport, pSymbolReaderHandle)))
             LOGE("Could not load source lines related info from PDB file. Could produce failures during breakpoint's source path resolve in future.");
-
-        if (FAILED(FillAsyncMethodsSteppingInfo(pModule, pSymbolReaderHandle)))
-            LOGE("Could not load async methods related info from PDB file. Could produce failures during stepping in async methods in future.");
     }
 
     IfFailRet(GetModuleId(pModule, module.id));
index 5c866d60b522655c931757a587d466f447526662..74a8cb81ba52f79ff60a684fde8398597cf3cef6 100644 (file)
@@ -294,35 +294,30 @@ public:
         {};
     };
 
+    bool IsMethodHaveAwait(CORDB_ADDRESS modAddress, mdMethodDef methodToken);
+    bool FindNextAwaitInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToken, ULONG32 ipOffset, AwaitInfo **awaitInfo);
+    bool FindLastIlOffsetAwaitInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToken, ULONG32 &lastIlOffset);
+
+private:
+
     struct AsyncMethodInfo
     {
+        CORDB_ADDRESS modAddress;
+        mdMethodDef methodToken;
+
         std::vector<AwaitInfo> awaits;
         // Part of NotifyDebuggerOfWaitCompletion magic, see ManagedDebugger::SetupAsyncStep().
         ULONG32 lastIlOffset;
 
         AsyncMethodInfo() :
-            awaits(), lastIlOffset(0)
+            modAddress(0), methodToken(mdMethodDefNil), awaits(), lastIlOffset(0)
         {};
     };
 
-    bool IsMethodHaveAwait(CORDB_ADDRESS modAddress, mdMethodDef methodToken);
-    bool FindNextAwaitInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToken, ULONG32 ipOffset, AwaitInfo **awaitInfo);
-    bool FindLastIlOffsetAwaitInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToken, ULONG32 &lastIlOffset);
-
-private:
-
-    struct PairHash
-    {
-        template <class T1, class T2>
-        size_t operator()(const std::pair<T1, T2> &pair) const
-        {
-            return std::hash<T1>{}(pair.first) ^ std::hash<T2>{}(pair.second);
-        }
-    };
-    // All async methods stepping information for all loaded (with symbols) modules.
-    std::unordered_map<std::pair<CORDB_ADDRESS, mdMethodDef>, AsyncMethodInfo, PairHash> m_asyncMethodsSteppingInfo;
-    std::mutex m_asyncMethodsSteppingInfoMutex;
-    HRESULT FillAsyncMethodsSteppingInfo(ICorDebugModule *pModule, PVOID pSymbolReaderHandle);
+    AsyncMethodInfo asyncMethodSteppingInfo;
+    std::mutex m_asyncMethodSteppingInfoMutex;
+    // Note, result stored into asyncMethodSteppingInfo.
+    HRESULT GetAsyncMethodSteppingInfo(CORDB_ADDRESS modAddress, mdMethodDef methodToken);
 };
 
 } // namespace netcoredbg