Beispiel #1
0
        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());
        }
Beispiel #2
0
        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 _));
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
        }