From bd8558cd2163ce8a1ad8f66a287a1f5a8046dda3 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 12 Aug 2026 18:51:41 -0700 Subject: [PATCH] enable cache fallback --- .../ExecutionManager/ExecutionManagerCore.cs | 29 ++- .../Contracts/RuntimeTypeSystem_1.cs | 180 ++++++++++-------- .../ExecutionManager/ExecutionManagerTests.cs | 5 + .../cdac/tests/UnitTests/MethodDescTests.cs | 6 + .../cdac/tests/UnitTests/MethodTableTests.cs | 4 + 5 files changed, 134 insertions(+), 90 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs index 1e7fad5357992c..d0c16c3449704b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs @@ -220,6 +220,20 @@ internal static RangeSection Find(Target target, Data.RangeSectionMap topRangeSe return null; } } + + private CodeBlock GetOrCreateCodeBlock(CodeBlockHandle codeInfoHandle) + { + if (_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info)) + return info; + + info = GetCodeBlock(new TargetCodePointer(codeInfoHandle.Address.Value)); + if (info is null || !info.Valid) + throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}"); + + _codeInfos.TryAdd(codeInfoHandle.Address, info); + return info; + } + CodeBlockHandle? IExecutionManager.GetCodeBlockHandle(TargetCodePointer ip) { TargetPointer key = ip.AsTargetPointer; // FIXME: thumb bit. It's harmless (we potentialy have 2 cache entries per IP), but we should fix it @@ -238,16 +252,14 @@ internal static RangeSection Find(Target target, Data.RangeSectionMap topRangeSe TargetPointer IExecutionManager.GetMethodDesc(CodeBlockHandle codeInfoHandle) { - if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info)) - throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}"); + CodeBlock info = GetOrCreateCodeBlock(codeInfoHandle); return info.MethodDescAddress; } TargetPointer IExecutionManager.GetStartAddress(CodeBlockHandle codeInfoHandle) { - if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info)) - throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}"); + CodeBlock info = GetOrCreateCodeBlock(codeInfoHandle); return info.StartAddress; } @@ -338,8 +350,7 @@ bool IExecutionManager.IsFunclet(CodeBlockHandle codeInfoHandle) bool IExecutionManager.IsFilterFunclet(CodeBlockHandle codeInfoHandle) { - if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info)) - throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}"); + CodeBlock info = GetOrCreateCodeBlock(codeInfoHandle); IExecutionManager eman = this; @@ -406,8 +417,7 @@ void IExecutionManager.GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPoint TargetNUInt IExecutionManager.GetRelativeOffset(CodeBlockHandle codeInfoHandle) { - if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info)) - throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}"); + CodeBlock info = GetOrCreateCodeBlock(codeInfoHandle); return info.RelativeOffset; } @@ -539,8 +549,7 @@ IReadOnlyList IExecutionManager.GetDynamicFunctionTableEntries(Ta private RangeSection RangeSectionFromCodeBlockHandle(CodeBlockHandle codeInfoHandle) { - if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info)) - throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}"); + _ = GetOrCreateCodeBlock(codeInfoHandle); RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, codeInfoHandle.Address.Value); return range; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index fbe6e2265d3707..f14397a388e299 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -56,6 +56,30 @@ private TargetTypeHandle GetOrCreateTargetTypeHandle(TargetPointer address) return handle; } + private MethodTable GetOrCreateMethodTable(ITypeHandle typeHandle) + { + MethodTable methodTable; + if (!_methodTables.TryGetValue(typeHandle.Address, out methodTable)) + { + _ = GetTypeHandle(typeHandle.Address); + methodTable = _methodTables[typeHandle.Address]; + } + + return methodTable; + } + + private MethodDesc GetOrCreateMethodDesc(MethodDescHandle methodDescHandle) + { + MethodDesc methodDesc; + if (!_methodDescs.TryGetValue(methodDescHandle.Address, out methodDesc)) + { + _ = GetMethodDescHandle(methodDescHandle.Address); + methodDesc = _methodDescs[methodDescHandle.Address]; + } + + return methodDesc; + } + internal struct MethodTable { internal MethodTableFlags_1 Flags { get; } @@ -539,7 +563,7 @@ public TargetPointer GetModule(ITypeHandle typeHandle) { if (typeHandle.IsMethodTable()) { - return _methodTables[typeHandle.Address].Module; + return GetOrCreateMethodTable(typeHandle).Module; } else if (typeHandle.IsTypeDesc()) { @@ -563,20 +587,20 @@ public TargetPointer GetModule(ITypeHandle typeHandle) } } public TargetPointer GetCanonicalMethodTable(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).MethodTable; - public bool IsCanonicalMethodTable(ITypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].IsCanonMT; - public TargetPointer GetParentMethodTable(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : _methodTables[typeHandle.Address].ParentMethodTable; + public bool IsCanonicalMethodTable(ITypeHandle typeHandle) => typeHandle.IsMethodTable() && GetOrCreateMethodTable(typeHandle).IsCanonMT; + public TargetPointer GetParentMethodTable(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetOrCreateMethodTable(typeHandle).ParentMethodTable; - public uint GetBaseSize(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize; + public uint GetBaseSize(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : GetOrCreateMethodTable(typeHandle).Flags.BaseSize; - public uint GetNumInstanceFieldBytes(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.BaseSize - GetClassData(typeHandle).BaseSizePadding; + public uint GetNumInstanceFieldBytes(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : GetOrCreateMethodTable(typeHandle).Flags.BaseSize - GetClassData(typeHandle).BaseSizePadding; - public uint GetComponentSize(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : _methodTables[typeHandle.Address].Flags.ComponentSize; + public uint GetComponentSize(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : GetOrCreateMethodTable(typeHandle).Flags.ComponentSize; private TargetPointer GetClassPointer(ITypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) return TargetPointer.Null; - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); switch (MethodTableFlags_1.GetEEClassOrCanonMTBits(methodTable.EEClassOrCanonMT)) { case MethodTableFlags_1.EEClassOrCanonMTBits.EEClass: @@ -584,7 +608,7 @@ private TargetPointer GetClassPointer(ITypeHandle typeHandle) case MethodTableFlags_1.EEClassOrCanonMTBits.CanonMT: TargetPointer canonMTPtr = MethodTableFlags_1.UntagEEClassOrCanonMT(methodTable.EEClassOrCanonMT); ITypeHandle canonMTHandle = GetTypeHandle(canonMTPtr); - MethodTable canonMT = _methodTables[canonMTHandle.Address]; + MethodTable canonMT = GetOrCreateMethodTable(canonMTHandle); return canonMT.EEClassOrCanonMT; // canonical method table EEClassOrCanonMT is always EEClass default: throw new InvalidOperationException(); @@ -634,7 +658,7 @@ private Data.EEClass GetClassData(ITypeHandle typeHandle) public bool IsObject(ITypeHandle typeHandle) => ObjectMethodTablePointer != TargetPointer.Null && ObjectMethodTablePointer == typeHandle.Address; - public bool IsString(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.IsString; + public bool IsString(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : GetOrCreateMethodTable(typeHandle).Flags.IsString; public bool IsCorElementTypeObjRef(CorElementType elementType) => elementType is CorElementType.Class @@ -663,8 +687,8 @@ public TargetPointer GetWellKnownMethodTable(WellKnownMethodTable kind) return value; } - public bool ContainsGCPointers(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers; - public bool IsByRefLike(ITypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].Flags.IsByRefLike; + public bool ContainsGCPointers(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : GetOrCreateMethodTable(typeHandle).Flags.ContainsGCPointers; + public bool IsByRefLike(ITypeHandle typeHandle) => typeHandle.IsMethodTable() && GetOrCreateMethodTable(typeHandle).Flags.IsByRefLike; private bool IsFeatureHfaTarget(out RuntimeInfoArchitecture arch) { @@ -679,7 +703,7 @@ public bool TryGetHFAElementSize(ITypeHandle typeHandle, out int elementSize) if (!IsFeatureHfaTarget(out RuntimeInfoArchitecture arch)) return false; - if (!typeHandle.IsMethodTable() || !_methodTables[typeHandle.Address].Flags.IsHFA) + if (!typeHandle.IsMethodTable() || !GetOrCreateMethodTable(typeHandle).Flags.IsHFA) return false; // ARM shortcut: no HVA, and RequiresAlign8 encodes the R4-vs-R8 choice @@ -687,7 +711,7 @@ public bool TryGetHFAElementSize(ITypeHandle typeHandle, out int elementSize) // type). Avoids walking fields. if (arch == RuntimeInfoArchitecture.Arm) { - elementSize = _methodTables[typeHandle.Address].Flags.RequiresAlign8 ? 8 : 4; + elementSize = GetOrCreateMethodTable(typeHandle).Flags.RequiresAlign8 ? 8 : 4; return true; } @@ -740,7 +764,7 @@ public bool TryGetHFAElementSize(ITypeHandle typeHandle, out int elementSize) // metadata decode failure returns 0 (treated as "not an HVA"). private int GetVectorHFAElementSize(ITypeHandle typeHandle) { - if (!typeHandle.IsMethodTable() || !_methodTables[typeHandle.Address].Flags.IsIntrinsicType) + if (!typeHandle.IsMethodTable() || !GetOrCreateMethodTable(typeHandle).Flags.IsIntrinsicType) return 0; try @@ -813,10 +837,10 @@ private static bool IsCorNumericalType(CorElementType t) => (t >= CorElementType.I1 && t <= CorElementType.R8) || t == CorElementType.I || t == CorElementType.U; - public bool RequiresAlign8(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8; + public bool RequiresAlign8(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : GetOrCreateMethodTable(typeHandle).Flags.RequiresAlign8; public bool IsContinuationWithoutMetadata(ITypeHandle typeHandle) => typeHandle.IsMethodTable() && ContinuationMethodTablePointer != TargetPointer.Null - && _methodTables[typeHandle.Address].ParentMethodTable == ContinuationMethodTablePointer + && GetOrCreateMethodTable(typeHandle).ParentMethodTable == ContinuationMethodTablePointer && ContinuationSingletonEEClassPointer != TargetPointer.Null && GetClassPointer(typeHandle) == ContinuationSingletonEEClassPointer; @@ -894,21 +918,21 @@ public bool IsContinuationWithoutMetadata(ITypeHandle typeHandle) => typeHandle. } } - public bool IsDynamicStatics(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.IsDynamicStatics; - public ushort GetNumInterfaces(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (ushort)0 : _methodTables[typeHandle.Address].NumInterfaces; + public bool IsDynamicStatics(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : GetOrCreateMethodTable(typeHandle).Flags.IsDynamicStatics; + public ushort GetNumInterfaces(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (ushort)0 : GetOrCreateMethodTable(typeHandle).NumInterfaces; public uint GetTypeDefToken(ITypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) return 0; - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); return (uint)(methodTable.Flags.GetTypeDefRid() | ((int)TableIndex.TypeDef << 24)); } public ushort GetNumVtableSlots(ITypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) return 0; - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); ushort numNonVirtualSlots = methodTable.IsCanonMT ? GetClassData(typeHandle).NumNonVirtualSlots : (ushort)0; return checked((ushort)(methodTable.NumVirtuals + numNonVirtualSlots)); } @@ -946,13 +970,13 @@ public IEnumerable GetFieldDescList(ITypeHandle typeHandle) int totalFields = numInstanceFields + GetNumStaticFields(typeHandle); return (fieldDescListPtr, fieldDescSize, totalFields); } - public bool IsTrackedReferenceWithFinalizer(ITypeHandle typeHandle) => typeHandle.IsMethodTable() && _methodTables[typeHandle.Address].Flags.IsTrackedReferenceWithFinalizer; + public bool IsTrackedReferenceWithFinalizer(ITypeHandle typeHandle) => typeHandle.IsMethodTable() && GetOrCreateMethodTable(typeHandle).Flags.IsTrackedReferenceWithFinalizer; private TargetPointer GetDynamicStaticsInfo(ITypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) return default; - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); if (!methodTable.Flags.IsDynamicStatics) return default; TargetPointer dynamicStaticsInfoSize = Data.DynamicStaticsInfo.GetSize(_target); @@ -962,7 +986,7 @@ private TargetPointer GetDynamicStaticsInfo(ITypeHandle typeHandle) private Data.ThreadStaticsInfo GetThreadStaticsInfo(ITypeHandle typeHandle) { - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); TargetPointer threadStaticsInfoSize = Data.ThreadStaticsInfo.GetSize(_target); TargetPointer threadStaticsInfoAddr = methodTable.AuxiliaryData - threadStaticsInfoSize; Data.ThreadStaticsInfo threadStaticsInfo = _target.ProcessedData.GetOrAdd(threadStaticsInfoAddr); @@ -1010,7 +1034,7 @@ public ReadOnlySpan GetInstantiation(ITypeHandle typeHandle) if (!typeHandle.IsMethodTable()) return default; - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); if (!methodTable.Flags.HasInstantiation) return default; @@ -1021,7 +1045,7 @@ public bool IsClassInited(ITypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) return false; - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); MethodTableAuxiliaryData auxiliaryData = _target.ProcessedData.GetOrAdd(methodTable.AuxiliaryData); return (auxiliaryData.Flags & (uint)MethodTableAuxiliaryFlags.Initialized) != 0; } @@ -1030,7 +1054,7 @@ public bool IsInitError(ITypeHandle typeHandle) { if (!typeHandle.IsMethodTable()) return false; - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); MethodTableAuxiliaryData auxiliaryData = _target.ProcessedData.GetOrAdd(methodTable.AuxiliaryData); return (auxiliaryData.Flags & (uint)MethodTableAuxiliaryFlags.IsInitError) != 0; } @@ -1043,7 +1067,7 @@ private sealed class TypeInstantiation : IData private TypeInstantiation(Target target, TargetPointer typePointer) { RuntimeTypeSystem_1 rts = (RuntimeTypeSystem_1)target.Contracts.RuntimeTypeSystem; - MethodTable methodTable = rts._methodTables[typePointer]; + MethodTable methodTable = rts.GetOrCreateMethodTable(rts.GetTypeHandle(typePointer)); Debug.Assert(methodTable.Flags.HasInstantiation); TargetPointer perInstInfo = methodTable.PerInstInfo; @@ -1063,7 +1087,7 @@ private TypeInstantiation(Target target, TargetPointer typePointer) } } - public bool IsGenericTypeDefinition(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.IsGenericTypeDefinition; + public bool IsGenericTypeDefinition(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : GetOrCreateMethodTable(typeHandle).Flags.IsGenericTypeDefinition; public bool ContainsGenericVariables(ITypeHandle typeHandle) { if (typeHandle.IsTypeDesc()) @@ -1089,15 +1113,15 @@ public bool ContainsGenericVariables(ITypeHandle typeHandle) return false; } - return _methodTables[typeHandle.Address].Flags.ContainsGenericVariables; + return GetOrCreateMethodTable(typeHandle).Flags.ContainsGenericVariables; } - public bool IsCollectible(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.IsCollectible; + public bool IsCollectible(ITypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : GetOrCreateMethodTable(typeHandle).Flags.IsCollectible; public bool HasTypeParam(ITypeHandle typeHandle) { if (typeHandle.IsMethodTable()) { - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); return methodTable.Flags.IsArray; } else if (typeHandle.IsTypeDesc()) @@ -1119,7 +1143,7 @@ public CorElementType GetSignatureCorElementType(ITypeHandle typeHandle) { if (typeHandle.IsMethodTable()) { - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); switch (methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask)) { @@ -1163,7 +1187,7 @@ public bool IsValueType(ITypeHandle typeHandle) { if (typeHandle.IsMethodTable()) { - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); return methodTable.Flags.IsValueType; } else if (typeHandle.IsTypeDesc()) @@ -1183,7 +1207,7 @@ public bool IsEnum(ITypeHandle typeHandle) if (!typeHandle.IsMethodTable()) return false; - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); return methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask) == MethodTableFlags_1.WFLAGS_HIGH.Category_Primitive; } @@ -1201,7 +1225,7 @@ public bool IsArray(ITypeHandle typeHandle, out uint rank) { if (typeHandle.IsMethodTable()) { - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); switch (methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask)) { @@ -1226,7 +1250,7 @@ public ITypeHandle GetTypeParam(ITypeHandle typeHandle) { if (typeHandle.IsMethodTable()) { - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); if (!methodTable.Flags.IsArray) throw new ArgumentException(nameof(typeHandle)); @@ -1314,7 +1338,7 @@ private bool IsLoaded(ITypeHandle typeHandle) return (typeDesc.TypeAndFlags & (uint)TypeDescFlags.IsNotFullyLoaded) == 0; // IsUnloaded } - MethodTable methodTable = _methodTables[typeHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(typeHandle); Data.MethodTableAuxiliaryData auxData = _target.ProcessedData.GetOrAdd(methodTable.AuxiliaryData); return (auxData.Flags & (uint)MethodTableAuxiliaryFlags.IsNotFullyLoaded) == 0; // IsUnloaded } @@ -1531,7 +1555,7 @@ public TargetPointer GetLoaderModule(ITypeHandle typeHandle) } } - MethodTable mt = _methodTables[typeHandle.Address]; + MethodTable mt = GetOrCreateMethodTable(typeHandle); Data.MethodTableAuxiliaryData mtAuxData = _target.ProcessedData.GetOrAdd(mt.AuxiliaryData); return mtAuxData.LoaderModule; } @@ -1590,7 +1614,7 @@ private MethodDescHandle GetMethodDescHandle(TargetPointer methodDescPointer, bo return new MethodDescHandle(methodDescPointer); } - public TargetPointer GetMethodTable(MethodDescHandle methodDescHandle) => _methodDescs[methodDescHandle.Address].MethodTable; + public TargetPointer GetMethodTable(MethodDescHandle methodDescHandle) => GetOrCreateMethodDesc(methodDescHandle).MethodTable; private InstantiatedMethodDesc AsInstantiatedMethodDesc(MethodDesc methodDesc) { @@ -1614,7 +1638,7 @@ private StoredSigMethodDesc AsStoredSigMethodDesc(MethodDesc methodDesc) public bool IsGenericMethodDefinition(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (methodDesc.Classification != MethodClassification.Instantiated) return false; @@ -1623,7 +1647,7 @@ public bool IsGenericMethodDefinition(MethodDescHandle methodDescHandle) public ReadOnlySpan GetGenericMethodInstantiation(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (methodDesc.Classification != MethodClassification.Instantiated) return default; @@ -1648,7 +1672,7 @@ private bool RequiresInstArgMethodTable(MethodDesc methodDesc) public GenericContextLoc GetGenericContextLoc(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (!IsSharedByGenericInstantiations(methodDesc)) return GenericContextLoc.None; else if (HasMethodInstantiation(methodDesc)) @@ -1701,7 +1725,7 @@ private bool IsAbstract(MethodDesc methodDesc) public bool IsAsyncMethod(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (!methodDesc.HasAsyncMethodData) return false; @@ -1714,13 +1738,13 @@ public bool IsAsyncMethod(MethodDescHandle methodDescHandle) public uint GetMethodToken(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); return methodDesc.Token; } public bool IsArrayMethod(MethodDescHandle methodDescHandle, out ArrayFunctionType functionType) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (methodDesc.Classification != MethodClassification.Array) { @@ -1754,7 +1778,7 @@ public bool IsArrayMethod(MethodDescHandle methodDescHandle, out ArrayFunctionTy public bool IsNoMetadataMethod(MethodDescHandle methodDescHandle, out string methodName) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (methodDesc.Classification != MethodClassification.Dynamic) { @@ -1768,7 +1792,7 @@ public bool IsNoMetadataMethod(MethodDescHandle methodDescHandle, out string met private bool IsStoredSigMethodDesc(MethodDescHandle methodDescHandle, out ReadOnlySpan signature) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); switch (methodDesc.Classification) { @@ -1793,7 +1817,7 @@ public bool TryGetMethodSignature(MethodDescHandle methodDescHandle, out ReadOnl return true; } - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (methodDesc.HasAsyncMethodData) { @@ -1831,7 +1855,7 @@ public bool TryGetMethodSignature(MethodDescHandle methodDescHandle, out ReadOnl public bool IsDynamicMethod(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (methodDesc.Classification != MethodClassification.Dynamic) { @@ -1843,13 +1867,13 @@ public bool IsDynamicMethod(MethodDescHandle methodDescHandle) public bool IsIL(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); return methodDesc.IsIL; } public bool IsILStub(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (methodDesc.Classification != MethodClassification.Dynamic) { return false; @@ -1860,7 +1884,7 @@ public bool IsILStub(MethodDescHandle methodDescHandle) public bool HasMDContextArg(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); if (methodDesc.Classification != MethodClassification.Dynamic) { @@ -1871,11 +1895,7 @@ public bool HasMDContextArg(MethodDescHandle methodDescHandle) } private MethodTable GetOrCreateMethodTable(MethodDesc methodDesc) - { - // Ensures that the method table is valid, created, and cached - _ = GetTypeHandle(methodDesc.MethodTable); - return _methodTables[methodDesc.MethodTable]; - } + => GetOrCreateMethodTable(GetTypeHandle(methodDesc.MethodTable)); private struct VtableIndirections { @@ -1911,7 +1931,7 @@ private TargetPointer GetAddressOfSlot(ITypeHandle typeHandle, uint slotNum) Debug.Assert(slotNum < GetNumVtableSlots(typeHandle), "Slot number is greater than the number of slots"); // MethodTable::GetSlotPtrRaw - MethodTable mt = _methodTables[typeHandle.Address]; + MethodTable mt = GetOrCreateMethodTable(typeHandle); if (slotNum < mt.NumVirtuals) { // Virtual slots live in chunks pointed to by vtable indirections @@ -1971,7 +1991,7 @@ private TargetPointer GetLoaderModule(MethodDesc md) bool IRuntimeTypeSystem.IsCollectibleMethod(MethodDescHandle methodDesc) { - MethodDesc md = _methodDescs[methodDesc.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDesc); TargetPointer loaderModuleAddr = GetLoaderModule(md); ModuleHandle mod = _target.Contracts.Loader.GetModuleHandleFromModulePtr(loaderModuleAddr); return _target.Contracts.Loader.IsCollectible(mod); @@ -1979,7 +1999,7 @@ bool IRuntimeTypeSystem.IsCollectibleMethod(MethodDescHandle methodDesc) bool IRuntimeTypeSystem.IsVersionable(MethodDescHandle methodDesc) { - MethodDesc md = _methodDescs[methodDesc.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDesc); if (md.IsEligibleForTieredCompilation) return true; // MethodDesc::IsEligibleForReJIT @@ -1996,7 +2016,7 @@ bool IRuntimeTypeSystem.IsVersionable(MethodDescHandle methodDesc) TargetPointer IRuntimeTypeSystem.GetMethodDescVersioningState(MethodDescHandle methodDesc) { - MethodDesc md = _methodDescs[methodDesc.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDesc); TargetPointer codeDataAddress = md.CodeData; if (codeDataAddress == TargetPointer.Null) return TargetPointer.Null; @@ -2007,18 +2027,18 @@ TargetPointer IRuntimeTypeSystem.GetMethodDescVersioningState(MethodDescHandle m uint IRuntimeTypeSystem.GetMethodToken(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); return methodDesc.Token; } ushort IRuntimeTypeSystem.GetSlotNumber(MethodDescHandle methodDesc) { - MethodDesc md = _methodDescs[methodDesc.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDesc); return md.Slot; } bool IRuntimeTypeSystem.HasNativeCodeSlot(MethodDescHandle methodDesc) { - MethodDesc md = _methodDescs[methodDesc.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDesc); return md.HasNativeCodeSlot; } @@ -2040,7 +2060,7 @@ private IEnumerable GetIntroducedMethods(ITypeHandle typeHandl // Validation of some MethodDescs fails in heap dumps due to missing memory. // Skipping validation should be okay as the pointers come from the target. MethodDescHandle methodDescHandle = GetMethodDescHandle(methodDescPtr, validate: false); - MethodDesc md = _methodDescs[methodDescHandle.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDescHandle); methodDescPtr += md.Size; yield return methodDescHandle; } @@ -2051,13 +2071,13 @@ private IEnumerable GetIntroducedMethods(ITypeHandle typeHandl TargetPointer IRuntimeTypeSystem.GetAsyncVariant(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); ITypeHandle methodTable = GetTypeHandle(methodDesc.MethodTable); ITypeHandle canonicalMethodTable = GetTypeHandle(GetCanonicalMethodTable(methodTable)); foreach (MethodDescHandle candidateHandle in GetIntroducedMethods(canonicalMethodTable)) { - MethodDesc candidate = _methodDescs[candidateHandle.Address]; + MethodDesc candidate = GetOrCreateMethodDesc(candidateHandle); if (candidate.Slot != methodDesc.Slot) continue; @@ -2098,7 +2118,7 @@ TargetPointer IRuntimeTypeSystem.GetMethodDescForSlot(ITypeHandle typeHandle, us { foreach (MethodDescHandle mdh in GetIntroducedMethods(canonMT)) { - MethodDesc md = _methodDescs[mdh.Address]; + MethodDesc md = GetOrCreateMethodDesc(mdh); if (md.Slot == slot) { return mdh.Address; @@ -2132,7 +2152,7 @@ private TargetPointer GetMethodDescForVtableSlot(ITypeHandle typeHandle, ushort ITypeHandle lookupMT = GetTypeHandle(lookupMTPtr); foreach (MethodDescHandle mdh in GetIntroducedMethods(lookupMT)) { - MethodDesc md = _methodDescs[mdh.Address]; + MethodDesc md = GetOrCreateMethodDesc(mdh); if (md.Slot == slot) { return mdh.Address; @@ -2180,13 +2200,13 @@ TargetCodePointer IRuntimeTypeSystem.GetSlot(ITypeHandle typeHandle, uint slot) TargetPointer IRuntimeTypeSystem.GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc) { - MethodDesc md = _methodDescs[methodDesc.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDesc); return md.GetAddressOfNativeCodeSlot(); } TargetCodePointer IRuntimeTypeSystem.GetNativeCode(MethodDescHandle methodDescHandle) { - MethodDesc md = _methodDescs[methodDescHandle.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDescHandle); // TODO(cdac): _ASSERTE(!IsDefaultInterfaceMethod() || HasNativeCodeSlot()); if (md.HasNativeCodeSlot) { @@ -2206,7 +2226,7 @@ TargetCodePointer IRuntimeTypeSystem.GetNativeCode(MethodDescHandle methodDescHa TargetCodePointer IRuntimeTypeSystem.GetMethodEntryPointIfExists(MethodDescHandle methodDescHandle) { - MethodDesc md = _methodDescs[methodDescHandle.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDescHandle); return GetMethodEntryPointIfExists(md); } @@ -2228,14 +2248,14 @@ private TargetCodePointer GetMethodEntryPointIfExists(MethodDesc md) TargetPointer methodTablePointer = md.MethodTable; ITypeHandle typeHandle = GetTypeHandle(methodTablePointer); - Debug.Assert(_methodTables[typeHandle.Address].IsCanonMT); + Debug.Assert(GetOrCreateMethodTable(typeHandle).IsCanonMT); TargetPointer addrOfSlot = GetAddressOfSlot(typeHandle, md.Slot); return _target.ReadCodePointer(addrOfSlot); } TargetPointer IRuntimeTypeSystem.GetGCStressCodeCopy(MethodDescHandle methodDesc) { - MethodDesc md = _methodDescs[methodDesc.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDesc); if (md.GCCoverageInfo is TargetPointer gcCoverageInfoAddr && gcCoverageInfoAddr != TargetPointer.Null) { return gcCoverageInfoAddr + (ulong)Data.GCCoverageInfo.GetSavedCodeOffset(_target); @@ -2259,7 +2279,7 @@ internal static OptimizationTier GetOptimizationTier(uint? optimizationTier) OptimizationTier IRuntimeTypeSystem.GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); TargetPointer codeDataAddress = methodDesc.CodeData; if (codeDataAddress == TargetPointer.Null) return OptimizationTier.OptimizationTierUnknown; @@ -2270,13 +2290,13 @@ OptimizationTier IRuntimeTypeSystem.GetMethodDescOptimizationTier(MethodDescHand bool IRuntimeTypeSystem.IsEligibleForTieredCompilation(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); return methodDesc.IsEligibleForTieredCompilation; } public AsyncMethodFlags GetAsyncMethodFlags(MethodDescHandle methodDescHandle) { - MethodDesc md = _methodDescs[methodDescHandle.Address]; + MethodDesc md = GetOrCreateMethodDesc(methodDescHandle); if (!md.HasAsyncMethodData) { return AsyncMethodFlags.None; @@ -2297,13 +2317,13 @@ public AsyncMethodFlags GetAsyncMethodFlags(MethodDescHandle methodDescHandle) public bool IsWrapperStub(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); return IsWrapperStub(methodDesc); } public bool IsUnboxingStub(MethodDescHandle methodDescHandle) { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodDesc methodDesc = GetOrCreateMethodDesc(methodDescHandle); return methodDesc.IsUnboxingStub; } @@ -2338,7 +2358,7 @@ public TargetPointer GetAddressOfMethodTableSlot(TargetPointer methodTablePointe private TargetPointer GetAddressOfMethodTableSlot(TargetPointer methodTablePointer, uint slot) { ITypeHandle typeHandle = GetTypeHandle(methodTablePointer); - Debug.Assert(_methodTables[typeHandle.Address].IsCanonMT); + Debug.Assert(GetOrCreateMethodTable(typeHandle).IsCanonMT); TargetPointer addrOfSlot = GetAddressOfSlot(typeHandle, slot); return addrOfSlot; } diff --git a/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs index 1c5b92404aa828..e42a9737be6ab2 100644 --- a/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs @@ -168,6 +168,11 @@ public void GetMethodDesc_OneRangeOneMethod(string version, MockTarget.Architect TargetPointer actualMethodDesc = em.GetMethodDesc(eeInfo.Value); Assert.Equal(new TargetPointer(expectedMethodDescAddress), actualMethodDesc); + em.Flush(FlushScope.All); + + actualMethodDesc = em.GetMethodDesc(eeInfo.Value); + Assert.Equal(new TargetPointer(expectedMethodDescAddress), actualMethodDesc); + // test middle of method eeInfo = em.GetCodeBlockHandle(new TargetCodePointer(methodStart + methodSize / 2)); Assert.NotNull(eeInfo); diff --git a/src/native/managed/cdac/tests/UnitTests/MethodDescTests.cs b/src/native/managed/cdac/tests/UnitTests/MethodDescTests.cs index 43a31e7bfa9e9f..7bdd98a33941b7 100644 --- a/src/native/managed/cdac/tests/UnitTests/MethodDescTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/MethodDescTests.cs @@ -163,6 +163,12 @@ public void GetMethodDescHandle_ILMethod_GetBasicData(MockTarget.Architecture ar Assert.False(rts.IsDynamicMethod(handle)); Assert.False(rts.IsILStub(handle)); Assert.False(rts.IsArrayMethod(handle, out _)); + + rts.Flush(FlushScope.All); + + Assert.Equal(expectedToken, rts.GetMethodToken(handle)); + Assert.Equal(expectedSlotNum, rts.GetSlotNumber(handle)); + Assert.Equal(objectMethodTable, rts.GetMethodTable(handle)); } [Theory] diff --git a/src/native/managed/cdac/tests/UnitTests/MethodTableTests.cs b/src/native/managed/cdac/tests/UnitTests/MethodTableTests.cs index ec2c5ea08375a2..664e156c74ec9e 100644 --- a/src/native/managed/cdac/tests/UnitTests/MethodTableTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/MethodTableTests.cs @@ -159,6 +159,10 @@ public void ValidateSystemStringMethodTable(MockTarget.Architecture arch) Assert.Equal(systemStringMethodTablePtr.Value, systemStringTypeHandle.Address.Value); Assert.False(contract.IsFreeObjectMethodTable(systemStringTypeHandle)); Assert.True(contract.IsString(systemStringTypeHandle)); + + contract.Flush(FlushScope.All); + + Assert.True(contract.IsString(systemStringTypeHandle)); } [Theory]