From a10eea6e4ce647061813519d5b0ea496f29495b9 Mon Sep 17 00:00:00 2001
From: leonard Wu <364452445@qq.com>
Date: 星期四, 09 八月 2018 09:47:08 +0800
Subject: [PATCH] 同步最新svn内容
---
Assets/Editor/MemoryProfiler/Crawler.cs | 714 +++++++++++++++++++++++++++++-----------------------------
1 files changed, 357 insertions(+), 357 deletions(-)
diff --git a/Assets/Editor/MemoryProfiler/Crawler.cs b/Assets/Editor/MemoryProfiler/Crawler.cs
index 064da56..178ccc6 100644
--- a/Assets/Editor/MemoryProfiler/Crawler.cs
+++ b/Assets/Editor/MemoryProfiler/Crawler.cs
@@ -1,357 +1,357 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using UnityEditor.MemoryProfiler;
-
-namespace MemoryProfilerWindow
-{
- enum PointerType
- {
- Reference,
- RawPointer
- }
-
- struct ThingToProfile
- {
- public readonly PointerType type;
- public readonly BytesAndOffset bytesAndOffset;
- public readonly ulong objectPointer;
- public readonly TypeDescription typeDescription;
- public readonly bool useStaticFields;
- public readonly int indexOfFrom;
-
- public ThingToProfile(ulong objectPtr, int refIndexOfFrom)
- {
- type = PointerType.Reference;
- objectPointer = objectPtr;
- indexOfFrom = refIndexOfFrom;
-
- useStaticFields = true;
- typeDescription = new TypeDescription();
- bytesAndOffset = new BytesAndOffset();
- }
-
- public ThingToProfile(TypeDescription typeDesc, BytesAndOffset inBytesAndOffset, bool inUseStaticFields, int inIndexOfFrom)
- {
- type = PointerType.RawPointer;
- typeDescription = typeDesc;
- bytesAndOffset = inBytesAndOffset;
- useStaticFields = inUseStaticFields;
- indexOfFrom = inIndexOfFrom;
- objectPointer = 0;
- }
- }
-
- internal class Crawler
- {
- private Dictionary<UInt64, TypeDescription> _typeInfoToTypeDescription;
-
- private Dictionary<int, UInt64> _pointer2Backups = new Dictionary<int, ulong>();
- private VirtualMachineInformation _virtualMachineInformation;
- private TypeDescription[] _typeDescriptions;
- private FieldDescription[][] _instanceFields;
- private FieldDescription[][] _staticFields;
-
- public PackedCrawlerData Crawl(PackedMemorySnapshot input)
- {
- _typeInfoToTypeDescription = input.typeDescriptions.ToDictionary(td => td.typeInfoAddress, td => td);
- _virtualMachineInformation = input.virtualMachineInformation;
- _typeDescriptions = input.typeDescriptions;
- _instanceFields = new FieldDescription[_typeDescriptions.Length][];
- _staticFields = new FieldDescription[_typeDescriptions.Length][];
-
- foreach (var type in _typeDescriptions)
- {
- _instanceFields[type.typeIndex] = TypeTools.AllFieldsOf(type, _typeDescriptions, TypeTools.FieldFindOptions.OnlyInstance).ToArray();
- _staticFields[type.typeIndex] = TypeTools.AllFieldsOf(type, _typeDescriptions, TypeTools.FieldFindOptions.OnlyStatic).ToArray();
- }
-
- var result = new PackedCrawlerData(input);
-
- var managedObjects = new List<PackedManagedObject>(result.startIndices.OfFirstManagedObject * 3);
-
- var connections = new List<Connection>(managedObjects.Capacity * 3);
- //we will be adding a lot of connections, but the input format also already had connections. (nativeobject->nativeobject and nativeobject->gchandle). we'll add ours to the ones already there.
- connections.AddRange(input.connections);
-
- Stack<ThingToProfile> thingsToProfile = new Stack<ThingToProfile>();
- for(int i = 0; i < input.gcHandles.Length; ++i)
- {
- thingsToProfile.Push(new ThingToProfile(input.gcHandles[i].target, result.startIndices.OfFirstGCHandle + i));
- }
-
- for (int i = 0; i < result.typesWithStaticFields.Length; i++)
- {
- var typeDescription = result.typesWithStaticFields[i];
- thingsToProfile.Push(new ThingToProfile(typeDescription, new BytesAndOffset { bytes = typeDescription.staticFieldBytes, offset = 0, pointerSize = _virtualMachineInformation.pointerSize }, true, result.startIndices.OfFirstStaticFields + i));
- }
-
- while (thingsToProfile.Count > 0)
- {
- var thingToProfile = thingsToProfile.Pop();
- if(thingToProfile.type == PointerType.Reference)
- {
- CrawlPointerNonRecursive(input, result.startIndices, thingToProfile.objectPointer, thingToProfile.indexOfFrom, connections, managedObjects, thingsToProfile);
- }
- else
- {
- CrawlRawObjectDataNonRecursive(input, result.startIndices, thingToProfile.bytesAndOffset, thingToProfile.typeDescription, thingToProfile.useStaticFields, thingToProfile.indexOfFrom, connections, managedObjects, thingsToProfile);
- }
- }
-
- result.managedObjects = managedObjects.ToArray();
- connections.AddRange(AddManagedToNativeConnectionsAndRestoreObjectHeaders(input, result.startIndices, result));
- result.connections = connections.ToArray();
-
- return result;
- }
-
- private IEnumerable<Connection> AddManagedToNativeConnectionsAndRestoreObjectHeaders(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, PackedCrawlerData packedCrawlerData)
- {
- if (packedMemorySnapshot.typeDescriptions.Length == 0)
- yield break;
-
- var unityEngineObjectTypeDescription = packedMemorySnapshot.typeDescriptions.First(td => td.name == "UnityEngine.Object");
-
- bool unityEngineObjectHasInstanceIDField = unityEngineObjectTypeDescription.fields.Any(f => f.name == "m_InstanceID");
- int instanceIDOffset = -1;
-
- if (unityEngineObjectHasInstanceIDField)
- instanceIDOffset = unityEngineObjectTypeDescription.fields.Single(f => f.name == "m_InstanceID").offset;
-
-#if UNITY_5_4_OR_NEWER
- var cachedPtrOffset = unityEngineObjectTypeDescription.fields.Single(f => f.name == "m_CachedPtr").offset;
-#endif
-
- for (int i = 0; i != packedCrawlerData.managedObjects.Length; i++)
- {
- var managedObjectIndex = i + startIndices.OfFirstManagedObject;
- var address = packedCrawlerData.managedObjects[i].address;
-
- var typeDescription = RestoreObjectHeader(packedMemorySnapshot.managedHeapSections, address, managedObjectIndex);
-
- if (!DerivesFrom(packedMemorySnapshot.typeDescriptions, typeDescription.typeIndex, unityEngineObjectTypeDescription.typeIndex))
- continue;
-
- int indexOfNativeObject = -1;
- if (unityEngineObjectHasInstanceIDField)
- {
- var instanceID = packedMemorySnapshot.managedHeapSections.Find(address + (UInt64)instanceIDOffset, packedMemorySnapshot.virtualMachineInformation).ReadInt32();
- indexOfNativeObject = Array.FindIndex(packedMemorySnapshot.nativeObjects, no => no.instanceId == instanceID);
- }
-#if UNITY_5_4_OR_NEWER // Since Unity 5.4, UnityEngine.Object no longer stores instance id inside when running in the player. Use cached ptr instead to find the index of native object
- else
- {
- // If you get a compilation error on the following 2 lines, update to Unity 5.4b14.
- var cachedPtr = packedMemorySnapshot.managedHeapSections.Find(address + (UInt64)cachedPtrOffset, packedMemorySnapshot.virtualMachineInformation).ReadPointer();
- indexOfNativeObject = Array.FindIndex(packedMemorySnapshot.nativeObjects, no => (ulong)no.nativeObjectAddress == cachedPtr);
- }
-#endif
-
- if (indexOfNativeObject != -1)
- yield return new Connection { @from = managedObjectIndex, to = indexOfNativeObject + startIndices.OfFirstNativeObject };
- }
- }
-
- private bool DerivesFrom(TypeDescription[] typeDescriptions, int typeIndex, int potentialBase)
- {
- if (typeIndex == potentialBase)
- return true;
- var baseIndex = typeDescriptions[typeIndex].baseOrElementTypeIndex;
-
- if (baseIndex == -1)
- return false;
-
- return DerivesFrom(typeDescriptions, baseIndex, potentialBase);
- }
-
- private TypeDescription GetTypeDescription(MemorySection[] heap, ulong objectAddress)
- {
- TypeDescription typeDescription;
-
- // IL2CPP has the class pointer as the first member of the object.
- if (!_typeInfoToTypeDescription.TryGetValue(objectAddress, out typeDescription))
- {
- // Mono has a vtable pointer as the first member of the object.
- // The first member of the vtable is the class pointer.
- var vtable = heap.Find(objectAddress, _virtualMachineInformation);
- var vtableClassPointer = vtable.ReadPointer();
- typeDescription = _typeInfoToTypeDescription[vtableClassPointer];
- }
-
- return typeDescription;
- }
-
- private TypeDescription RestoreObjectHeader(MemorySection[] heaps, ulong address, int managedObjectIndex)
- {
- var bo = heaps.Find(address, _virtualMachineInformation);
- var mask = this._virtualMachineInformation.pointerSize == 8 ? System.UInt64.MaxValue - 1 : System.UInt32.MaxValue - 1;
- var pointer = bo.ReadPointer();
- var typeInfoAddress = pointer & mask;
- bo.WritePointer(typeInfoAddress);
-
- UInt64 restoreValue = 0;
- _pointer2Backups.TryGetValue(managedObjectIndex, out restoreValue);
- bo.NextPointer().WritePointer(restoreValue);
-
- return GetTypeDescription(heaps, typeInfoAddress);
- }
-
- private void CrawlRawObjectDataNonRecursive(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, BytesAndOffset bytesAndOffset, TypeDescription typeDescription, bool useStaticFields, int indexOfFrom,
- List<Connection> out_connections, List<PackedManagedObject> out_managedObjects, Stack<ThingToProfile> out_thingsToProfile)
- {
-
- // Do not crawl MemoryProfilerWindow objects
- if (typeDescription.name.StartsWith("MemoryProfilerWindow."))
- return;
-
- var fields = useStaticFields ? _staticFields[typeDescription.typeIndex] : _instanceFields[typeDescription.typeIndex];
-
- for(int i = 0; i < fields.Length; ++i)
- {
- var field = fields[i];
- var fieldType = packedMemorySnapshot.typeDescriptions[field.typeIndex];
- var fieldLocation = bytesAndOffset.Add(field.offset - (useStaticFields ? 0 : _virtualMachineInformation.objectHeaderSize));
-
- if(fieldType.isValueType)
- {
- out_thingsToProfile.Push(new ThingToProfile(fieldType, fieldLocation, false, indexOfFrom));
- continue;
- }
- else
- {
- //temporary workaround for a bug in 5.3b4 and earlier where we would get literals returned as fields with offset 0. soon we'll be able to remove this code.
- bool gotException = false;
- try
- {
- fieldLocation.ReadPointer();
- }
- catch (ArgumentException)
- {
- UnityEngine.Debug.LogWarningFormat("Skipping field {0} on type {1}", field.name, typeDescription.name);
- UnityEngine.Debug.LogWarningFormat("FieldType.name: {0}", fieldType.name);
- gotException = true;
- }
-
- if (!gotException)
- {
- out_thingsToProfile.Push(new ThingToProfile(fieldLocation.ReadPointer(), indexOfFrom));
- }
- }
- }
- }
-
- private void CrawlPointerNonRecursive(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, ulong pointer, int indexOfFrom, List<Connection> out_connections, List<PackedManagedObject> out_managedObjects, Stack<ThingToProfile> out_thingsToProfile)
- {
- var bo = packedMemorySnapshot.managedHeapSections.Find(pointer, _virtualMachineInformation);
- if (!bo.IsValid)
- return;
-
- UInt64 typeInfoAddress;
- int indexOfObject;
- bool wasAlreadyCrawled;
- try
- {
- ParseObjectHeader(startIndices, packedMemorySnapshot.managedHeapSections, pointer, out typeInfoAddress, out indexOfObject, out wasAlreadyCrawled, out_managedObjects);
- }
- catch (Exception e)
- {
- UnityEngine.Debug.LogWarningFormat("Exception parsing object header. Skipping. {0}", e);
- return;
- }
-
- out_connections.Add(new Connection() { from = indexOfFrom, to = indexOfObject });
-
- if (wasAlreadyCrawled)
- return;
-
- var typeDescription = _typeInfoToTypeDescription[typeInfoAddress];
-
- if (!typeDescription.isArray)
- {
- out_thingsToProfile.Push(new ThingToProfile(typeDescription, bo.Add(_virtualMachineInformation.objectHeaderSize), false, indexOfObject));
- return;
- }
-
- var arrayLength = ArrayTools.ReadArrayLength(packedMemorySnapshot.managedHeapSections, pointer, typeDescription, _virtualMachineInformation);
- var elementType = packedMemorySnapshot.typeDescriptions[typeDescription.baseOrElementTypeIndex];
- var cursor = bo.Add(_virtualMachineInformation.arrayHeaderSize);
- for (int i = 0; i != arrayLength; i++)
- {
- if (elementType.isValueType)
- {
- out_thingsToProfile.Push(new ThingToProfile(elementType, cursor, false, indexOfObject));
- cursor = cursor.Add(elementType.size);
- }
- else
- {
- out_thingsToProfile.Push(new ThingToProfile(cursor.ReadPointer(), indexOfObject));
- cursor = cursor.NextPointer();
- }
- }
- }
-
- int SizeOfObjectInBytes(TypeDescription typeDescription, BytesAndOffset bo, MemorySection[] heap, ulong address)
- {
- if (typeDescription.isArray)
- return ArrayTools.ReadArrayObjectSizeInBytes(heap, address, typeDescription, _typeDescriptions, _virtualMachineInformation);
-
- if (typeDescription.name == "System.String")
- return StringTools.ReadStringObjectSizeInBytes(bo, _virtualMachineInformation);
-
- //array and string are the only types that are special, all other types just have one size, which is stored in the typedescription
- return typeDescription.size;
- }
-
- private void ParseObjectHeader(StartIndices startIndices, MemorySection[] heap, ulong originalHeapAddress, out ulong typeInfoAddress, out int indexOfObject, out bool wasAlreadyCrawled, List<PackedManagedObject> outManagedObjects)
- {
- var bo = heap.Find(originalHeapAddress, _virtualMachineInformation);
-
- var pointer1 = bo.ReadPointer();
- var pointer2 = bo.NextPointer();
-
- if (HasMarkBit(pointer1) == 0)
- {
- TypeDescription typeDescription = GetTypeDescription(heap, pointer1);
-
- wasAlreadyCrawled = false;
- indexOfObject = outManagedObjects.Count + startIndices.OfFirstManagedObject;
- typeInfoAddress = typeDescription.typeInfoAddress;
-
- var size = SizeOfObjectInBytes(typeDescription, bo, heap, originalHeapAddress);
-
- outManagedObjects.Add(new PackedManagedObject() { address = originalHeapAddress, size = size, typeIndex = typeDescription.typeIndex });
-
- //okay, we gathered all information, now lets set the mark bit, and store the index for this object in the 2nd pointer of the header, which is rarely used.
- bo.WritePointer(pointer1 | 1);
-
- //test writepointer implementation
- ulong magic = bo.pointerSize == 8 ? 0x12345678deadbeefUL : 0xdeadbeef;
-
- pointer2.WritePointer(magic);
- var check = pointer2.ReadPointer();
- if (check != magic)
- throw new Exception("writepointer broken");
-
- pointer2.WritePointer((ulong)indexOfObject);
- return;
- }
-
- //give typeinfo address back without the markbit
- typeInfoAddress = ClearMarkBit(pointer1);
- wasAlreadyCrawled = true;
- //read the index for this object that we stored in the 2ndpointer field of the header
- indexOfObject = (int)pointer2.ReadPointer();
- }
-
- private static ulong HasMarkBit(ulong pointer1)
- {
- return pointer1 & 1;
- }
-
- private static ulong ClearMarkBit(ulong pointer1)
- {
- return pointer1 & ~(1UL);
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor.MemoryProfiler;
+
+namespace MemoryProfilerWindow
+{
+ enum PointerType
+ {
+ Reference,
+ RawPointer
+ }
+
+ struct ThingToProfile
+ {
+ public readonly PointerType type;
+ public readonly BytesAndOffset bytesAndOffset;
+ public readonly ulong objectPointer;
+ public readonly TypeDescription typeDescription;
+ public readonly bool useStaticFields;
+ public readonly int indexOfFrom;
+
+ public ThingToProfile(ulong objectPtr, int refIndexOfFrom)
+ {
+ type = PointerType.Reference;
+ objectPointer = objectPtr;
+ indexOfFrom = refIndexOfFrom;
+
+ useStaticFields = true;
+ typeDescription = new TypeDescription();
+ bytesAndOffset = new BytesAndOffset();
+ }
+
+ public ThingToProfile(TypeDescription typeDesc, BytesAndOffset inBytesAndOffset, bool inUseStaticFields, int inIndexOfFrom)
+ {
+ type = PointerType.RawPointer;
+ typeDescription = typeDesc;
+ bytesAndOffset = inBytesAndOffset;
+ useStaticFields = inUseStaticFields;
+ indexOfFrom = inIndexOfFrom;
+ objectPointer = 0;
+ }
+ }
+
+ internal class Crawler
+ {
+ private Dictionary<UInt64, TypeDescription> _typeInfoToTypeDescription;
+
+ private Dictionary<int, UInt64> _pointer2Backups = new Dictionary<int, ulong>();
+ private VirtualMachineInformation _virtualMachineInformation;
+ private TypeDescription[] _typeDescriptions;
+ private FieldDescription[][] _instanceFields;
+ private FieldDescription[][] _staticFields;
+
+ public PackedCrawlerData Crawl(PackedMemorySnapshot input)
+ {
+ _typeInfoToTypeDescription = input.typeDescriptions.ToDictionary(td => td.typeInfoAddress, td => td);
+ _virtualMachineInformation = input.virtualMachineInformation;
+ _typeDescriptions = input.typeDescriptions;
+ _instanceFields = new FieldDescription[_typeDescriptions.Length][];
+ _staticFields = new FieldDescription[_typeDescriptions.Length][];
+
+ foreach (var type in _typeDescriptions)
+ {
+ _instanceFields[type.typeIndex] = TypeTools.AllFieldsOf(type, _typeDescriptions, TypeTools.FieldFindOptions.OnlyInstance).ToArray();
+ _staticFields[type.typeIndex] = TypeTools.AllFieldsOf(type, _typeDescriptions, TypeTools.FieldFindOptions.OnlyStatic).ToArray();
+ }
+
+ var result = new PackedCrawlerData(input);
+
+ var managedObjects = new List<PackedManagedObject>(result.startIndices.OfFirstManagedObject * 3);
+
+ var connections = new List<Connection>(managedObjects.Capacity * 3);
+ //we will be adding a lot of connections, but the input format also already had connections. (nativeobject->nativeobject and nativeobject->gchandle). we'll add ours to the ones already there.
+ connections.AddRange(input.connections);
+
+ Stack<ThingToProfile> thingsToProfile = new Stack<ThingToProfile>();
+ for(int i = 0; i < input.gcHandles.Length; ++i)
+ {
+ thingsToProfile.Push(new ThingToProfile(input.gcHandles[i].target, result.startIndices.OfFirstGCHandle + i));
+ }
+
+ for (int i = 0; i < result.typesWithStaticFields.Length; i++)
+ {
+ var typeDescription = result.typesWithStaticFields[i];
+ thingsToProfile.Push(new ThingToProfile(typeDescription, new BytesAndOffset { bytes = typeDescription.staticFieldBytes, offset = 0, pointerSize = _virtualMachineInformation.pointerSize }, true, result.startIndices.OfFirstStaticFields + i));
+ }
+
+ while (thingsToProfile.Count > 0)
+ {
+ var thingToProfile = thingsToProfile.Pop();
+ if(thingToProfile.type == PointerType.Reference)
+ {
+ CrawlPointerNonRecursive(input, result.startIndices, thingToProfile.objectPointer, thingToProfile.indexOfFrom, connections, managedObjects, thingsToProfile);
+ }
+ else
+ {
+ CrawlRawObjectDataNonRecursive(input, result.startIndices, thingToProfile.bytesAndOffset, thingToProfile.typeDescription, thingToProfile.useStaticFields, thingToProfile.indexOfFrom, connections, managedObjects, thingsToProfile);
+ }
+ }
+
+ result.managedObjects = managedObjects.ToArray();
+ connections.AddRange(AddManagedToNativeConnectionsAndRestoreObjectHeaders(input, result.startIndices, result));
+ result.connections = connections.ToArray();
+
+ return result;
+ }
+
+ private IEnumerable<Connection> AddManagedToNativeConnectionsAndRestoreObjectHeaders(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, PackedCrawlerData packedCrawlerData)
+ {
+ if (packedMemorySnapshot.typeDescriptions.Length == 0)
+ yield break;
+
+ var unityEngineObjectTypeDescription = packedMemorySnapshot.typeDescriptions.First(td => td.name == "UnityEngine.Object");
+
+ bool unityEngineObjectHasInstanceIDField = unityEngineObjectTypeDescription.fields.Any(f => f.name == "m_InstanceID");
+ int instanceIDOffset = -1;
+
+ if (unityEngineObjectHasInstanceIDField)
+ instanceIDOffset = unityEngineObjectTypeDescription.fields.Single(f => f.name == "m_InstanceID").offset;
+
+#if UNITY_5_4_OR_NEWER
+ var cachedPtrOffset = unityEngineObjectTypeDescription.fields.Single(f => f.name == "m_CachedPtr").offset;
+#endif
+
+ for (int i = 0; i != packedCrawlerData.managedObjects.Length; i++)
+ {
+ var managedObjectIndex = i + startIndices.OfFirstManagedObject;
+ var address = packedCrawlerData.managedObjects[i].address;
+
+ var typeDescription = RestoreObjectHeader(packedMemorySnapshot.managedHeapSections, address, managedObjectIndex);
+
+ if (!DerivesFrom(packedMemorySnapshot.typeDescriptions, typeDescription.typeIndex, unityEngineObjectTypeDescription.typeIndex))
+ continue;
+
+ int indexOfNativeObject = -1;
+ if (unityEngineObjectHasInstanceIDField)
+ {
+ var instanceID = packedMemorySnapshot.managedHeapSections.Find(address + (UInt64)instanceIDOffset, packedMemorySnapshot.virtualMachineInformation).ReadInt32();
+ indexOfNativeObject = Array.FindIndex(packedMemorySnapshot.nativeObjects, no => no.instanceId == instanceID);
+ }
+#if UNITY_5_4_OR_NEWER // Since Unity 5.4, UnityEngine.Object no longer stores instance id inside when running in the player. Use cached ptr instead to find the index of native object
+ else
+ {
+ // If you get a compilation error on the following 2 lines, update to Unity 5.4b14.
+ var cachedPtr = packedMemorySnapshot.managedHeapSections.Find(address + (UInt64)cachedPtrOffset, packedMemorySnapshot.virtualMachineInformation).ReadPointer();
+ indexOfNativeObject = Array.FindIndex(packedMemorySnapshot.nativeObjects, no => (ulong)no.nativeObjectAddress == cachedPtr);
+ }
+#endif
+
+ if (indexOfNativeObject != -1)
+ yield return new Connection { @from = managedObjectIndex, to = indexOfNativeObject + startIndices.OfFirstNativeObject };
+ }
+ }
+
+ private bool DerivesFrom(TypeDescription[] typeDescriptions, int typeIndex, int potentialBase)
+ {
+ if (typeIndex == potentialBase)
+ return true;
+ var baseIndex = typeDescriptions[typeIndex].baseOrElementTypeIndex;
+
+ if (baseIndex == -1)
+ return false;
+
+ return DerivesFrom(typeDescriptions, baseIndex, potentialBase);
+ }
+
+ private TypeDescription GetTypeDescription(MemorySection[] heap, ulong objectAddress)
+ {
+ TypeDescription typeDescription;
+
+ // IL2CPP has the class pointer as the first member of the object.
+ if (!_typeInfoToTypeDescription.TryGetValue(objectAddress, out typeDescription))
+ {
+ // Mono has a vtable pointer as the first member of the object.
+ // The first member of the vtable is the class pointer.
+ var vtable = heap.Find(objectAddress, _virtualMachineInformation);
+ var vtableClassPointer = vtable.ReadPointer();
+ typeDescription = _typeInfoToTypeDescription[vtableClassPointer];
+ }
+
+ return typeDescription;
+ }
+
+ private TypeDescription RestoreObjectHeader(MemorySection[] heaps, ulong address, int managedObjectIndex)
+ {
+ var bo = heaps.Find(address, _virtualMachineInformation);
+ var mask = this._virtualMachineInformation.pointerSize == 8 ? System.UInt64.MaxValue - 1 : System.UInt32.MaxValue - 1;
+ var pointer = bo.ReadPointer();
+ var typeInfoAddress = pointer & mask;
+ bo.WritePointer(typeInfoAddress);
+
+ UInt64 restoreValue = 0;
+ _pointer2Backups.TryGetValue(managedObjectIndex, out restoreValue);
+ bo.NextPointer().WritePointer(restoreValue);
+
+ return GetTypeDescription(heaps, typeInfoAddress);
+ }
+
+ private void CrawlRawObjectDataNonRecursive(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, BytesAndOffset bytesAndOffset, TypeDescription typeDescription, bool useStaticFields, int indexOfFrom,
+ List<Connection> out_connections, List<PackedManagedObject> out_managedObjects, Stack<ThingToProfile> out_thingsToProfile)
+ {
+
+ // Do not crawl MemoryProfilerWindow objects
+ if (typeDescription.name.StartsWith("MemoryProfilerWindow."))
+ return;
+
+ var fields = useStaticFields ? _staticFields[typeDescription.typeIndex] : _instanceFields[typeDescription.typeIndex];
+
+ for(int i = 0; i < fields.Length; ++i)
+ {
+ var field = fields[i];
+ var fieldType = packedMemorySnapshot.typeDescriptions[field.typeIndex];
+ var fieldLocation = bytesAndOffset.Add(field.offset - (useStaticFields ? 0 : _virtualMachineInformation.objectHeaderSize));
+
+ if(fieldType.isValueType)
+ {
+ out_thingsToProfile.Push(new ThingToProfile(fieldType, fieldLocation, false, indexOfFrom));
+ continue;
+ }
+ else
+ {
+ //temporary workaround for a bug in 5.3b4 and earlier where we would get literals returned as fields with offset 0. soon we'll be able to remove this code.
+ bool gotException = false;
+ try
+ {
+ fieldLocation.ReadPointer();
+ }
+ catch (ArgumentException)
+ {
+ UnityEngine.Debug.LogWarningFormat("Skipping field {0} on type {1}", field.name, typeDescription.name);
+ UnityEngine.Debug.LogWarningFormat("FieldType.name: {0}", fieldType.name);
+ gotException = true;
+ }
+
+ if (!gotException)
+ {
+ out_thingsToProfile.Push(new ThingToProfile(fieldLocation.ReadPointer(), indexOfFrom));
+ }
+ }
+ }
+ }
+
+ private void CrawlPointerNonRecursive(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, ulong pointer, int indexOfFrom, List<Connection> out_connections, List<PackedManagedObject> out_managedObjects, Stack<ThingToProfile> out_thingsToProfile)
+ {
+ var bo = packedMemorySnapshot.managedHeapSections.Find(pointer, _virtualMachineInformation);
+ if (!bo.IsValid)
+ return;
+
+ UInt64 typeInfoAddress;
+ int indexOfObject;
+ bool wasAlreadyCrawled;
+ try
+ {
+ ParseObjectHeader(startIndices, packedMemorySnapshot.managedHeapSections, pointer, out typeInfoAddress, out indexOfObject, out wasAlreadyCrawled, out_managedObjects);
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogWarningFormat("Exception parsing object header. Skipping. {0}", e);
+ return;
+ }
+
+ out_connections.Add(new Connection() { from = indexOfFrom, to = indexOfObject });
+
+ if (wasAlreadyCrawled)
+ return;
+
+ var typeDescription = _typeInfoToTypeDescription[typeInfoAddress];
+
+ if (!typeDescription.isArray)
+ {
+ out_thingsToProfile.Push(new ThingToProfile(typeDescription, bo.Add(_virtualMachineInformation.objectHeaderSize), false, indexOfObject));
+ return;
+ }
+
+ var arrayLength = ArrayTools.ReadArrayLength(packedMemorySnapshot.managedHeapSections, pointer, typeDescription, _virtualMachineInformation);
+ var elementType = packedMemorySnapshot.typeDescriptions[typeDescription.baseOrElementTypeIndex];
+ var cursor = bo.Add(_virtualMachineInformation.arrayHeaderSize);
+ for (int i = 0; i != arrayLength; i++)
+ {
+ if (elementType.isValueType)
+ {
+ out_thingsToProfile.Push(new ThingToProfile(elementType, cursor, false, indexOfObject));
+ cursor = cursor.Add(elementType.size);
+ }
+ else
+ {
+ out_thingsToProfile.Push(new ThingToProfile(cursor.ReadPointer(), indexOfObject));
+ cursor = cursor.NextPointer();
+ }
+ }
+ }
+
+ int SizeOfObjectInBytes(TypeDescription typeDescription, BytesAndOffset bo, MemorySection[] heap, ulong address)
+ {
+ if (typeDescription.isArray)
+ return ArrayTools.ReadArrayObjectSizeInBytes(heap, address, typeDescription, _typeDescriptions, _virtualMachineInformation);
+
+ if (typeDescription.name == "System.String")
+ return StringTools.ReadStringObjectSizeInBytes(bo, _virtualMachineInformation);
+
+ //array and string are the only types that are special, all other types just have one size, which is stored in the typedescription
+ return typeDescription.size;
+ }
+
+ private void ParseObjectHeader(StartIndices startIndices, MemorySection[] heap, ulong originalHeapAddress, out ulong typeInfoAddress, out int indexOfObject, out bool wasAlreadyCrawled, List<PackedManagedObject> outManagedObjects)
+ {
+ var bo = heap.Find(originalHeapAddress, _virtualMachineInformation);
+
+ var pointer1 = bo.ReadPointer();
+ var pointer2 = bo.NextPointer();
+
+ if (HasMarkBit(pointer1) == 0)
+ {
+ TypeDescription typeDescription = GetTypeDescription(heap, pointer1);
+
+ wasAlreadyCrawled = false;
+ indexOfObject = outManagedObjects.Count + startIndices.OfFirstManagedObject;
+ typeInfoAddress = typeDescription.typeInfoAddress;
+
+ var size = SizeOfObjectInBytes(typeDescription, bo, heap, originalHeapAddress);
+
+ outManagedObjects.Add(new PackedManagedObject() { address = originalHeapAddress, size = size, typeIndex = typeDescription.typeIndex });
+
+ //okay, we gathered all information, now lets set the mark bit, and store the index for this object in the 2nd pointer of the header, which is rarely used.
+ bo.WritePointer(pointer1 | 1);
+
+ //test writepointer implementation
+ ulong magic = bo.pointerSize == 8 ? 0x12345678deadbeefUL : 0xdeadbeef;
+
+ pointer2.WritePointer(magic);
+ var check = pointer2.ReadPointer();
+ if (check != magic)
+ throw new Exception("writepointer broken");
+
+ pointer2.WritePointer((ulong)indexOfObject);
+ return;
+ }
+
+ //give typeinfo address back without the markbit
+ typeInfoAddress = ClearMarkBit(pointer1);
+ wasAlreadyCrawled = true;
+ //read the index for this object that we stored in the 2ndpointer field of the header
+ indexOfObject = (int)pointer2.ReadPointer();
+ }
+
+ private static ulong HasMarkBit(ulong pointer1)
+ {
+ return pointer1 & 1;
+ }
+
+ private static ulong ClearMarkBit(ulong pointer1)
+ {
+ return pointer1 & ~(1UL);
+ }
+ }
+}
--
Gitblit v1.8.0