Model: Eliminate stream reads and duplicate TypeInfos from GetTypeFromVirtualAddress

This commit is contained in:
Katy Coe
2020-02-02 09:36:23 +01:00
parent b73885ca8e
commit 57451de036
5 changed files with 21 additions and 18 deletions

View File

@@ -49,9 +49,12 @@ namespace Il2CppInspector
// List of constructed generic method function pointers corresponding to each possible method instantiation
public Dictionary<Il2CppMethodSpec, ulong> GenericMethodPointers { get; } = new Dictionary<Il2CppMethodSpec, ulong>();
// Every defined type
// Every type reference (TypeRef) sorted by index
public List<Il2CppType> TypeReferences { get; private set; }
// Every type reference index sorted by virtual address
public Dictionary<ulong, int> TypeReferenceIndicesByAddress { get; private set; }
// From v24.2 onwards, this structure is stored for each module (image)
// One assembly may contain multiple modules
public Dictionary<string, Il2CppCodeGenModule> 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<ulong>(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<Il2CppType>(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount);
// Custom attribute constructors (function pointers)

View File

@@ -56,6 +56,7 @@ namespace Il2CppInspector
public Dictionary<int, (ulong, object)> ParameterDefaultValue { get; } = new Dictionary<int, (ulong, object)>();
public List<long> FieldOffsets { get; }
public List<Il2CppType> TypeReferences => Binary.TypeReferences;
public Dictionary<ulong, int> TypeReferenceIndicesByAddress => Binary.TypeReferenceIndicesByAddress;
public List<Il2CppGenericInst> GenericInstances => Binary.GenericInstances;
public Dictionary<string, Il2CppCodeGenModule> Modules => Binary.Modules;
public ulong[] CustomAttributeGenerators => Binary.CustomAttributeGenerators;

View File

@@ -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<string, TypeInfo> TypesByFullName { get; } = new Dictionary<string, TypeInfo>();
// List of type references that are initialized via pointers in the image
public ConcurrentDictionary<ulong, TypeInfo> TypesByVirtualAddress { get; } = new ConcurrentDictionary<ulong, TypeInfo>();
// Every type
public IEnumerable<TypeInfo> Types => new IEnumerable<TypeInfo>[]
{TypesByDefinitionIndex, TypesByReferenceIndex, TypesByMethodSpecClassIndex.Values, TypesByVirtualAddress.Values}
public IEnumerable<TypeInfo> Types => new IEnumerable<TypeInfo>[] {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<Il2CppType>(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;
}

View File

@@ -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;

View File

@@ -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<Il2CppGenericClass>(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<Il2CppGenericInst>(generic.context.class_inst);
if (generic.context.method_inst != 0)