private static void PatchDistributedUpdate(PatchContext ctx, MethodBase callerMethod) { var foundAnyIterate = false; var msil = PatchUtilities.ReadInstructions(callerMethod).ToList(); for (var i = 0; i < msil.Count; i++) { var insn = msil[i]; if ((insn.OpCode != OpCodes.Callvirt && insn.OpCode != OpCodes.Call) || !IsDistributedIterate((insn.Operand as MsilOperandInline <MethodBase>)?.Value as MethodInfo)) { continue; } foundAnyIterate = true; // Call to Iterate(). Backtrace up the instruction stack to find the statement creating the delegate. var foundNewDel = false; for (var j = i - 1; j >= 1; j--) { var insn2 = msil[j]; if (insn2.OpCode != OpCodes.Newobj) { continue; } var ctorType = (insn2.Operand as MsilOperandInline <MethodBase>)?.Value?.DeclaringType; if (ctorType == null || !ctorType.IsGenericType || ctorType.GetGenericTypeDefinition() != typeof(Action <>)) { continue; } foundNewDel = true; // Find the instruction loading the function pointer this delegate is created with var ldftn = msil[j - 1]; if (ldftn.OpCode != OpCodes.Ldftn || !(ldftn.Operand is MsilOperandInline <MethodBase> targetMethod)) { Log.Error( $"Unable to find ldftn instruction for call to Iterate in {callerMethod.DeclaringType}#{callerMethod}"); } else { Log.Debug( $"Patching {targetMethod.Value.DeclaringType}#{targetMethod.Value} for {callerMethod.DeclaringType}#{callerMethod}"); PatchDistUpdateDel(ctx, targetMethod.Value); } break; } if (!foundNewDel) { Log.Error( $"Unable to find new Action() call for Iterate in {callerMethod.DeclaringType}#{callerMethod}"); } } if (!foundAnyIterate) { Log.Error($"Unable to find any calls to {_distributedUpdaterIterate} in {callerMethod.DeclaringType}#{callerMethod}"); } }
static MethodBase FindAction(MethodBase caller) { var msil = PatchUtilities.ReadInstructions(caller).ToList(); for (var i = 0; i < msil.Count; i++) { Log.Trace($"insn: {i} {msil[i]}"); var newobj = msil[i]; if (newobj.OpCode != OpCodes.Newobj) { continue; } Log.Trace("newobj found"); var newobjType = (newobj.Operand as MsilOperandInline <MethodBase>)?.Value?.DeclaringType; if (newobjType == null) { continue; } if (newobjType != typeof(GenericLoop.VoidAction)) { continue; } var ldftn = msil[i - 1]; Log.Trace($"ldftn found: {ldftn}"); if (ldftn.OpCode != OpCodes.Ldftn) { continue; } if (!(ldftn.Operand is MsilOperandInline <MethodBase> action)) { continue; } return(action.Value); } throw new Exception("Failed to patch: action not found in FixedLoop.Run()"); }