Skip to content

Commit

Permalink
Rework on private field injection. Now without local variables and wo…
Browse files Browse the repository at this point in the history
…rks both with instance and static fields
  • Loading branch information
pardeike committed May 18, 2018
1 parent 1298398 commit e3ddd13
Showing 1 changed file with 18 additions and 30 deletions.
48 changes: 18 additions & 30 deletions Harmony/MethodPatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,12 @@ static string GetParameterOverride(this MethodInfo method, string name, bool che

static MethodInfo getMethodMethod = typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) });

static List<KeyValuePair<LocalBuilder, FieldInfo>> EmitCallParameter(ILGenerator il, MethodBase original, MethodInfo patch, Dictionary<string, LocalBuilder> variables, bool allowFirsParamPassthrough)
static void EmitCallParameter(ILGenerator il, MethodBase original, MethodInfo patch, Dictionary<string, LocalBuilder> variables, bool allowFirsParamPassthrough)
{
var isInstance = original.IsStatic == false;
var originalParameters = original.GetParameters();
var originalParameterNames = originalParameters.Select(p => p.Name).ToArray();

var privateFieldVars = new List<KeyValuePair<LocalBuilder, FieldInfo>>();

// check for passthrough using first parameter (which must have same type as return type)
var parameters = patch.GetParameters().ToList();
if (allowFirsParamPassthrough && patch.ReturnType != typeof(void) && parameters.Count > 0 && parameters[0].ParameterType == patch.ReturnType)
Expand Down Expand Up @@ -243,19 +241,25 @@ static List<KeyValuePair<LocalBuilder, FieldInfo>> EmitCallParameter(ILGenerator
if (patchParam.Name.StartsWith(INSTANCE_FIELD_PREFIX))
{
var fieldInfo = AccessTools.Field(original.DeclaringType, patchParam.Name.Substring(INSTANCE_FIELD_PREFIX.Length));
if (patchParam.ParameterType.IsByRef)
if (fieldInfo.IsStatic)
{
var localVar = DynamicTools.DeclareLocalVariable(il, fieldInfo.FieldType);
Emitter.Emit(il, OpCodes.Ldarg_0);
Emitter.Emit(il, OpCodes.Ldfld, fieldInfo);
Emitter.Emit(il, OpCodes.Stloc, localVar);
Emitter.Emit(il, OpCodes.Ldloca, localVar);
privateFieldVars.Add(new KeyValuePair<LocalBuilder, FieldInfo>(localVar, fieldInfo));
if (patchParam.ParameterType.IsByRef)
Emitter.Emit(il, OpCodes.Ldsflda, fieldInfo);
else
Emitter.Emit(il, OpCodes.Ldsfld, fieldInfo);
}
else
{
Emitter.Emit(il, OpCodes.Ldarg_0);
Emitter.Emit(il, OpCodes.Ldfld, fieldInfo);
if (patchParam.ParameterType.IsByRef)
{
Emitter.Emit(il, OpCodes.Ldarg_0);
Emitter.Emit(il, OpCodes.Ldflda, fieldInfo);
}
else
{
Emitter.Emit(il, OpCodes.Ldarg_0);
Emitter.Emit(il, OpCodes.Ldfld, fieldInfo);
}
}
continue;
}
Expand Down Expand Up @@ -322,25 +326,16 @@ static List<KeyValuePair<LocalBuilder, FieldInfo>> EmitCallParameter(ILGenerator
Emitter.Emit(il, OpCodes.Ldarg, patchArgIndex);
Emitter.Emit(il, LoadIndOpCodeFor(originalParameters[idx].ParameterType));
}

return privateFieldVars;
}

static bool AddPrefixes(ILGenerator il, MethodBase original, List<MethodInfo> prefixes, Dictionary<string, LocalBuilder> variables, Label label)
{
var canHaveJump = false;
prefixes.ForEach(fix =>
{
var privateFieldVars = EmitCallParameter(il, original, fix, variables, false);
EmitCallParameter(il, original, fix, variables, false);
Emitter.Emit(il, OpCodes.Call, fix);
foreach (var privateFieldVar in privateFieldVars)
{
Emitter.Emit(il, OpCodes.Ldloc, privateFieldVar.Key);
Emitter.Emit(il, OpCodes.Ldarg_0);
Emitter.Emit(il, OpCodes.Stfld, privateFieldVar.Value);
}
if (fix.ReturnType != typeof(void))
{
if (fix.ReturnType != typeof(bool))
Expand All @@ -358,16 +353,9 @@ static void AddPostfixes(ILGenerator il, MethodBase original, List<MethodInfo> p
.Where(fix => passthroughPatches == (fix.ReturnType != typeof(void)))
.Do(fix =>
{
var privateFieldVars = EmitCallParameter(il, original, fix, variables, true);
EmitCallParameter(il, original, fix, variables, true);
Emitter.Emit(il, OpCodes.Call, fix);
foreach (var privateFieldVar in privateFieldVars)
{
Emitter.Emit(il, OpCodes.Ldloc, privateFieldVar.Key);
Emitter.Emit(il, OpCodes.Ldarg_0);
Emitter.Emit(il, OpCodes.Stfld, privateFieldVar.Value);
}
if (fix.ReturnType != typeof(void))
{
var firstFixParam = fix.GetParameters().FirstOrDefault();
Expand Down

0 comments on commit e3ddd13

Please sign in to comment.