private void CrawlRawObjectData(PackedMemorySnapshot packedMemorySnapshot, StartIndices startIndices, BytesAndOffset bytesAndOffset, TypeDescription typeDescription, bool useStaticFields, int indexOfFrom, List <Connection> out_connections, List <PackedManagedObject> out_managedObjects) { foreach (var field in TypeTools.AllFieldsOf(typeDescription, _typeDescriptions, useStaticFields ? TypeTools.FieldFindOptions.OnlyStatic : TypeTools.FieldFindOptions.OnlyInstance)) { if (field.typeIndex == typeDescription.typeIndex && typeDescription.isValueType) { //this happens in System.Single, which is a weird type that has a field of its own type. continue; } if (field.offset == -1) { //this is how we encode TLS fields. todo: actually treat TLS fields as roots continue; } var fieldType = packedMemorySnapshot.typeDescriptions[field.typeIndex]; var fieldLocation = bytesAndOffset.Add(field.offset - (useStaticFields ? 0 : _virtualMachineInformation.objectHeaderSize)); if (fieldType.isValueType) { CrawlRawObjectData(packedMemorySnapshot, startIndices, fieldLocation, fieldType, false, indexOfFrom, out_connections, out_managedObjects); continue; } //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) { CrawlPointer(packedMemorySnapshot, startIndices, fieldLocation.ReadPointer(), indexOfFrom, out_connections, out_managedObjects); } } }
public PackedCrawlerData Crawl(PackedMemorySnapshot input) { UnityEditor.EditorUtility.DisplayProgressBar("Crawl", "init", 0); _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(); } UnityEditor.EditorUtility.DisplayProgressBar("Crawl", "adding connections", 0.1f); 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); UnityEditor.EditorUtility.DisplayProgressBar("Crawl", "adding thing to profile", 0.2f); 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)); } UnityEditor.EditorUtility.DisplayProgressBar("Crawl", "crawlpointer and crawlrawobjectdata", 0.3f); int totalCount = thingsToProfile.Count; 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); } int leftCount = thingsToProfile.Count; if (leftCount % 5 == 0 && UnityEditor.EditorUtility.DisplayCancelableProgressBar("Crawl", string.Format("crawlpointer and crawlrawobjectdata (left:{0}/initial:{1})", leftCount, totalCount), 0.3f + 0.5f * (totalCount - (leftCount > 0 ? leftCount : 0)) / totalCount)) { break; } } UnityEditor.EditorUtility.DisplayProgressBar("Crawl", "composing result", 0.8f); result.managedObjects = managedObjects.ToArray(); connections.AddRange(AddManagedToNativeConnectionsAndRestoreObjectHeaders(input, result.startIndices, result)); result.connections = connections.ToArray(); UnityEditor.EditorUtility.DisplayProgressBar("Crawl", "finish.", 1.0f); UnityEditor.EditorUtility.ClearProgressBar(); return(result); }