| File: Contracts\RuntimeMutableTypeSystem_1.cs | Web Access |
| Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using Microsoft.Diagnostics.DataContractReader.RuntimeTypeSystemHelpers; namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly struct RuntimeMutableTypeSystem_1 : IRuntimeMutableTypeSystem { private readonly Target _target; public RuntimeMutableTypeSystem_1(Target target) { _target = target; } internal enum FieldDescFlags2 : uint { OffsetMask = 0x07ffffff, } bool IRuntimeMutableTypeSystem.IsFieldDescEnCNew(TargetPointer fieldDescPointer) { Data.FieldDesc fieldDesc = _target.ProcessedData.GetOrAdd<Data.FieldDesc>(fieldDescPointer); uint offset = fieldDesc.DWord2 & (uint)FieldDescFlags2.OffsetMask; return offset == _target.ReadGlobal<uint>(Constants.Globals.FieldOffsetNewEnc); } IEnumerable<TargetPointer> IRuntimeMutableTypeSystem.EnumerateAddedFieldDescs(TypeHandle typeHandle, bool staticFields) { // Only MethodTable type handles can have EnC-added fields. TypeDescs (TypeVar, FnPtr, etc.) cannot. if (!typeHandle.IsMethodTable()) yield break; IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; ILoader loader = _target.Contracts.Loader; TargetPointer modulePtr = rts.GetModule(typeHandle); if (modulePtr == TargetPointer.Null) yield break; ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); if (!loader.GetFlags(moduleHandle).HasFlag(ModuleFlags.EditAndContinue)) yield break; // The Module field backing the EnC class list is only present in builds compiled with // FEATURE_METADATA_UPDATER. If absent, there can be no EnC data. Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(modulePtr); if (module.EnCClassList is not TargetPointer classListAddr) yield break; Data.UnorderedArrayBase classList = _target.ProcessedData.GetOrAdd<Data.UnorderedArrayBase>(classListAddr); if (classList.Count == 0 || classList.Table == TargetPointer.Null) yield break; // Locate the EnCEEClassData entry for this MethodTable. TargetPointer mtPtr = typeHandle.Address; ulong ptrSize = (ulong)_target.PointerSize; TargetPointer classDataPtr = TargetPointer.Null; for (uint i = 0; i < classList.Count; i++) { TargetPointer entry = _target.ReadPointer(classList.Table + i * ptrSize); if (entry == TargetPointer.Null) continue; Data.EnCEEClassData candidate = _target.ProcessedData.GetOrAdd<Data.EnCEEClassData>(entry); if (candidate.MethodTable == mtPtr) { classDataPtr = entry; break; } } if (classDataPtr == TargetPointer.Null) yield break; Data.EnCEEClassData classData = _target.ProcessedData.GetOrAdd<Data.EnCEEClassData>(classDataPtr); TargetPointer node = staticFields ? classData.AddedStaticFields : classData.AddedInstanceFields; while (node != TargetPointer.Null) { Data.EnCAddedFieldElement element = _target.ProcessedData.GetOrAdd<Data.EnCAddedFieldElement>(node); yield return element.FieldDesc; node = element.Next; } } bool IRuntimeMutableTypeSystem.DoesEnCFieldDescNeedFixup(TargetPointer encFieldDescPointer) { Data.EnCFieldDesc encFieldDesc = _target.ProcessedData.GetOrAdd<Data.EnCFieldDesc>(encFieldDescPointer); return encFieldDesc.NeedsFixup != 0; } TargetPointer IRuntimeMutableTypeSystem.GetEnCStaticFieldDataAddress(TargetPointer encFieldDescPointer) { Data.EnCFieldDesc encFieldDesc = _target.ProcessedData.GetOrAdd<Data.EnCFieldDesc>(encFieldDescPointer); if (encFieldDesc.StaticFieldData == TargetPointer.Null) return TargetPointer.Null; Data.EnCAddedStaticField staticField = _target.ProcessedData.GetOrAdd<Data.EnCAddedStaticField>(encFieldDesc.StaticFieldData); return staticField.FieldData; } TargetPointer IRuntimeMutableTypeSystem.GetEnCInstanceFieldAddress(TargetPointer objectAddress, TargetPointer encFieldDescPointer) { IObject objectContract = _target.Contracts.Object; IGC gcContract = _target.Contracts.GC; IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; TargetPointer syncBlockAddress = objectContract.GetSyncBlockAddress(objectAddress); if (syncBlockAddress == TargetPointer.Null) return TargetPointer.Null; Data.SyncBlock syncBlock = _target.ProcessedData.GetOrAdd<Data.SyncBlock>(syncBlockAddress); if (syncBlock.EnCInfo is not TargetPointer encInfoAddress) return TargetPointer.Null; Data.EnCSyncBlockInfo encInfo = _target.ProcessedData.GetOrAdd<Data.EnCSyncBlockInfo>(encInfoAddress); // Walk the linked list of EnCAddedField entries to find the matching FieldDesc TargetPointer entryPtr = encInfo.List; while (entryPtr != TargetPointer.Null) { Data.EnCAddedField entry = _target.ProcessedData.GetOrAdd<Data.EnCAddedField>(entryPtr); if (entry.FieldDesc == encFieldDescPointer) { // Found it. Get the dependent handle secondary (the EnC helper object). TargetPointer handleAddress = entry.FieldData.Handle; if (handleAddress == TargetPointer.Null) return TargetPointer.Null; TargetNUInt secondary = gcContract.GetHandleExtraInfo(handleAddress); TargetPointer helperObjectAddress = new TargetPointer(secondary.Value); if (helperObjectAddress == TargetPointer.Null) return TargetPointer.Null; Data.EditAndContinueHelperObject helper = _target.ProcessedData.GetOrAdd<Data.EditAndContinueHelperObject>(helperObjectAddress); TargetPointer objectReferenceAddress = helper.ObjectReferenceAddress; // Read the OBJECTREF stored in _objectReference TargetPointer fieldObject = _target.ReadPointer(objectReferenceAddress); // Determine field type and compute final address CorElementType fieldType = rts.GetFieldDescType(encFieldDescPointer); if (fieldType == CorElementType.ValueType) { // Value type is boxed, so unbox to get at the data if (fieldObject == TargetPointer.Null) return TargetPointer.Null; Data.Object boxedObj = _target.ProcessedData.GetOrAdd<Data.Object>(fieldObject); return boxedObj.Data; } else if (fieldType == CorElementType.Class) { // The OBJECTREF slot itself is the field value location return objectReferenceAddress; } else { // Primitive stored in a 1-element array. Get pointer to first element. if (fieldObject == TargetPointer.Null) return TargetPointer.Null; return objectContract.GetArrayData(fieldObject, out _, out _, out _); } } entryPtr = entry.Next; } return TargetPointer.Null; } }