Skip to content

Commit

Permalink
Better generic support
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Byass committed Feb 17, 2021
1 parent fe03c3c commit 9b0a47e
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cpp2IL/Analysis/Actions/CallManagedFunctionInRegAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public CallManagedFunctionInRegAction(MethodAnalysis context, Instruction instru
}
}

if (!MethodUtils.CheckParameters(instruction, _targetMethod, context, !_targetMethod.IsStatic, out arguments, false))
if (!MethodUtils.CheckParameters(instruction, _targetMethod, context, !_targetMethod.IsStatic, out arguments, failOnLeftoverArgs: false))
{
AddComment("Mismatched parameters detected here.");
}
Expand Down
38 changes: 29 additions & 9 deletions Cpp2IL/Analysis/MethodUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,32 @@ public static bool CheckParameters(Instruction associatedInstruction, Il2CppMeth
{
MethodReference managedMethod = SharedState.UnmanagedToManagedMethods[method];

TypeReference? beingCalledOn = null;
if (managedMethod.DeclaringType.HasGenericParameters && objectMethodBeingCalledOn?.Type is GenericInstanceType {HasGenericArguments: true} git)
{
managedMethod = managedMethod.MakeGeneric(git.GenericArguments.ToArray());
// managedMethod = managedMethod.MakeGeneric(git.GenericArguments.ToArray());
var gim = new GenericInstanceMethod(managedMethod);
foreach (var gitGenericArgument in git.GenericArguments)
{
gim.GenericArguments.Add(gitGenericArgument);
}

managedMethod = gim;
beingCalledOn = git;
}

return CheckParameters(associatedInstruction, managedMethod, context, isInstance, out arguments, failOnLeftoverArgs);
return CheckParameters(associatedInstruction, managedMethod, context, isInstance, out arguments, beingCalledOn, failOnLeftoverArgs);
}

public static bool CheckParameters(Instruction associatedInstruction, MethodReference method, MethodAnalysis context, bool isInstance, [NotNullWhen(true)] out List<IAnalysedOperand>? arguments, bool failOnLeftoverArgs = true)
public static bool CheckParameters(Instruction associatedInstruction, MethodReference method, MethodAnalysis context, bool isInstance, [NotNullWhen(true)] out List<IAnalysedOperand>? arguments, TypeReference? beingCalledOn = null, bool failOnLeftoverArgs = true)
{
return LibCpp2IlMain.ThePe!.is32Bit ? CheckParameters32(associatedInstruction, method, context, isInstance, out arguments) : CheckParameters64(method, context, isInstance, out arguments, failOnLeftoverArgs);
if (beingCalledOn == null)
beingCalledOn = method.DeclaringType;

return LibCpp2IlMain.ThePe!.is32Bit ? CheckParameters32(associatedInstruction, method, context, isInstance, beingCalledOn, out arguments) : CheckParameters64(method, context, isInstance, out arguments, beingCalledOn, failOnLeftoverArgs);
}

private static bool CheckParameters64(MethodReference method, MethodAnalysis context, bool isInstance, [NotNullWhen(true)] out List<IAnalysedOperand>? arguments, bool failOnLeftoverArgs = true)
private static bool CheckParameters64(MethodReference method, MethodAnalysis context, bool isInstance, [NotNullWhen(true)] out List<IAnalysedOperand>? arguments, TypeReference beingCalledOn, bool failOnLeftoverArgs = true)
{
arguments = null;

Expand All @@ -48,13 +60,21 @@ private static bool CheckParameters64(MethodReference method, MethodAnalysis con
{
if (actualArgs.Count(a => a != null) == 0) return false;

var parameterType = parameterData.ParameterType;

if (parameterType is GenericParameter gp && beingCalledOn is GenericInstanceType git)
{
var genericIdx = git.ElementType.GenericParameters.ToList().FindIndex(g => g.Name == gp.FullName);
parameterType = git.GenericArguments[genericIdx];
}

var arg = actualArgs.RemoveAndReturn(0);
switch (arg)
{
case ConstantDefinition cons when cons.Type.FullName != parameterData.ParameterType.ToString(): //Constant type mismatch
case ConstantDefinition cons when cons.Type.FullName != parameterType.ToString(): //Constant type mismatch
return false;
case LocalDefinition local when local.Type == null || !parameterData.ParameterType.Resolve().IsAssignableFrom(local.Type): //Local type mismatch
if(!parameterData.ParameterType.IsPrimitive || local.Type?.IsPrimitive != true)
case LocalDefinition local when local.Type == null || !parameterType.Resolve().IsAssignableFrom(local.Type): //Local type mismatch
if(!parameterType.IsPrimitive || local.Type?.IsPrimitive != true)
return false;
break; //If both are primitive we forgive.
}
Expand All @@ -71,7 +91,7 @@ private static bool CheckParameters64(MethodReference method, MethodAnalysis con
return true;
}

private static bool CheckParameters32(Instruction associatedInstruction, MethodReference method, MethodAnalysis context, bool isInstance, [NotNullWhen(true)] out List<IAnalysedOperand>? arguments)
private static bool CheckParameters32(Instruction associatedInstruction, MethodReference method, MethodAnalysis context, bool isInstance, TypeReference beingCalledOn, [NotNullWhen(true)] out List<IAnalysedOperand>? arguments)
{
arguments = new List<IAnalysedOperand>();

Expand Down
2 changes: 1 addition & 1 deletion Cpp2IL/Analysis/ResultModels/ConstantDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class ConstantDefinition : IAnalysedOperand
public override string ToString()
{
if (Type == typeof(string))
return (string) Value;
return $"\"{Value}\"";

if (Type == typeof(bool))
return Convert.ToString((bool) Value);
Expand Down
8 changes: 7 additions & 1 deletion Cpp2IL/AssemblyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,13 @@ private static List<CppMethodData> ProcessTypeContents(Il2CppMetadata metadata,
var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex);
var parameterType = cppAssembly.types[parameterDef.typeIndex];
var parameterTypeRef = Utils.ImportTypeInto(methodDefinition, parameterType, cppAssembly, metadata);
var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes) parameterType.attrs, parameterTypeRef);

ParameterDefinition parameterDefinition;
if (parameterTypeRef is GenericParameter genericParameter)
parameterDefinition = new ParameterDefinition(genericParameter);
else
parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes) parameterType.attrs, parameterTypeRef);

methodDefinition.Parameters.Add(parameterDefinition);
//Default values for params
if (parameterDefinition.HasDefault)
Expand Down
3 changes: 3 additions & 0 deletions Cpp2IL/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ public static TypeReference ImportTypeInto(MemberReference importInto, Il2CppTyp
{
if (SharedState.GenericParamsByIndex.TryGetValue(toImport.data.genericParameterIndex, out var genericParameter))
{
if(importInto is MethodDefinition mDef)
mDef.GenericParameters.Add(genericParameter);
return genericParameter;
}

Expand All @@ -227,6 +229,7 @@ public static TypeReference ImportTypeInto(MemberReference importInto, Il2CppTyp
{
genericParameter = new GenericParameter(genericName, methodDefinition.DeclaringType);
methodDefinition.DeclaringType.GenericParameters.Add(genericParameter);
methodDefinition.GenericParameters.Add(genericParameter);
SharedState.GenericParamsByIndex.Add(toImport.data.genericParameterIndex, genericParameter);
return genericParameter;
}
Expand Down
3 changes: 2 additions & 1 deletion LibCpp2IL/Metadata/Il2CppMetadata.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -245,7 +246,7 @@ public int GetDefaultValueFromIndex(int index)
return metadataHeader.fieldAndParameterDefaultValueDataOffset + index;
}

private Dictionary<int, string> _cachedStrings = new Dictionary<int, string>();
private ConcurrentDictionary<int, string> _cachedStrings = new ConcurrentDictionary<int, string>();

public string GetStringFromIndex(int index)
{
Expand Down

0 comments on commit 9b0a47e

Please sign in to comment.