internal static List <CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers) { if (generator == null) { throw new ArgumentNullException(nameof(generator)); } if (method == null) { throw new ArgumentNullException(nameof(method)); } var originalVariables = MethodPatcher.DeclareLocalVariables(generator, method); var useStructReturnBuffer = StructReturnBuffer.NeedsFix(method); var copier = new MethodCopier(method, generator, originalVariables); copier.SetArgumentShift(useStructReturnBuffer); var info = Harmony.GetPatchInfo(method); if (info != null) { var sortedTranspilers = PatchFunctions.GetSortedPatchMethods(method, info.Transpilers.ToArray(), false); for (var i = 0; i < maxTranspilers && i < sortedTranspilers.Count; i++) { copier.AddTranspiler(sortedTranspilers[i]); } } var endLabels = new List <Label>(); var emitter = new Emitter(generator, false); copier.Finalize(emitter, endLabels, out var hasReturnCode); return(emitter.GetInstructions().OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList()); }
internal static List <CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers) { if (generator == null) { throw new ArgumentNullException(nameof(generator)); } if (method == null) { throw new ArgumentNullException(nameof(method)); } var originalVariables = MethodPatcher.DeclareLocalVariables(generator, method); var useStructReturnBuffer = StructReturnBuffer.NeedsFix(method); var copier = new MethodCopier(method, generator, originalVariables); copier.SetArgumentShift(useStructReturnBuffer); var info = Harmony.GetPatchInfo(method); if (info != null) { var sortedTranspilers = PatchFunctions.GetSortedPatchMethods(method, info.Transpilers.ToArray(), false); for (var i = 0; i < maxTranspilers && i < sortedTranspilers.Count; i++) { copier.AddTranspiler(sortedTranspilers[i]); } } return(copier.Finalize(null, null, out var _)); }
internal MethodPatcher(MethodBase original, MethodBase source, List <MethodInfo> prefixes, List <MethodInfo> postfixes, List <MethodInfo> transpilers, List <MethodInfo> finalizers, bool debug) { if (original is null) { throw new ArgumentNullException(nameof(original)); } this.debug = debug; this.original = original; this.source = source; this.prefixes = prefixes; this.postfixes = postfixes; this.transpilers = transpilers; this.finalizers = finalizers; Memory.MarkForNoInlining(original); if (debug) { FileLog.LogBuffered($"### Patch: {original.FullDescription()}"); FileLog.FlushBuffer(); } idx = prefixes.Count() + postfixes.Count() + finalizers.Count(); useStructReturnBuffer = StructReturnBuffer.NeedsFix(original); if (debug && useStructReturnBuffer) { FileLog.Log($"### Note: A buffer for the returned struct is used. That requires an extra IntPtr argument before the first real argument"); } returnType = AccessTools.GetReturnedType(original); patch = CreateDynamicMethod(original, $"_Patch{idx}", debug); if (patch is null) { throw new Exception("Could not create replacement method"); } il = patch.GetILGenerator(); emitter = new Emitter(il, debug); }
internal static DynamicMethodDefinition CreateDynamicMethod(MethodBase original, string suffix, bool debug) { if (original is null) { throw new ArgumentNullException(nameof(original)); } var useStructReturnBuffer = StructReturnBuffer.NeedsFix(original); var patchName = $"{original.DeclaringType?.FullName}.{original.Name}{suffix}"; patchName = patchName.Replace("<>", ""); var parameters = original.GetParameters(); var parameterTypes = new List <Type>(); parameterTypes.AddRange(parameters.Types()); if (useStructReturnBuffer) { parameterTypes.Insert(0, typeof(IntPtr)); } if (original.IsStatic is false) { if (AccessTools.IsStruct(original.DeclaringType)) { parameterTypes.Insert(0, original.DeclaringType.MakeByRefType()); } else { parameterTypes.Insert(0, original.DeclaringType); } } var returnType = useStructReturnBuffer ? typeof(void) : AccessTools.GetReturnedType(original); var method = new DynamicMethodDefinition( patchName, returnType, parameterTypes.ToArray() ) { OwnerType = original.DeclaringType }; var offset = (original.IsStatic ? 0 : 1) + (useStructReturnBuffer ? 1 : 0); if (useStructReturnBuffer) { method.Definition.Parameters[original.IsStatic ? 0 : 1].Name = "retbuf"; } if (!original.IsStatic) { method.Definition.Parameters[0].Name = "this"; } for (var i = 0; i < parameters.Length; i++) { var param = method.Definition.Parameters[i + offset]; param.Attributes = (Mono.Cecil.ParameterAttributes)parameters[i].Attributes; param.Name = parameters[i].Name; } if (debug) { var parameterStrings = parameterTypes.Select(p => p.FullDescription()).ToList(); if (parameterTypes.Count == method.Definition.Parameters.Count) { for (var i = 0; i < parameterTypes.Count; i++) { parameterStrings[i] += $" {method.Definition.Parameters[i].Name}"; } } FileLog.Log($"### Replacement: static {returnType.FullDescription()} {original.DeclaringType.FullName}::{patchName}({parameterStrings.Join()})"); } return(method); }
internal static DynamicMethodDefinition CreateDynamicMethod(MethodBase original, string suffix, bool debug) { if (original == null) { throw new ArgumentNullException(nameof(original)); } var patchName = original.Name + suffix; patchName = patchName.Replace("<>", ""); var parameters = original.GetParameters(); var parameterTypes = parameters.Types().ToList(); var useStructReturnBuffer = StructReturnBuffer.NeedsFix(original); if (useStructReturnBuffer) { parameterTypes.Insert(0, typeof(IntPtr)); } if (original.IsStatic == false) { if (AccessTools.IsStruct(original.DeclaringType)) { parameterTypes.Insert(0, original.DeclaringType.MakeByRefType()); } else { parameterTypes.Insert(0, original.DeclaringType); } } var returnType = useStructReturnBuffer ? typeof(void) : AccessTools.GetReturnedType(original); var method = new DynamicMethodDefinition( patchName, returnType, parameterTypes.ToArray() ) { OwnerType = original.DeclaringType }; #if NETSTANDARD2_0 || NETCOREAPP2_0 #else var offset = (original.IsStatic ? 0 : 1) + (useStructReturnBuffer ? 1 : 0); if (useStructReturnBuffer) { method.Definition.Parameters[original.IsStatic ? 0 : 1].Name = "retbuf"; } if (!original.IsStatic) { method.Definition.Parameters[0].Name = "this"; } for (var i = 0; i < parameters.Length; i++) { var param = method.Definition.Parameters[i + offset]; param.Attributes = (Mono.Cecil.ParameterAttributes)parameters[i].Attributes; param.Name = parameters[i].Name; } #endif if (debug) { FileLog.LogBuffered($"### Replacement: static {returnType.FullDescription()} {original.DeclaringType.FullName}::{patchName}{parameterTypes.ToArray().Description()}"); } return(method); }