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