From b875090d05551cebc97214f72140921fc7f6d50d Mon Sep 17 00:00:00 2001 From: Andreas Pardeike Date: Tue, 17 Jan 2017 00:47:20 +0100 Subject: [PATCH] Improved memory method so JIT compiler does not optimize it away --- Harmony/Harmony.csproj | 12 +----------- Harmony/Platform.cs | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/Harmony/Harmony.csproj b/Harmony/Harmony.csproj index 638fe1b3..215e84d1 100644 --- a/Harmony/Harmony.csproj +++ b/Harmony/Harmony.csproj @@ -1,4 +1,4 @@ - + @@ -62,16 +62,6 @@ - - - - False - - - - False - - if exist "$(TargetDir)$(TargetName).pdb" "C:\Program Files (x86)\Mono\bin\mono.exe" "C:\Program Files (x86)\Mono\lib\mono\4.5\pdb2mdb.exe" "$(TargetPath)" diff --git a/Harmony/Platform.cs b/Harmony/Platform.cs index 8e3d6d27..eee6e8bd 100644 --- a/Harmony/Platform.cs +++ b/Harmony/Platform.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.InteropServices; namespace Harmony { @@ -99,6 +100,18 @@ public static unsafe long WriteLong(long memory, long value) return memory + sizeof(long); } + // purpose of this method is to "do some work" so the JIT compiler + // does not optimize our code away. since it is never called with 0 + // it actually does nothing + public static void LongConsumer(long val) + { + if (val == 0) Console.WriteLine(val); + } + + // the way we create rwx memory is by building a new method and making + // sure the JIT compiler does not optimize our code away. We force this + // by calling a second method. the loop runs an estimated times to make + // sure we have enough assembler code to cover our memory size static int counter; public static long GetMemory(int size) { @@ -110,21 +123,15 @@ public static long GetMemory(int size) var methodName = "HarmonyMemoryMethod" + counter; var methodBuilder = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[0]); var il = methodBuilder.GetILGenerator(); - // lets try to be clever enough that no optimization reduces our JIT code size - il.DeclareLocal(typeof(int)); - il.Emit(OpCodes.Ldc_I4, 0); - for (int i = 1; i <= size / 2; i++) // size/2 is a rough estimate + for (var i = 1; i <= 1 + (size / 8); i++) { - il.Emit(OpCodes.Stloc_0); - il.Emit(OpCodes.Ldloc_0); - il.Emit(OpCodes.Ldc_I4, i); - il.Emit(OpCodes.Add); + il.Emit(OpCodes.Ldc_I8, 0x1000000000000000 + i); + il.Emit(OpCodes.Call, typeof(Platform).GetMethod("LongConsumer")); } - il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ret); var type = typeBuilder.CreateType(); var m = type.GetMethod(methodName); - m.Invoke(null, new object[] { }); + m.Invoke(null, new object[] { }); // make sure it is JIT-compiled return m.MethodHandle.GetFunctionPointer().ToInt64(); } }