Пример #1
0
		internal List<CodeInstruction> GetResult(ILGenerator generator, MethodBase method)
		{
			IEnumerable instructions = codeInstructions;
			transpilers.ForEach(transpiler =>
			{
				// before calling some transpiler, convert the input to 'their' CodeInstruction type
				// also remember any unassignable values that otherwise would be lost
				instructions = ConvertToGeneralInstructions(transpiler, instructions, out var unassignedValues);

				// remember the order of the original input (for detection of dupped code instructions)
				var originalInstructions = new List<object>();
				originalInstructions.AddRange(instructions.Cast<object>());

				// call the transpiler
				var parameter = GetTranspilerCallParameters(generator, transpiler, method, instructions);
				instructions = transpiler.Invoke(null, parameter.ToArray()) as IEnumerable;

				// convert result back to 'our' CodeInstruction and re-assign otherwise lost fields
				if (unassignedValues != null)
					instructions = ConvertToOurInstructions(instructions, typeof(CodeInstruction), originalInstructions, unassignedValues);
			});

			var result = instructions.Cast<CodeInstruction>().ToList();
			if (argumentShift)
				StructReturnBuffer.ArgumentShifter(result);
			return result;
		}
Пример #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 _));
        }
Пример #3
0
        static bool HasStructReturnBuffer()
        {
            if (AccessTools.IsMonoRuntime)
            {
                if (hasTestResult_Mono is false)
                {
                    Sandbox.hasStructReturnBuffer_Mono = false;
                    var self        = new StructReturnBuffer();
                    var original    = AccessTools.DeclaredMethod(typeof(Sandbox), nameof(Sandbox.GetStruct_Mono));
                    var replacement = AccessTools.DeclaredMethod(typeof(Sandbox), nameof(Sandbox.GetStructReplacement_Mono));
                    _ = Memory.DetourMethod(original, replacement);
                    _ = new Sandbox().GetStruct_Mono(Sandbox.magicValue, Sandbox.magicValue);
                    hasTestResult_Mono = true;
                }
                return(Sandbox.hasStructReturnBuffer_Mono);
            }

            if (hasTestResult_Net is false)
            {
                Sandbox.hasStructReturnBuffer_Net = false;
                var self        = new StructReturnBuffer();
                var original    = AccessTools.DeclaredMethod(typeof(Sandbox), nameof(Sandbox.GetStruct_Net));
                var replacement = AccessTools.DeclaredMethod(typeof(Sandbox), nameof(Sandbox.GetStructReplacement_Net));
                _ = Memory.DetourMethod(original, replacement);
                _ = new Sandbox().GetStruct_Net(Sandbox.magicValue, Sandbox.magicValue);
                hasTestResult_Net = true;
            }
            return(Sandbox.hasStructReturnBuffer_Net);
        }
Пример #4
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());
        }
Пример #5
0
 static bool HasStructReturnBuffer()
 {
     if (hasTestResult == false)
     {
         Sandbox.hasStructReturnBuffer = false;
         var self        = new StructReturnBuffer();
         var original    = AccessTools.DeclaredMethod(typeof(Sandbox), nameof(Sandbox.GetStruct));
         var replacement = AccessTools.DeclaredMethod(typeof(Sandbox), nameof(Sandbox.GetStructReplacement));
         _             = Memory.DetourMethod(original, replacement);
         _             = new Sandbox().GetStruct(Sandbox.magicValue, Sandbox.magicValue);
         hasTestResult = true;
     }
     return(Sandbox.hasStructReturnBuffer);
 }
Пример #6
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);
        }
Пример #7
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);
        }
Пример #8
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);
        }