static bool injectMethod(AssemblyDefinition assembly, MethodDefinition method, int hotfixType, FieldReference stateTable) { var type = method.DeclaringType; var luaDelegateName = getDelegateName(method); if (luaDelegateName == null) { Debug.LogError("too many overload!"); return false; } bool isFinalize = method.Name == "Finalize"; TypeReference delegateType = null; MethodReference invoke = null; int param_count = method.Parameters.Count + (method.IsStatic ? 0 : 1); if (!findHotfixDelegate(assembly, method, out delegateType, out invoke, hotfixType)) { Debug.LogError("can not find delegate for " + method.DeclaringType + "." + method.Name + "! try re-genertate code."); return false; } if (delegateType == null || invoke == null) { throw new Exception("unknow exception!"); } FieldDefinition fieldDefinition = new FieldDefinition(luaDelegateName, Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.Private, delegateType); type.Fields.Add(fieldDefinition); FieldReference fieldReference = fieldDefinition.GetGeneric(); bool statefulConstructor = (hotfixType == 1) && method.IsConstructor && !method.IsStatic; var firstIns = method.Body.Instructions[0]; var processor = method.Body.GetILProcessor(); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Brfalse, firstIns)); if (statefulConstructor) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldarg_0)); } processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); for (int i = 0; i < param_count; i++) { if (i < ldargs.Length) { processor.InsertBefore(firstIns, processor.Create(ldargs[i])); } else { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldarg, (short)i)); } if (i == 0 && hotfixType == 1 && !method.IsStatic && !method.IsConstructor) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldfld, stateTable)); } else if (i == 0 && !method.IsStatic && type.IsValueType) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldobj, type)); } } processor.InsertBefore(firstIns, processor.Create(OpCodes.Call, invoke)); if (statefulConstructor) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Stfld, stateTable)); } if (isFinalize && hotfixType == 1) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldarg_0)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldnull)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Stfld, stateTable)); } if (!method.IsConstructor && !isFinalize) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ret)); } if (isFinalize) { method.Body.ExceptionHandlers[0].TryStart = method.Body.Instructions[0]; } return true; }
static bool injectType(AssemblyDefinition assembly, TypeReference hotfixAttributeType, TypeDefinition type) { foreach(var nestedTypes in type.NestedTypes) { if (!injectType(assembly, hotfixAttributeType, nestedTypes)) { return false; } } CustomAttribute hotfixAttr = type.CustomAttributes.FirstOrDefault(ca => ca.AttributeType == hotfixAttributeType); int hotfixType; if (hotfixAttr != null) { hotfixType = (int)hotfixAttr.ConstructorArguments[0].Value; } else { if (!hotfixCfg.ContainsKey(type.FullName)) { return true; } hotfixType = (int)hotfixCfg[type.FullName]; } FieldReference stateTable = null; if (hotfixType == 1) { if (type.IsAbstract && type.IsSealed) { throw new InvalidOperationException(type.FullName + " is static, can not be mark as Stateful!"); } var stateTableDefinition = new FieldDefinition("__Hitfix_xluaStateTable", Mono.Cecil.FieldAttributes.Private, luaTableType); type.Fields.Add(stateTableDefinition); stateTable = stateTableDefinition.GetGeneric(); } foreach (var method in type.Methods) { if (method.Name != ".cctor" && !method.IsAbstract && !method.IsPInvokeImpl && method.Body != null) { if ((method.HasGenericParameters || genericInOut(assembly, method)) ? !injectGenericMethod(assembly, method, hotfixType, stateTable) : !injectMethod(assembly, method, hotfixType, stateTable)) { return false; } } } return true; }
static bool injectGenericMethod(AssemblyDefinition assembly, MethodDefinition method, int hotfixType, FieldReference stateTable) { var type = method.DeclaringType; var luaDelegateName = getDelegateName(method); if (luaDelegateName == null) { Debug.LogError("too many overload!"); return false; } bool isFinalize = method.Name == "Finalize"; FieldDefinition fieldDefinition = new FieldDefinition(luaDelegateName, Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.Private, luaFunctionType); type.Fields.Add(fieldDefinition); FieldReference fieldReference = fieldDefinition.GetGeneric(); int param_start = method.IsStatic ? 0 : 1; int param_count = method.Parameters.Count + param_start; var firstIns = method.Body.Instructions[0]; var processor = method.Body.GetILProcessor(); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Brfalse, firstIns)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Callvirt, invokeSessionStart)); bool statefulConstructor = (hotfixType == 1) && 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(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldarg_0)); if (hotfixType == 1 && !method.IsConstructor) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldfld, stateTable)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Callvirt, MakeGenericMethod(inParam, luaTableType))); } else { if (type.IsValueType) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldobj, method.DeclaringType.GetGeneric())); } processor.InsertBefore(firstIns, 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(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); if (i < ldargs.Length) { processor.InsertBefore(firstIns, processor.Create(ldargs[i])); } else { processor.InsertBefore(firstIns, 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(firstIns, processor.Create(OpCodes.Ldobj, paramType)); } else { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldind_Ref)); } } if (i == param_count - 1 && param.CustomAttributes.Any(ca => ca.AttributeType.FullName == "System.ParamArrayAttribute")) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Callvirt, MakeGenericMethod(inParams, ((ArrayType)paramType).ElementType))); } else { processor.InsertBefore(firstIns, processor.Create(OpCodes.Callvirt, MakeGenericMethod(inParam, paramType))); } } } } int outStart = (isVoid ? 0 : 1); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldc_I4, outCout + outStart)); processor.InsertBefore(firstIns, 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(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldc_I4, outPos)); int arg_pos = param_start + i; if (arg_pos < ldargs.Length) { processor.InsertBefore(firstIns, processor.Create(ldargs[arg_pos])); } else { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldarg, (short)arg_pos)); } processor.InsertBefore(firstIns, processor.Create(OpCodes.Callvirt, MakeGenericMethod(outParam, ((ByReferenceType)method.Parameters[i].ParameterType).ElementType))); outPos++; } } if (statefulConstructor) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldarg_0)); } processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldsfld, fieldReference)); if (isVoid) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Callvirt, invokeSessionEnd)); } else { processor.InsertBefore(firstIns, processor.Create(OpCodes.Callvirt, MakeGenericMethod(invokeSessionEndWithResult, returnType))); } if (statefulConstructor) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Stfld, stateTable)); } if (isFinalize && hotfixType == 1) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldarg_0)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Ldnull)); processor.InsertBefore(firstIns, processor.Create(OpCodes.Stfld, stateTable)); } if (!method.IsConstructor && !isFinalize) { processor.InsertBefore(firstIns, processor.Create(OpCodes.Ret)); } if (isFinalize) { method.Body.ExceptionHandlers[0].TryStart = method.Body.Instructions[0]; } return true; }