diff --git a/Editor/Emit/ProxyCallAllocator.cs b/Editor/Emit/ProxyCallAllocator.cs index e50bf46..530380c 100644 --- a/Editor/Emit/ProxyCallAllocator.cs +++ b/Editor/Emit/ProxyCallAllocator.cs @@ -56,11 +56,18 @@ namespace Obfuz.Emit const int maxProxyMethodPerDispatchMethod = 1000; + + class CallInfo + { + public IMethod method; + public bool callVir; + } + class DispatchMethodInfo { public MethodDef methodDef; public int secret; - public List methods = new List(); + public List methods = new List(); } private readonly Dictionary> _dispatchMethods = new Dictionary>(SignatureEqualityComparer.Instance); @@ -100,9 +107,23 @@ namespace Obfuz.Emit private MethodSig CreateDispatchMethodSig(IMethod method) { MethodSig methodSig = MetaUtil.ToSharedMethodSig(_module.CorLibTypes, MetaUtil.GetInflatedMethodSig(method)); + //methodSig.Params + switch(MetaUtil.GetThisArgType(method)) + { + case ThisArgType.Class: + { + methodSig.Params.Insert(0, _module.CorLibTypes.Object); + break; + } + case ThisArgType.ValueType: + { + methodSig.Params.Insert(0, _module.CorLibTypes.UIntPtr); + break; + } + } // extra param for secret methodSig.Params.Add(_module.CorLibTypes.Int32); - return methodSig; + return MethodSig.CreateStatic(methodSig.RetType, methodSig.Params.ToArray()); } private DispatchMethodInfo GetDispatchMethod(IMethod method) @@ -136,7 +157,7 @@ namespace Obfuz.Emit proxyMethod = methodDispatcher.methodDef, secret = methodDispatcher.methods.Count, }; - methodDispatcher.methods.Add(method); + methodDispatcher.methods.Add(new CallInfo { method = method, callVir = callVir}); _methodProxys.Add(key, proxyInfo); } return new ProxyCallMethodData { proxyMethod = proxyInfo.proxyMethod, secret = proxyInfo.secret }; @@ -154,7 +175,24 @@ namespace Obfuz.Emit var body = new CilBody(); methodDef.Body = body; var ins = body.Instructions; - ins.Add(Instruction.Create(OpCodes.Ret)); + + foreach (Parameter param in methodDef.Parameters) + { + ins.Add(Instruction.Create(OpCodes.Ldarg, param)); + } + + var switchCases = new List(); + var switchInst = Instruction.Create(OpCodes.Switch, switchCases); + ins.Add(switchInst); + var ret = Instruction.Create(OpCodes.Ret); + foreach (CallInfo ci in dispatchMethod.methods) + { + var callTargetMethod = Instruction.Create(ci.callVir ? OpCodes.Callvirt : OpCodes.Call, ci.method); + switchCases.Add(callTargetMethod); + ins.Add(callTargetMethod); + ins.Add(Instruction.Create(OpCodes.Br, ret)); + } + ins.Add(ret); } } } diff --git a/Editor/Utils/MetaUtil.cs b/Editor/Utils/MetaUtil.cs index 06ae6b7..77b066a 100644 --- a/Editor/Utils/MetaUtil.cs +++ b/Editor/Utils/MetaUtil.cs @@ -6,9 +6,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine.Assertions; +using UnityEngine.UIElements; namespace Obfuz.Utils { + public enum ThisArgType + { + None, + ValueType, + Class, + } + public static class MetaUtil { public static string GetModuleNameWithoutExt(string moduleName) @@ -551,6 +559,32 @@ namespace Obfuz.Utils throw new NotSupportedException($" method: {method}"); } + public static ThisArgType GetThisArgType(IMethod method) + { + if (!method.MethodSig.HasThis) + { + return ThisArgType.None; + } + if (method is MethodDef methodDef) + { + return methodDef.DeclaringType.IsValueType ? ThisArgType.ValueType : ThisArgType.Class; + } + if (method is MemberRef memberRef) + { + TypeDef typeDef = MetaUtil.GetMemberRefTypeDefParentOrNull(memberRef.Class); + if (typeDef == null) + { + return ThisArgType.Class; + } + return typeDef.IsValueType ? ThisArgType.ValueType : ThisArgType.Class; + } + if (method is MethodSpec methodSpec) + { + return GetThisArgType(methodSpec.Method); + } + throw new NotSupportedException($" method: {method}"); + } + public static MethodSig ToSharedMethodSig(ICorLibTypes corTypes, MethodSig methodSig) { var newReturnType = ToShareTypeSig(corTypes, methodSig.RetType);