static bool injectGenericMethod(AssemblyDefinition assembly, MethodDefinition method, HotfixFlagInTool hotfixType, FieldReference stateTable) { var type = method.DeclaringType; bool isFinalize = (method.Name == "Finalize" && method.IsSpecialName); bool isIntKey = hotfixType.HasFlag(HotfixFlagInTool.IntKey) && !type.HasGenericParameters; //isIntKey = !type.HasGenericParameters; FieldReference fieldReference = null; VariableDefinition injection = null; if (!isIntKey) { var luaDelegateName = getDelegateName(method); if (luaDelegateName == null) { Error("too many overload!"); return(false); } FieldDefinition fieldDefinition = new FieldDefinition(luaDelegateName, Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.Private, delegateBridgeType); type.Fields.Add(fieldDefinition); fieldReference = fieldDefinition.GetGeneric(); } injection = new VariableDefinition(delegateBridgeType); method.Body.Variables.Add(injection); int param_start = method.IsStatic ? 0 : 1; int param_count = method.Parameters.Count + param_start; var insertPoint = method.Body.Instructions[0]; var processor = method.Body.GetILProcessor(); if (method.IsConstructor) { insertPoint = findNextRet(method.Body.Instructions, insertPoint); } bool isStateful = hotfixType.HasFlag(HotfixFlagInTool.Stateful); while (insertPoint != null) { if (isIntKey) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, bridgeIndexByKey.Count)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, hotfixFlagGetter)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Brfalse, insertPoint)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, bridgeIndexByKey.Count)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, delegateBridgeGetter)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stloc, injection)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldsfld, fieldReference)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stloc, injection)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Brfalse, insertPoint)); } processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, invokeSessionStart)); bool statefulConstructor = isStateful && method.IsConstructor && !method.IsStatic; TypeReference returnType = statefulConstructor ? luaTableType : method.ReturnType; bool isVoid = returnType.FullName == "System.Void"; int outCout = 0; for (int i = 0; i < param_count; i++) { if (i == 0 && !method.IsStatic) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg_0)); if (isStateful && !method.IsConstructor) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldfld, stateTable)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, MakeGenericMethod(inParam, luaTableType))); } else { if (type.IsValueType) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldobj, method.DeclaringType.GetGeneric())); } processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, MakeGenericMethod(inParam, method.DeclaringType.GetGeneric()))); } } else { var param = method.Parameters[i - param_start]; if (param.ParameterType.IsByReference) { outCout++; } if (!param.IsOut) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); if (i < ldargs.Length) { processor.InsertBefore(insertPoint, processor.Create(ldargs[i])); } else if (i < 256) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg_S, (byte)i)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg, (short)i)); } var paramType = param.ParameterType; if (param.ParameterType.IsByReference) { paramType = ((ByReferenceType)paramType).ElementType; if (paramType.IsValueType || paramType.IsGenericParameter) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldobj, paramType)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldind_Ref)); } } if (i == param_count - 1 && param.CustomAttributes.Any(ca => ca.AttributeType.FullName == "System.ParamArrayAttribute")) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, MakeGenericMethod(inParams, ((ArrayType)paramType).ElementType))); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, MakeGenericMethod(inParam, paramType))); } } } } int outStart = (isVoid ? 0 : 1); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, outCout + outStart)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, functionInvoke)); int outPos = outStart; for (int i = 0; i < method.Parameters.Count; i++) { if (method.Parameters[i].ParameterType.IsByReference) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, outPos)); int arg_pos = param_start + i; if (arg_pos < ldargs.Length) { processor.InsertBefore(insertPoint, processor.Create(ldargs[arg_pos])); } else if (arg_pos < 256) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg_S, (byte)arg_pos)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg, (short)arg_pos)); } processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, MakeGenericMethod(outParam, ((ByReferenceType)method.Parameters[i].ParameterType).ElementType))); outPos++; } } if (statefulConstructor) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg_0)); } processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); if (isVoid) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, invokeSessionEnd)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Callvirt, MakeGenericMethod(invokeSessionEndWithResult, returnType))); } if (statefulConstructor) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stfld, stateTable)); } if (isFinalize && isStateful) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg_0)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldnull)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stfld, stateTable)); } if (!method.IsConstructor && !isFinalize) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ret)); } if (!method.IsConstructor) { break; } insertPoint = findNextRet(method.Body.Instructions, insertPoint); } if (isFinalize) { method.Body.ExceptionHandlers[0].TryStart = method.Body.Instructions[0]; } return(true); }
static bool injectMethod(AssemblyDefinition assembly, MethodDefinition method, HotfixFlagInTool hotfixType, FieldReference stateTable) { var type = method.DeclaringType; bool isFinalize = (method.Name == "Finalize" && method.IsSpecialName); MethodReference invoke = null; int param_count = method.Parameters.Count + (method.IsStatic ? 0 : 1); if (!findHotfixDelegate(assembly, method, out invoke, hotfixType)) { Error("can not find delegate for " + method.DeclaringType + "." + method.Name + "! try re-genertate code."); return(false); } if (invoke == null) { throw new Exception("unknow exception!"); } FieldReference fieldReference = null; VariableDefinition injection = null; bool isIntKey = hotfixType.HasFlag(HotfixFlagInTool.IntKey) && !type.HasGenericParameters; //isIntKey = !type.HasGenericParameters; if (!isIntKey) { injection = new VariableDefinition(delegateBridgeType); method.Body.Variables.Add(injection); var luaDelegateName = getDelegateName(method); if (luaDelegateName == null) { Error("too many overload!"); return(false); } FieldDefinition fieldDefinition = new FieldDefinition(luaDelegateName, Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.Private, delegateBridgeType); type.Fields.Add(fieldDefinition); fieldReference = fieldDefinition.GetGeneric(); } bool isStateful = hotfixType.HasFlag(HotfixFlagInTool.Stateful); bool ignoreValueType = hotfixType.HasFlag(HotfixFlagInTool.ValueTypeBoxing); bool statefulConstructor = isStateful && method.IsConstructor && !method.IsStatic; var insertPoint = method.Body.Instructions[0]; var processor = method.Body.GetILProcessor(); if (method.IsConstructor) { insertPoint = findNextRet(method.Body.Instructions, insertPoint); } while (insertPoint != null) { if (isIntKey) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, bridgeIndexByKey.Count)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, hotfixFlagGetter)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldsfld, fieldReference)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stloc, injection)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); } processor.InsertBefore(insertPoint, processor.Create(OpCodes.Brfalse, insertPoint)); if (statefulConstructor) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg_0)); } if (isIntKey) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, bridgeIndexByKey.Count)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, delegateBridgeGetter)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloc, injection)); } for (int i = 0; i < param_count; i++) { if (i < ldargs.Length) { processor.InsertBefore(insertPoint, processor.Create(ldargs[i])); } else if (i < 256) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg_S, (byte)i)); } else { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg, (short)i)); } if (i == 0 && isStateful && !method.IsStatic && !method.IsConstructor) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldfld, stateTable)); } else if (i == 0 && !method.IsStatic && type.IsValueType) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldobj, type)); } if (ignoreValueType) { TypeReference paramType; if (method.IsStatic) { paramType = method.Parameters[i].ParameterType; } else { paramType = (i == 0) ? type : method.Parameters[i - 1].ParameterType; } if (paramType.IsValueType) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Box, paramType)); } } } processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, invoke)); if (statefulConstructor) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stfld, stateTable)); } if (isFinalize && isStateful) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg_0)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldnull)); processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stfld, stateTable)); } if (!method.IsConstructor && !isFinalize) { processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ret)); } if (!method.IsConstructor) { break; } insertPoint = findNextRet(method.Body.Instructions, insertPoint); } if (isFinalize) { if (method.Body.ExceptionHandlers.Count == 0) { throw new InvalidProgramException("Finalize has not try-catch? Type :" + method.DeclaringType); } method.Body.ExceptionHandlers[0].TryStart = method.Body.Instructions[0]; } if (isIntKey) { bridgeIndexByKey.Add(method); } return(true); }
static bool findHotfixDelegate(AssemblyDefinition assembly, MethodDefinition method, out MethodReference invoke, HotfixFlagInTool hotfixType) { bool isStateful = hotfixType.HasFlag(HotfixFlagInTool.Stateful); bool ignoreValueType = hotfixType.HasFlag(HotfixFlagInTool.ValueTypeBoxing); for (int i = 0; i < hotfix_bridges.Count; i++) { MethodDefinition hotfix_bridge = hotfix_bridges[i]; var returnType = (isStateful && method.IsConstructor && !method.IsStatic) ? luaTableType : method.ReturnType; if (isSameType(returnType, hotfix_bridge.ReturnType)) { var parametersOfDelegate = hotfix_bridge.Parameters; int compareOffset = 0; if (!method.IsStatic) { var typeOfSelf = (isStateful && !method.IsConstructor) ? luaTableType : ((!ignoreValueType && method.DeclaringType.IsValueType) ? method.DeclaringType : objType); if ((parametersOfDelegate.Count == 0) || parametersOfDelegate[0].ParameterType.IsByReference || !isSameType(typeOfSelf, parametersOfDelegate[0].ParameterType)) { continue; } compareOffset++; } if (method.Parameters.Count != (parametersOfDelegate.Count - compareOffset)) { continue; } bool paramMatch = true; for (int j = 0; j < method.Parameters.Count; j++) { var param_left = method.Parameters[j]; var param_right = parametersOfDelegate[compareOffset++]; if (param_left.IsOut != param_right.IsOut || param_left.ParameterType.IsByReference != param_right.ParameterType.IsByReference) { paramMatch = false; break; } if (!ignoreValueType && param_left.ParameterType.IsValueType != param_right.ParameterType.IsValueType) { paramMatch = false; break; } bool isparam = param_left.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Name == "ParamArrayAttribute") != null; var type_left = (isparam || param_left.ParameterType.IsByReference || (!ignoreValueType && param_left.ParameterType.IsValueType)) ? param_left.ParameterType : objType; if (!isSameType(type_left, param_right.ParameterType)) { paramMatch = false; break; } } if (!paramMatch) { continue; } invoke = hotfix_bridge; return(true); } } invoke = null; return(false); }
static bool genericInOut(AssemblyDefinition assembly, MethodDefinition method, HotfixFlagInTool hotfixType) { bool isStateful = hotfixType.HasFlag(HotfixFlagInTool.Stateful); bool ignoreValueType = hotfixType.HasFlag(HotfixFlagInTool.ValueTypeBoxing); if (hasGenericParameter(method.ReturnType) || isNoPublic(assembly, method.ReturnType)) { return(true); } var parameters = method.Parameters; if (!method.IsStatic && (!isStateful || method.IsConstructor) && (hasGenericParameter(method.DeclaringType) || ((!ignoreValueType && method.DeclaringType.IsValueType) && isNoPublic(assembly, method.DeclaringType)))) { return(true); } for (int i = 0; i < parameters.Count; i++) { if (hasGenericParameter(parameters[i].ParameterType) || (((!ignoreValueType && parameters[i].ParameterType.IsValueType) || parameters[i].ParameterType.IsByReference) && isNoPublic(assembly, parameters[i].ParameterType))) { return(true); } } return(false); }
static bool HasFlag(this HotfixFlagInTool toCheck, HotfixFlagInTool flag) { return((toCheck != HotfixFlagInTool.Stateless) && ((toCheck & flag) == flag)); }