Dedup param, array and byref/pointer types
We're aiming to make TypeInfo instances unique - no two TypeInfo instances within a given model should refer to the same type. This will allow us to use simple reference equality for comparing types.
This commit is contained in:
@@ -22,6 +22,9 @@ namespace Il2CppInspector.Reflection
|
|||||||
// List of all types from TypeRefs ordered by instanceIndex
|
// List of all types from TypeRefs ordered by instanceIndex
|
||||||
public TypeInfo[] TypesByReferenceIndex { get; }
|
public TypeInfo[] TypesByReferenceIndex { get; }
|
||||||
|
|
||||||
|
// List of all types from GenericParameters
|
||||||
|
public TypeInfo[] GenericParameterTypes { get; }
|
||||||
|
|
||||||
// List of all methods from MethodSpecs (closed generic methods that can be called; does not need to be in a generic class)
|
// List of all methods from MethodSpecs (closed generic methods that can be called; does not need to be in a generic class)
|
||||||
public Dictionary<Il2CppMethodSpec, MethodBase> GenericMethods { get; } = new Dictionary<Il2CppMethodSpec, MethodBase>();
|
public Dictionary<Il2CppMethodSpec, MethodBase> GenericMethods { get; } = new Dictionary<Il2CppMethodSpec, MethodBase>();
|
||||||
|
|
||||||
@@ -64,6 +67,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
Package = package;
|
Package = package;
|
||||||
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
|
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
|
||||||
TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count];
|
TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count];
|
||||||
|
GenericParameterTypes = new TypeInfo[package.GenericParameters.Length];
|
||||||
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
|
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
|
||||||
MethodInvokers = new MethodInvoker[package.MethodInvokePointers.Length];
|
MethodInvokers = new MethodInvoker[package.MethodInvokePointers.Length];
|
||||||
|
|
||||||
@@ -168,6 +172,25 @@ namespace Il2CppInspector.Reflection
|
|||||||
return referencedType;
|
return referencedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TypeInfo GetGenericParameterType(int index) {
|
||||||
|
if (GenericParameterTypes[index] != null)
|
||||||
|
return GenericParameterTypes[index];
|
||||||
|
|
||||||
|
var paramType = Package.GenericParameters[index]; // genericParameterIndex
|
||||||
|
var container = Package.GenericContainers[paramType.ownerIndex];
|
||||||
|
TypeInfo result;
|
||||||
|
|
||||||
|
if (container.is_method == 1) {
|
||||||
|
var owner = MethodsByDefinitionIndex[container.ownerIndex];
|
||||||
|
result = new TypeInfo(owner, paramType);
|
||||||
|
} else {
|
||||||
|
var owner = TypesByDefinitionIndex[container.ownerIndex];
|
||||||
|
result = new TypeInfo(owner, paramType);
|
||||||
|
}
|
||||||
|
GenericParameterTypes[index] = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// The attribute index is an index into AttributeTypeRanges, each of which is a start-end range index into AttributeTypeIndices, each of which is a TypeIndex
|
// The attribute index is an index into AttributeTypeRanges, each of which is a start-end range index into AttributeTypeIndices, each of which is a TypeIndex
|
||||||
public int GetCustomAttributeIndex(Assembly asm, uint token, int customAttributeIndex) {
|
public int GetCustomAttributeIndex(Assembly asm, uint token, int customAttributeIndex) {
|
||||||
// Prior to v24.1, Type, Field, Parameter, Method, Event, Property, Assembly definitions had their own customAttributeIndex field
|
// Prior to v24.1, Type, Field, Parameter, Method, Event, Property, Assembly definitions had their own customAttributeIndex field
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
// Store the generic type parameters for later instantiation
|
// Store the generic type parameters for later instantiation
|
||||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
||||||
|
genericArguments = Enumerable.Range((int)container.genericParameterStart, container.type_argc)
|
||||||
genericArguments = pkg.GenericParameters.Skip((int)container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToArray();
|
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set method attributes
|
// Set method attributes
|
||||||
|
|||||||
@@ -33,10 +33,21 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Cached derived types
|
||||||
|
private Dictionary<int, TypeInfo> generatedArrayTypes = new Dictionary<int, TypeInfo>();
|
||||||
|
private TypeInfo generatedByRefType;
|
||||||
|
private TypeInfo generatedPointerType;
|
||||||
// This property exposes all types which have been generated directly from this one.
|
// This property exposes all types which have been generated directly from this one.
|
||||||
public IEnumerable<TypeInfo> CachedGeneratedTypes {
|
public IEnumerable<TypeInfo> CachedGeneratedTypes {
|
||||||
get {
|
get {
|
||||||
return genericTypeInstances?.Values ?? Enumerable.Empty<TypeInfo>();
|
IEnumerable<TypeInfo> result = generatedArrayTypes.Values;
|
||||||
|
if (genericTypeInstances != null)
|
||||||
|
result = result.Concat(genericTypeInstances.Values);
|
||||||
|
if (generatedByRefType != null)
|
||||||
|
result = result.Append(generatedByRefType);
|
||||||
|
if (generatedPointerType != null)
|
||||||
|
result = result.Append(generatedPointerType);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,6 +601,9 @@ namespace Il2CppInspector.Reflection {
|
|||||||
MemberType |= MemberTypes.NestedType;
|
MemberType |= MemberTypes.NestedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add to global type definition list
|
||||||
|
Assembly.Model.TypesByDefinitionIndex[Index] = this;
|
||||||
|
|
||||||
// Generic type definition?
|
// Generic type definition?
|
||||||
if (Definition.genericContainerIndex >= 0) {
|
if (Definition.genericContainerIndex >= 0) {
|
||||||
IsGenericType = true;
|
IsGenericType = true;
|
||||||
@@ -598,13 +612,13 @@ namespace Il2CppInspector.Reflection {
|
|||||||
// Store the generic type parameters for later instantiation
|
// Store the generic type parameters for later instantiation
|
||||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
||||||
|
|
||||||
genericArguments = pkg.GenericParameters.Skip((int) container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToArray();
|
genericArguments = Enumerable.Range((int)container.genericParameterStart, container.type_argc)
|
||||||
|
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
||||||
genericTypeInstances = new Dictionary<TypeInfo[], TypeInfo>(new TypeArgumentsComparer());
|
genericTypeInstances = new Dictionary<TypeInfo[], TypeInfo>(new TypeArgumentsComparer());
|
||||||
genericTypeInstances[genericArguments] = this;
|
genericTypeInstances[genericArguments] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to global type definition list
|
// TODO: Move this to after we've populated TypesByReferenceIndex, since FullName might touch that
|
||||||
Assembly.Model.TypesByDefinitionIndex[Index] = this;
|
|
||||||
Assembly.Model.TypesByFullName[FullName] = this;
|
Assembly.Model.TypesByFullName[FullName] = this;
|
||||||
|
|
||||||
if ((Definition.flags & Il2CppConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0)
|
if ((Definition.flags & Il2CppConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0)
|
||||||
@@ -749,30 +763,21 @@ namespace Il2CppInspector.Reflection {
|
|||||||
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
||||||
var descriptor = image.ReadMappedObject<Il2CppArrayType>(typeRef.datapoint);
|
var descriptor = image.ReadMappedObject<Il2CppArrayType>(typeRef.datapoint);
|
||||||
var elementType = model.GetTypeFromVirtualAddress(descriptor.etype);
|
var elementType = model.GetTypeFromVirtualAddress(descriptor.etype);
|
||||||
underlyingType = new TypeInfo(elementType, descriptor.rank);
|
underlyingType = elementType.MakeArrayType(descriptor.rank);
|
||||||
break;
|
break;
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
|
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
|
||||||
elementType = model.GetTypeFromVirtualAddress(typeRef.datapoint);
|
elementType = model.GetTypeFromVirtualAddress(typeRef.datapoint);
|
||||||
underlyingType = new TypeInfo(elementType, 1);
|
underlyingType = elementType.MakeArrayType(1);
|
||||||
break;
|
break;
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
|
case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
|
||||||
elementType = model.GetTypeFromVirtualAddress(typeRef.datapoint);
|
elementType = model.GetTypeFromVirtualAddress(typeRef.datapoint);
|
||||||
underlyingType = new TypeInfo(elementType, isPointer: true);
|
underlyingType = elementType.MakePointerType();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Generic type and generic method parameters
|
// Generic type and generic method parameters
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
|
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
|
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
|
||||||
var paramType = model.Package.GenericParameters[typeRef.datapoint]; // genericParameterIndex
|
underlyingType = model.GetGenericParameterType((int)typeRef.datapoint);
|
||||||
var container = model.Package.GenericContainers[paramType.ownerIndex];
|
|
||||||
|
|
||||||
if(container.is_method == 1) {
|
|
||||||
var owner = model.MethodsByDefinitionIndex[container.ownerIndex];
|
|
||||||
underlyingType = new TypeInfo(owner, paramType);
|
|
||||||
} else {
|
|
||||||
var owner = model.TypesByDefinitionIndex[container.ownerIndex];
|
|
||||||
underlyingType = new TypeInfo(owner, paramType);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Primitive types
|
// Primitive types
|
||||||
@@ -892,7 +897,26 @@ namespace Il2CppInspector.Reflection {
|
|||||||
Name = ElementType.Name;
|
Name = ElementType.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeInfo MakeByRefType() => new TypeInfo(this, isPointer: false);
|
public TypeInfo MakeArrayType(int rank = 1) {
|
||||||
|
TypeInfo type;
|
||||||
|
if (generatedArrayTypes.TryGetValue(rank, out type))
|
||||||
|
return type;
|
||||||
|
type = new TypeInfo(this, rank);
|
||||||
|
generatedArrayTypes[rank] = type;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeInfo MakeByRefType() {
|
||||||
|
if (generatedByRefType == null)
|
||||||
|
generatedByRefType = new TypeInfo(this, isPointer: false);
|
||||||
|
return generatedByRefType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeInfo MakePointerType() {
|
||||||
|
if (generatedPointerType == null)
|
||||||
|
generatedPointerType = new TypeInfo(this, isPointer: true);
|
||||||
|
return generatedPointerType;
|
||||||
|
}
|
||||||
|
|
||||||
// Get all the other types directly referenced by this type (single level depth; no recursion)
|
// Get all the other types directly referenced by this type (single level depth; no recursion)
|
||||||
public List<TypeInfo> GetAllTypeReferences() {
|
public List<TypeInfo> GetAllTypeReferences() {
|
||||||
|
|||||||
Reference in New Issue
Block a user