From 57451de036659df54b4d2dcbd3a68a6a9aff8561 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Sun, 2 Feb 2020 09:36:23 +0100 Subject: [PATCH] Model: Eliminate stream reads and duplicate TypeInfos from GetTypeFromVirtualAddress --- Il2CppInspector/IL2CPP/Il2CppBinary.cs | 7 ++++++- Il2CppInspector/IL2CPP/Il2CppInspector.cs | 1 + Il2CppInspector/Reflection/Il2CppModel.cs | 22 +++++++++------------ Il2CppInspector/Reflection/ParameterInfo.cs | 6 ++---- Il2CppInspector/Reflection/TypeInfo.cs | 3 +++ 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/Il2CppInspector/IL2CPP/Il2CppBinary.cs b/Il2CppInspector/IL2CPP/Il2CppBinary.cs index 368768c..d4d7235 100644 --- a/Il2CppInspector/IL2CPP/Il2CppBinary.cs +++ b/Il2CppInspector/IL2CPP/Il2CppBinary.cs @@ -49,9 +49,12 @@ namespace Il2CppInspector // List of constructed generic method function pointers corresponding to each possible method instantiation public Dictionary GenericMethodPointers { get; } = new Dictionary(); - // Every defined type + // Every type reference (TypeRef) sorted by index public List TypeReferences { get; private set; } + // Every type reference index sorted by virtual address + public Dictionary TypeReferenceIndicesByAddress { get; private set; } + // From v24.2 onwards, this structure is stored for each module (image) // One assembly may contain multiple modules public Dictionary Modules { get; private set; } @@ -193,6 +196,8 @@ namespace Il2CppInspector FieldOffsetPointers = image.ReadMappedWordArray(MetadataRegistration.pfieldOffsets, (int)MetadataRegistration.fieldOffsetsCount); // Type references (pointer array) + var typeRefPointers = image.ReadMappedArray(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount); + TypeReferenceIndicesByAddress = typeRefPointers.Zip(Enumerable.Range(0, typeRefPointers.Length), (a, i) => new { a, i }).ToDictionary(x => x.a, x => x.i); TypeReferences = image.ReadMappedObjectPointerArray(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount); // Custom attribute constructors (function pointers) diff --git a/Il2CppInspector/IL2CPP/Il2CppInspector.cs b/Il2CppInspector/IL2CPP/Il2CppInspector.cs index 08cb4c1..dae3f3a 100644 --- a/Il2CppInspector/IL2CPP/Il2CppInspector.cs +++ b/Il2CppInspector/IL2CPP/Il2CppInspector.cs @@ -56,6 +56,7 @@ namespace Il2CppInspector public Dictionary ParameterDefaultValue { get; } = new Dictionary(); public List FieldOffsets { get; } public List TypeReferences => Binary.TypeReferences; + public Dictionary TypeReferenceIndicesByAddress => Binary.TypeReferenceIndicesByAddress; public List GenericInstances => Binary.GenericInstances; public Dictionary Modules => Binary.Modules; public ulong[] CustomAttributeGenerators => Binary.CustomAttributeGenerators; diff --git a/Il2CppInspector/Reflection/Il2CppModel.cs b/Il2CppInspector/Reflection/Il2CppModel.cs index c9b55b9..5ecbe64 100644 --- a/Il2CppInspector/Reflection/Il2CppModel.cs +++ b/Il2CppInspector/Reflection/Il2CppModel.cs @@ -8,7 +8,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace Il2CppInspector.Reflection { @@ -32,12 +31,8 @@ namespace Il2CppInspector.Reflection // List of all type definitions by fully qualified name (TypeDefs only) public Dictionary TypesByFullName { get; } = new Dictionary(); - // List of type references that are initialized via pointers in the image - public ConcurrentDictionary TypesByVirtualAddress { get; } = new ConcurrentDictionary(); - // Every type - public IEnumerable Types => new IEnumerable[] - {TypesByDefinitionIndex, TypesByReferenceIndex, TypesByMethodSpecClassIndex.Values, TypesByVirtualAddress.Values} + public IEnumerable Types => new IEnumerable[] {TypesByDefinitionIndex, TypesByReferenceIndex, TypesByMethodSpecClassIndex.Values} .SelectMany(t => t).Distinct(); // List of all methods ordered by their MethodDefinitionIndex @@ -103,7 +98,7 @@ namespace Il2CppInspector.Reflection // Get list of pointers to type parameters (both unresolved and concrete) var genericTypeArguments = Package.BinaryImage.ReadMappedWordArray(inst.type_argv, (int)inst.type_argc); - + return genericTypeArguments.Select(a => GetTypeFromVirtualAddress((ulong) a)).ToList(); } @@ -149,17 +144,18 @@ namespace Il2CppInspector.Reflection return TypesByFullName[fqn]; } - // Type from a virtual address pointer + // Get a TypeRef by its virtual address // These are always nested types from references within another TypeRef - // TODO: Eliminate GetTypeFromVirtualAddress() - use base and offset from MetadataRegistration.ptypes (Package.TypeReferences) instead public TypeInfo GetTypeFromVirtualAddress(ulong ptr) { - if (TypesByVirtualAddress.ContainsKey(ptr)) - return TypesByVirtualAddress[ptr]; + var typeRefIndex = Package.TypeReferenceIndicesByAddress[ptr]; - var type = Package.BinaryImage.ReadMappedObject(ptr); + if (TypesByReferenceIndex[typeRefIndex] != null) + return TypesByReferenceIndex[typeRefIndex]; + + var type = Package.TypeReferences[typeRefIndex]; var referencedType = resolveTypeReference(type); - TypesByVirtualAddress.TryAdd(ptr, referencedType); + TypesByReferenceIndex[typeRefIndex] = referencedType; return referencedType; } diff --git a/Il2CppInspector/Reflection/ParameterInfo.cs b/Il2CppInspector/Reflection/ParameterInfo.cs index 68abea9..e4caf51 100644 --- a/Il2CppInspector/Reflection/ParameterInfo.cs +++ b/Il2CppInspector/Reflection/ParameterInfo.cs @@ -103,10 +103,8 @@ namespace Il2CppInspector.Reflection Position = generic.Position; Attributes = generic.Attributes; - // TODO: Duplicate instances of 'concrete' may cause this search to fail. Replace with a straight lookup after eliminating GetTypeFromVirtualAddress - //paramTypeReference = Array.IndexOf(model.TypesByReferenceIndex, concrete); - // TODO: Get rid of this slow and filthy hack to force finding the correct type reference - paramTypeReference = model.TypesByReferenceIndex.Select((v, i) => new {i, v}).First(t => t.v.ToString() == concrete.ToString()).i; + // Search for the concrete type's TypeRef index to store as the parameter type reference index + paramTypeReference = Array.IndexOf(model.TypesByReferenceIndex, concrete); DefaultValue = generic.DefaultValue; DefaultValueMetadataAddress = generic.DefaultValueMetadataAddress; diff --git a/Il2CppInspector/Reflection/TypeInfo.cs b/Il2CppInspector/Reflection/TypeInfo.cs index 321506a..444ef51 100644 --- a/Il2CppInspector/Reflection/TypeInfo.cs +++ b/Il2CppInspector/Reflection/TypeInfo.cs @@ -580,6 +580,8 @@ namespace Il2CppInspector.Reflection { // Open and closed generic types if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { + + // TODO: Replace with array load from Il2CppMetadataRegistration.genericClasses var generic = image.ReadMappedObject(pType.datapoint); // Il2CppGenericClass * // We have seen one test case where the TypeRef can point to no generic instance @@ -608,6 +610,7 @@ namespace Il2CppInspector.Reflection { IsGenericParameter = false; // Get the instantiation + // TODO: Replace with array load from Il2CppMetadataRegistration.genericInsts var genericInstance = image.ReadMappedObject(generic.context.class_inst); if (generic.context.method_inst != 0)