public static Instruction ParseInstruction(ILProcessor processor, TypeDefinition type, XElement instrXML) { return(processor.Create(OpCodes.Stloc_0)); }
/// <summary> /// Patches the Method. /// </summary> /// <param name="Method">The Method.</param> Boolean PatchMethod(MethodDefinition Method) { Boolean IsSharpJit = false; List<String> Attributes = this.GetSharpDXAttributes(Method); if (Attributes.Contains("SharpDX.ModuleInit")) { CreateModuleInit(Method); } if (Method.DeclaringType.Name == "Interop") { if (Method.Name == "memcpy") { CreateMemcpy(Method); } else if (Method.Name == "memset") { CreateMemset(Method); } else if ((Method.Name == "Cast") || (Method.Name == "CastOut")) { CreateCastMethod(Method); } else if (Method.Name == "CastArray") { CreateCastArrayMethod(Method); } else if (Method.Name == "Read" || (Method.Name == "ReadOut") || (Method.Name == "Read2D")) { if (Method.Parameters.Count == 2) CreateReadMethod(Method); else CreateReadRangeMethod(Method); } else if (Method.Name == "Write" || (Method.Name == "Write2D")) { if (Method.Parameters.Count == 2) CreateWriteMethod(Method); else CreateWriteRangeMethod(Method); } } else if (Method.HasBody) { ILProcessor IlProcessor = Method.Body.GetILProcessor(); Collection<Instruction> instructions = Method.Body.Instructions; Instruction Instruction = null; Instruction previousInstruction; for (Int32 Index = 0; Index < instructions.Count; Index++) { previousInstruction = Instruction; Instruction = instructions[Index]; if (Instruction.OpCode != OpCodes.Call || !(Instruction.Operand is MethodReference)) continue; MethodReference MethodDescription = (MethodReference)Instruction.Operand; if (MethodDescription is MethodDefinition) { foreach (CustomAttribute CustomAttribute in ((MethodDefinition)MethodDescription).CustomAttributes) { if (CustomAttribute.AttributeType.FullName == typeof(ObfuscationAttribute).FullName) { foreach (Mono.Cecil.CustomAttributeNamedArgument Arg in CustomAttribute.Properties) { if (Arg.Name == "Feature" && Arg.Argument.Value != null) { var customValue = Arg.Argument.Value.ToString(); if (customValue.StartsWith("SharpJit.")) { IsSharpJit = true; break; } } } } if (IsSharpJit) break; } } if (!IsSharpJit) { if (MethodDescription.Name.StartsWith("Calli") && MethodDescription.DeclaringType.Name == "LocalInterop") { CallSite CallSite = new CallSite(MethodDescription.ReturnType) { CallingConvention = MethodCallingConvention.StdCall }; // Last parameter is the function ptr, so we don't add it as a parameter for calli // as it is already an implicit parameter for calli for (Int32 ParameterIndex = 0; ParameterIndex < MethodDescription.Parameters.Count - 1; ParameterIndex++) { ParameterDefinition ParameterDefinition = MethodDescription.Parameters[ParameterIndex]; CallSite.Parameters.Add(ParameterDefinition); } // Create calli Instruction Instruction CallIInstruction = IlProcessor.Create(OpCodes.Calli, CallSite); // Replace instruction IlProcessor.Replace(Instruction, CallIInstruction); } else if (MethodDescription.DeclaringType.Name == "Interop") { if (MethodDescription.FullName.Contains("Fixed")) { if (MethodDescription.Parameters[0].ParameterType.IsArray) { ReplaceFixedArrayStatement(Method, IlProcessor, Instruction); } else { ReplaceFixedStatement(Method, IlProcessor, Instruction); } } else if (MethodDescription.Name.StartsWith("ReadInline")) { this.ReplaceReadInline(Method, IlProcessor, Instruction); } else if (MethodDescription.Name.StartsWith("CopyInline") || MethodDescription.Name.StartsWith("WriteInline")) { this.ReplaceCopyInline(Method, IlProcessor, Instruction); } else if (MethodDescription.Name.StartsWith("SizeOf")) { this.ReplaceSizeOfStructGeneric(Method, IlProcessor, Instruction); } } } } } return IsSharpJit; }
// todo add documentation public static Instruction Create <T, TR>(this ILProcessor worker, OpCode code, Expression <Func <T, TR> > expression) { MethodReference typeref = worker.Body.Method.Module.ImportReference(expression); return(worker.Create(code, typeref)); }
public static MethodDefinition ProcessSyncVarSet(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId) { //Create the set method MethodDefinition set = new MethodDefinition("set_Network" + originalName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, Weaver.voidType); ILProcessor setWorker = set.Body.GetILProcessor(); // if (!SyncVarEqual(value, ref playerData)) Instruction endOfMethod = setWorker.Create(OpCodes.Nop); // this setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); // new value to set setWorker.Append(setWorker.Create(OpCodes.Ldarg_1)); // reference to field to set // make generic version of SetSyncVar with field type if (fd.FieldType.FullName == Weaver.gameObjectType.FullName) { // reference to netId Field to set setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldfld, netFieldId)); setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.syncVarGameObjectEqualReference)); } else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName) { // reference to netId Field to set setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldfld, netFieldId)); setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.syncVarNetworkIdentityEqualReference)); } else { setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldflda, fd)); GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference); syncVarEqualGm.GenericArguments.Add(fd.FieldType); setWorker.Append(setWorker.Create(OpCodes.Call, syncVarEqualGm)); } setWorker.Append(setWorker.Create(OpCodes.Brtrue, endOfMethod)); CheckForHookFunction(td, fd, out MethodDefinition hookFunctionMethod); if (hookFunctionMethod != null) { //if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit)) Instruction label = setWorker.Create(OpCodes.Nop); setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.NetworkServerGetLocalClientActive)); setWorker.Append(setWorker.Create(OpCodes.Brfalse, label)); setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit)); setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.getSyncVarHookGuard)); setWorker.Append(setWorker.Create(OpCodes.Brtrue, label)); // setSyncVarHookGuard(dirtyBit, true); setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit)); setWorker.Append(setWorker.Create(OpCodes.Ldc_I4_1)); setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarHookGuard)); // call hook setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldarg_1)); setWorker.Append(setWorker.Create(OpCodes.Call, hookFunctionMethod)); // setSyncVarHookGuard(dirtyBit, false); setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit)); setWorker.Append(setWorker.Create(OpCodes.Ldc_I4_0)); setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarHookGuard)); setWorker.Append(label); } // this setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); // new value to set setWorker.Append(setWorker.Create(OpCodes.Ldarg_1)); // reference to field to set setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldflda, fd)); // dirty bit setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit)); // 8 byte integer aka long if (fd.FieldType.FullName == Weaver.gameObjectType.FullName) { // reference to netId Field to set setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldflda, netFieldId)); setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarGameObjectReference)); } else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName) { // reference to netId Field to set setWorker.Append(setWorker.Create(OpCodes.Ldarg_0)); setWorker.Append(setWorker.Create(OpCodes.Ldflda, netFieldId)); setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarNetworkIdentityReference)); } else { // make generic version of SetSyncVar with field type GenericInstanceMethod gm = new GenericInstanceMethod(Weaver.setSyncVarReference); gm.GenericArguments.Add(fd.FieldType); // invoke SetSyncVar setWorker.Append(setWorker.Create(OpCodes.Call, gm)); } setWorker.Append(endOfMethod); setWorker.Append(setWorker.Create(OpCodes.Ret)); set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType)); set.SemanticsAttributes = MethodSemanticsAttributes.Setter; return(set); }
public override Instruction CreateInstruction(ILProcessor worker, OpCode opcode) { return(worker.Create(opcode, SelectedOperand)); }
/// <summary> /// Transfuses an instruction into a target method. /// </summary> /// <param name="inst">Instruction to transfuse</param> /// <param name="offset">Start offset</param> /// <param name="targetAssembly">Target assembly</param> /// <param name="targetMethod">Target method</param> /// <param name="importToAssembly">Assembly to import to</param> /// <param name="verbose">Whether to print verbose messages to the console</param> /// <returns></returns> public static Instruction TransfuseInstruction(Instruction inst, int offset, AssemblyDefinition targetAssembly, MethodDefinition targetMethod, AssemblyDefinition importToAssembly, bool verbose) { Instruction newInst = null; ILProcessor proc = targetMethod.Body.GetILProcessor(); if (inst.Operand == null) { newInst = proc.Create(inst.OpCode); } else if (inst.Operand is byte) { newInst = proc.Create(inst.OpCode, (byte)inst.Operand); } else if (inst.Operand is sbyte) { newInst = proc.Create(inst.OpCode, (sbyte)inst.Operand); } else if (inst.Operand is short) { newInst = proc.Create(inst.OpCode, (short)inst.Operand); } else if (inst.Operand is int) { newInst = proc.Create(inst.OpCode, (int)inst.Operand); } else if (inst.Operand is long) { newInst = proc.Create(inst.OpCode, (long)inst.Operand); } else if (inst.Operand is float) { newInst = proc.Create(inst.OpCode, (float)inst.Operand); } else if (inst.Operand is double) { newInst = proc.Create(inst.OpCode, (double)inst.Operand); } else if (inst.Operand is string) { newInst = proc.Create(inst.OpCode, (string)inst.Operand); } else if (inst.Operand is Instruction) { newInst = proc.Create(inst.OpCode, TransfuseInstruction(inst.Operand as Instruction, offset, targetAssembly, targetMethod, importToAssembly, verbose)); } else if (inst.Operand is Instruction[]) { Instruction[] insts = inst.Operand as Instruction[]; for (var i = 0; i < insts.Length; i++) { insts[i] = TransfuseInstruction(insts[i], offset, targetAssembly, targetMethod, importToAssembly, verbose); } newInst = proc.Create(inst.OpCode, insts); } else if (inst.Operand is VariableReference) { VariableDefinition def = (inst.Operand as VariableReference).Resolve(); newInst = proc.Create(inst.OpCode, new VariableDefinition(def.Name, importToAssembly.MainModule.Import(def.VariableType))); } else if (inst.Operand is TypeReference) { TypeDefinition def = (inst.Operand as TypeReference).Resolve(); if (def != null) { if (verbose) { Console.WriteLine("< import " + def); } newInst = proc.Create(inst.OpCode, importToAssembly.MainModule.Import(def)); } else { throw new Exception("Unresolved TypeReference: " + inst.Operand); } } else if (inst.Operand is FieldReference) { FieldDefinition def = (inst.Operand as FieldReference).Resolve(); if (def != null) { if (verbose) { Console.WriteLine("< import " + def); } newInst = proc.Create(inst.OpCode, importToAssembly.MainModule.Import(def)); } else { throw new Exception("Unresolved FieldReference: " + inst.Operand); } } else if (inst.Operand is MethodReference) { MethodDefinition def = (inst.Operand as MethodReference).Resolve(); if (def != null) { if (verbose) { Console.WriteLine("< import " + def); } newInst = proc.Create(inst.OpCode, importToAssembly.MainModule.Import(def)); } else { throw new Exception("Unresolved MethodReference: " + inst.Operand); } } else { throw new Exception("Unknown Operand type: " + inst.Operand.GetType()); } newInst.Offset = offset + inst.Offset; return(newInst); }
public static void EmitPointerToObject(this ILProcessor body, TypeReference originalReturnType, TypeReference convertedReturnType, TypeRewriteContext enclosingType, Instruction loadPointer, bool extraDerefForNonValueTypes, bool unboxValueType) { // input stack: not used // output stack: converted result if (originalReturnType is GenericParameter) { EmitPointerToObjectGeneric(body, originalReturnType, convertedReturnType, enclosingType, loadPointer, extraDerefForNonValueTypes, unboxValueType); return; } var imports = enclosingType.AssemblyContext.Imports; if (originalReturnType.FullName == "System.Void") { // do nothing } else if (originalReturnType.IsValueType) { if (convertedReturnType.IsValueType) { body.Append(loadPointer); if (unboxValueType) { body.Emit(OpCodes.Call, imports.ObjectUnbox); } body.Emit(OpCodes.Ldobj, convertedReturnType); } else { if (!unboxValueType) { var classPointerTypeRef = new GenericInstanceType(imports.Il2CppClassPointerStore) { GenericArguments = { convertedReturnType } }; var classPointerFieldRef = new FieldReference(nameof(Il2CppClassPointerStore <int> .NativeClassPtr), imports.IntPtr, classPointerTypeRef); body.Emit(OpCodes.Ldsfld, enclosingType.NewType.Module.ImportReference(classPointerFieldRef)); body.Append(loadPointer); body.Emit(OpCodes.Call, imports.ObjectBox); } else // already boxed { body.Append(loadPointer); } body.Emit(OpCodes.Newobj, new MethodReference(".ctor", imports.Void, convertedReturnType) { Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true }); } } else if (originalReturnType.FullName == "System.String") { body.Append(loadPointer); if (extraDerefForNonValueTypes) { body.Emit(OpCodes.Ldind_I); } body.Emit(OpCodes.Call, imports.StringFromNative); } else if (originalReturnType.IsArray && originalReturnType.GetElementType().IsGenericParameter) { body.Append(loadPointer); var actualReturnType = imports.Il2CppArrayBaseSelfSubst; var methodRef = new MethodReference(nameof(Il2CppArrayBase <int> .WrapNativeGenericArrayPointer), actualReturnType, convertedReturnType) { HasThis = false, Parameters = { new ParameterDefinition(imports.IntPtr) } }; body.Emit(OpCodes.Call, methodRef); } else { var createRealObject = body.Create(OpCodes.Newobj, new MethodReference(".ctor", imports.Void, convertedReturnType) { Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true }); var endNop = body.Create(OpCodes.Nop); body.Append(loadPointer); if (extraDerefForNonValueTypes) { body.Emit(OpCodes.Ldind_I); } body.Emit(OpCodes.Dup); body.Emit(OpCodes.Brtrue_S, createRealObject); body.Emit(OpCodes.Pop); body.Emit(OpCodes.Ldnull); body.Emit(OpCodes.Br, endNop); body.Append(createRealObject); body.Append(endNop); } }
public static MethodDefinition ProcessEventInvoke(TypeDefinition td, EventDefinition ed) { // find the field that matches the event FieldDefinition eventField = null; foreach (FieldDefinition fd in td.Fields) { if (fd.FullName == ed.FullName) { eventField = fd; break; } } if (eventField == null) { Weaver.Error($"event field not found for {ed.Name}. Did you declare it as an event?", ed); return(null); } MethodDefinition cmd = new MethodDefinition("InvokeSyncEvent" + ed.Name, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType); ILProcessor worker = cmd.Body.GetILProcessor(); Instruction label1 = worker.Create(OpCodes.Nop); Instruction label2 = worker.Create(OpCodes.Nop); NetworkBehaviourProcessor.WriteClientActiveCheck(worker, ed.Name, label1, "Event"); // null event check worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Castclass, td)); worker.Append(worker.Create(OpCodes.Ldfld, eventField)); worker.Append(worker.Create(OpCodes.Brtrue, label2)); worker.Append(worker.Create(OpCodes.Ret)); worker.Append(label2); // setup reader worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Castclass, td)); worker.Append(worker.Create(OpCodes.Ldfld, eventField)); // read the event arguments MethodReference invoke = Resolvers.ResolveMethod(eventField.FieldType, Weaver.CurrentAssembly, "Invoke"); if (!NetworkBehaviourProcessor.ReadArguments(invoke.Resolve(), worker, RemoteCallType.SyncEvent)) { return(null); } // invoke actual event delegate function worker.Append(worker.Create(OpCodes.Callvirt, invoke)); worker.Append(worker.Create(OpCodes.Ret)); NetworkBehaviourProcessor.AddInvokeParameters(cmd.Parameters); return(cmd); }
static MethodDefinition GenerateArrayReadFunc(TypeReference variable) { if (!variable.IsArrayType()) { Weaver.Error($"{variable.Name} is an unsupported type. Jagged and multidimensional arrays are not supported", variable); return(null); } MethodDefinition readerFunc = GenerateReaderFunction(variable); TypeReference elementType = variable.GetElementType(); MethodReference elementReadFunc = GetReadFunc(elementType); if (elementReadFunc == null) { Weaver.Error($"Cannot generate reader for Array because element {elementType.Name} does not have a reader. Use a supported type or provide a custom reader", variable); return(readerFunc); } // int lengh readerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.Import <int>())); // T[] array readerFunc.Body.Variables.Add(new VariableDefinition(variable)); // int i; readerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.Import <int>())); ILProcessor worker = readerFunc.Body.GetILProcessor(); // int length = reader.ReadPackedInt32(); GenerateReadLength(worker); GenerateNullLengthCheck(worker); // T value = new T[length]; worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Newarr, variable.GetElementType())); worker.Append(worker.Create(OpCodes.Stloc_1)); // for (int i=0; i< length ; i++) { GenerateFor(worker, () => { // value[i] = reader.ReadT(); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldelema, variable.GetElementType())); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, elementReadFunc)); worker.Append(worker.Create(OpCodes.Stobj, variable.GetElementType())); }); // return value; worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ret)); return(readerFunc); }
static int EmitParameters(MethodDefinition method, MethodDefinition native, MethodBody body, ILProcessor il) { int i; for (i = 0; i < method.Parameters.Count; i++) { var parameter = method.Parameters[i]; var p = method.Module.Import(method.Parameters[i].ParameterType); il.Emit(OpCodes.Ldarg, i); if (p.Name.Contains("Int32") && native.Parameters[i].ParameterType.Name.Contains("IntPtr")) { // This is a convenience Int32 overload for an IntPtr (size_t) parameter. // We need to convert the loaded argument to IntPtr. il.Emit(OpCodes.Conv_I); } else if (p.Name == "StringBuilder") { EmitStringBuilderParameter(method, parameter, body, il); } else if (p.Name == "String" && !p.IsArray) { EmitStringParameter(method, parameter, body, il); } else if (p.IsByReference) { body.Variables.Add(new VariableDefinition(new PinnedType(p))); var index = body.Variables.Count - 1; il.Emit(OpCodes.Stloc, index); il.Emit(OpCodes.Ldloc, index); il.Emit(OpCodes.Conv_I); } else if (p.IsArray) { if (p.Name != method.Module.Import(typeof(string[])).Name) { // .Net treats 1d arrays differently than higher rank arrays. // 1d arrays are directly supported by instructions such as ldlen and ldelema. // Higher rank arrays must be accessed through System.Array methods such as get_Length. // 1d array: // check array is not null // check ldlen array > 0 // ldc.i4.0 // ldelema // 2d array: // check array is not null // check array.get_Length() > 0 // ldc.i4.0 // ldc.i4.0 // call instance T& T[0..., 0...]::Address(int32, int32) // Mono treats everything as a 1d array. // Interestingly, the .Net approach works on both Mono and .Net. // The Mono approach fails when using high-rank arrays on .Net. // We should report a bug to http://bugzilla.xamarin.com // Pin the array and pass the address // of its first element. var array = (ArrayType)p; var element_type = p.GetElementType(); body.Variables.Add(new VariableDefinition(new PinnedType(new ByReferenceType(element_type)))); int pinned_index = body.Variables.Count - 1; var empty = il.Create(OpCodes.Ldc_I4, 0); var pin = il.Create(OpCodes.Ldarg, i); var end = il.Create(OpCodes.Stloc, pinned_index); // if (array == null) goto empty il.Emit(OpCodes.Brfalse, empty); // else if (array.Length != 0) goto pin il.Emit(OpCodes.Ldarg, i); if (array.Rank == 1) { il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); } else { var get_length = method.Module.Import( mscorlib.MainModule.GetType("System.Array").Methods.First(m => m.Name == "get_Length")); il.Emit(OpCodes.Callvirt, get_length); } il.Emit(OpCodes.Brtrue, pin); // empty: IntPtr ptr = IntPtr.Zero il.Append(empty); il.Emit(OpCodes.Conv_U); il.Emit(OpCodes.Br, end); // pin: &array[0] il.Append(pin); if (array.Rank == 1) { // 1d array (vector), address is taken by ldelema il.Emit(OpCodes.Ldc_I4, 0); il.Emit(OpCodes.Ldelema, element_type); } else { // 2d-3d array, address must be taken as follows: // call instance T& T[0..., 0..., 0...]::Address(int, int, int) ByReferenceType t_ref = array.ElementType.MakeByReferenceType(); MethodReference get_address = new MethodReference("Address", t_ref, array); for (int r = 0; r < array.Rank; r++) { get_address.Parameters.Add(new ParameterDefinition(TypeInt32)); } get_address.HasThis = true; // emit the get_address call for (int r = 0; r < array.Rank; r++) { il.Emit(OpCodes.Ldc_I4, 0); } il.Emit(OpCodes.Call, get_address); } // end: fixed (IntPtr ptr = &array[0]) il.Append(end); il.Emit(OpCodes.Ldloc, pinned_index); il.Emit(OpCodes.Conv_I); } else { EmitStringArrayParameter(method, parameter, body, il); } } } return(i); }
private void InstrumentInstruction(int instructionId, Instruction instruction, MethodReference hitMethodReference, MethodDefinition method, ILProcessor ilProcessor) { var pathParamLoadInstruction = ilProcessor.Create(OpCodes.Ldstr, hitsFile); var lineParamLoadInstruction = ilProcessor.Create(OpCodes.Ldc_I4, instructionId); var registerInstruction = ilProcessor.Create(OpCodes.Call, hitMethodReference); ilProcessor.InsertBefore(instruction, registerInstruction); ilProcessor.InsertBefore(registerInstruction, lineParamLoadInstruction); ilProcessor.InsertBefore(lineParamLoadInstruction, pathParamLoadInstruction); var newFirstInstruction = pathParamLoadInstruction; //change try/finally etc to point to our first instruction if they referenced the one we inserted before foreach (var handler in method.Body.ExceptionHandlers) { if (handler.FilterStart == instruction) { handler.FilterStart = newFirstInstruction; } if (handler.TryStart == instruction) { handler.TryStart = newFirstInstruction; } if (handler.TryEnd == instruction) { handler.TryEnd = newFirstInstruction; } if (handler.HandlerStart == instruction) { handler.HandlerStart = newFirstInstruction; } if (handler.HandlerEnd == instruction) { handler.HandlerEnd = newFirstInstruction; } } //change instructions with a target instruction if they referenced the one we inserted before to be our first instruction foreach (var iteratedInstruction in method.Body.Instructions) { var operand = iteratedInstruction.Operand; if (operand == instruction) { iteratedInstruction.Operand = newFirstInstruction; continue; } if (!(operand is Instruction[])) { continue; } var operands = (Instruction[])operand; for (var i = 0; i < operands.Length; ++i) { if (operands[i] == instruction) { operands[i] = newFirstInstruction; } } } }
public Instruction CreateInstruction(ILProcessor worker, OpCode opcode) { return(worker.Create(opcode, _selectedInstructions.ToArray())); }
private static void InjectIL(TypeDefinition type, ModuleDefinition module) { const string targetMethod = "Load"; // From class -> JsonLoadRequest -> StringDataLoadRequest TypeDefinition baseType = type.BaseType.Resolve().BaseType.Resolve(); MethodDefinition method = baseType.GetMethods().FirstOrDefault(m => m.Name == targetMethod); if (method == null) { CecilManager.WriteError($"Can't find method: {targetMethod}\n"); return; } ILProcessor ilProcessor = method.Body.GetILProcessor(); // Add a enew reference to an importable method call for AsyncJsonLoadRequest.Load() TypeReference ajlr_TR = module.ImportReference(typeof(AsyncJsonLoadRequest)); TypeReference taskTR = module.ImportReference(typeof(Task)); MethodReference ajlr_lr_MR = new MethodReference("LoadResource", taskTR, ajlr_TR); TypeReference stringTR = module.ImportReference(typeof(string)); ajlr_lr_MR.Parameters.Add(new ParameterDefinition(stringTR)); TypeReference actionStringTR = module.ImportReference(typeof(Action <string>)); ajlr_lr_MR.Parameters.Add(new ParameterDefinition(actionStringTR)); ajlr_lr_MR.ReturnType = taskTR; MethodReference ajlr_lr_Imported_MR = module.ImportReference(ajlr_lr_MR); // Walk the instructions to find the target. Don't mutate as we go, so we can use insertAfter later. int targetIdx = -1; for (int i = 0; i < method.Body.Instructions.Count - 1; i++) { Instruction instruction = method.Body.Instructions[i]; if (instruction.OpCode == OpCodes.Callvirt && instruction.Operand is MethodDefinition methodDef) { //CecilManager.WriteLog($"Found methodDef: {methodDef.FullName}"); if (methodDef.FullName.StartsWith("System.Void HBS.Data.DataLoader::LoadResource")) { CecilManager.WriteLog($"Found injection point: {methodDef.FullName}\n"); targetIdx = i; } } } if (targetIdx != -1) { // Replace callvirt for dataManager.dataLoader.LoadResource with call to AsyncJsonLoadRequest method.Body.Instructions[targetIdx] = ilProcessor.Create(OpCodes.Call, ajlr_lr_Imported_MR); // Elminate references to dataLoader (no longer used) method.Body.Instructions[targetIdx - 9].OpCode = OpCodes.Nop; method.Body.Instructions[targetIdx - 9].Operand = null; method.Body.Instructions[targetIdx - 8].OpCode = OpCodes.Nop; method.Body.Instructions[targetIdx - 8].Operand = null; method.Body.Instructions[targetIdx - 7].OpCode = OpCodes.Nop; method.Body.Instructions[targetIdx - 7].Operand = null; // Add a pop to remove the async Task (to eliminate dnSpy decompile err) Instruction popInst = ilProcessor.Create(OpCodes.Pop); ilProcessor.InsertAfter(method.Body.Instructions[targetIdx], popInst); } }
public InstructionBlock CreateThisVariable(VariableDefinition instanceVariable, TypeReference objectTypeReference) { if (_method.IsStatic) { return(new InstructionBlock("Static method call: " + _method.Name, _processor.Create(OpCodes.Nop))); } var loadThisInstruction = _processor.Create(OpCodes.Ldarg_0); var castInstruction = _processor.Create(OpCodes.Castclass, objectTypeReference); var storeThisInstruction = _processor.Create(OpCodes.Stloc, instanceVariable); return(new InstructionBlock( "Store instance for: " + _method.Name, loadThisInstruction, castInstruction, storeThisInstruction)); }
void GenerateDeSerialization() { Weaver.DLog(netBehaviourSubclass, " GenerateDeSerialization"); foreach (MethodDefinition m in netBehaviourSubclass.Methods) { if (m.Name == "OnDeserialize") { return; } } if (syncVars.Count == 0) { // no synvars, no need for custom OnDeserialize return; } MethodDefinition serialize = new MethodDefinition("OnDeserialize", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.voidType); serialize.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType))); serialize.Parameters.Add(new ParameterDefinition("initialState", ParameterAttributes.None, Weaver.boolType)); ILProcessor serWorker = serialize.Body.GetILProcessor(); // setup local for dirty bits serialize.Body.InitLocals = true; VariableDefinition dirtyBitsLocal = new VariableDefinition(Weaver.int64Type); serialize.Body.Variables.Add(dirtyBitsLocal); MethodReference baseDeserialize = Resolvers.ResolveMethodInParents(netBehaviourSubclass.BaseType, Weaver.CurrentAssembly, "OnDeserialize"); if (baseDeserialize != null) { serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // reader serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); // initialState serWorker.Append(serWorker.Create(OpCodes.Call, baseDeserialize)); } // Generates: if (initialState); Instruction initialStateLabel = serWorker.Create(OpCodes.Nop); serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel)); foreach (FieldDefinition syncVar in syncVars) { DeserializeField(syncVar, serWorker, serialize); } serWorker.Append(serWorker.Create(OpCodes.Ret)); // Generates: end if (initialState); serWorker.Append(initialStateLabel); // get dirty bits serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkReaderReadPackedUInt64)); serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); // conditionally read each syncvar int dirtyBit = Weaver.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName); // start at number of syncvars in parent foreach (FieldDefinition syncVar in syncVars) { Instruction varLabel = serWorker.Create(OpCodes.Nop); // check if dirty bit is set serWorker.Append(serWorker.Create(OpCodes.Ldloc_0)); serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit)); serWorker.Append(serWorker.Create(OpCodes.And)); serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel)); DeserializeField(syncVar, serWorker, serialize); serWorker.Append(varLabel); dirtyBit += 1; } if (Weaver.GenerateLogErrors) { serWorker.Append(serWorker.Create(OpCodes.Ldstr, "Injected Deserialize " + netBehaviourSubclass.Name)); serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.logErrorReference)); } serWorker.Append(serWorker.Create(OpCodes.Ret)); netBehaviourSubclass.Methods.Add(serialize); }
private static void GenerateReadLength(ILProcessor worker) { worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, GetReadFunc(WeaverTypes.Import <int>()))); worker.Append(worker.Create(OpCodes.Stloc_0)); }
public override Instruction CreateInstruction(ILProcessor worker, OpCode opcode) { var mdef = Context as MethodDefinition; return(mdef != null?worker.Create(opcode, CecilImporter.Import(mdef.DeclaringType.Module, SelectedOperand, mdef)) : null); }
private static void GenerateFor(ILProcessor worker, Action body) { // loop through array and deserialize each element // generates code like this // for (int i=0; i< length ; i++) // { // <body> // } worker.Append(worker.Create(OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Stloc_2)); Instruction labelHead = worker.Create(OpCodes.Nop); worker.Append(worker.Create(OpCodes.Br, labelHead)); // loop body Instruction labelBody = worker.Create(OpCodes.Nop); worker.Append(labelBody); body(); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldc_I4_1)); worker.Append(worker.Create(OpCodes.Add)); worker.Append(worker.Create(OpCodes.Stloc_2)); // loop while check worker.Append(labelHead); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Blt, labelBody)); }
public static MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId) { //Create the set method MethodDefinition set = new MethodDefinition("set_Network" + originalName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, WeaverTypes.Import(typeof(void))); ILProcessor worker = set.Body.GetILProcessor(); // if (!SyncVarEqual(value, ref playerData)) Instruction endOfMethod = worker.Create(OpCodes.Nop); // this worker.Emit(OpCodes.Ldarg_0); // new value to set worker.Emit(OpCodes.Ldarg_1); // reference to field to set // make generic version of SetSyncVar with field type if (fd.FieldType.Is <UnityEngine.GameObject>()) { // reference to netId Field to set worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldfld, netFieldId); worker.Emit(OpCodes.Call, WeaverTypes.syncVarGameObjectEqualReference); } else if (fd.FieldType.Is <NetworkIdentity>()) { // reference to netId Field to set worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldfld, netFieldId); worker.Emit(OpCodes.Call, WeaverTypes.syncVarNetworkIdentityEqualReference); } else if (fd.FieldType.IsDerivedFrom <NetworkBehaviour>()) { // reference to netId Field to set worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldfld, netFieldId); MethodReference getFunc = WeaverTypes.syncVarNetworkBehaviourEqualReference.MakeGeneric(fd.FieldType); worker.Emit(OpCodes.Call, getFunc); } else { worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, fd); GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(WeaverTypes.syncVarEqualReference); syncVarEqualGm.GenericArguments.Add(fd.FieldType); worker.Emit(OpCodes.Call, syncVarEqualGm); } worker.Emit(OpCodes.Brtrue, endOfMethod); // T oldValue = value; // TODO for GO/NI we need to backup the netId don't we? VariableDefinition oldValue = new VariableDefinition(fd.FieldType); set.Body.Variables.Add(oldValue); worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldfld, fd); worker.Emit(OpCodes.Stloc, oldValue); // this worker.Emit(OpCodes.Ldarg_0); // new value to set worker.Emit(OpCodes.Ldarg_1); // reference to field to set worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, fd); // dirty bit // 8 byte integer aka long worker.Emit(OpCodes.Ldc_I8, dirtyBit); if (fd.FieldType.Is <UnityEngine.GameObject>()) { // reference to netId Field to set worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, netFieldId); worker.Emit(OpCodes.Call, WeaverTypes.setSyncVarGameObjectReference); } else if (fd.FieldType.Is <NetworkIdentity>()) { // reference to netId Field to set worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, netFieldId); worker.Emit(OpCodes.Call, WeaverTypes.setSyncVarNetworkIdentityReference); } else if (fd.FieldType.IsDerivedFrom <NetworkBehaviour>()) { // reference to netId Field to set worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldflda, netFieldId); MethodReference getFunc = WeaverTypes.setSyncVarNetworkBehaviourReference.MakeGeneric(fd.FieldType); worker.Emit(OpCodes.Call, getFunc); } else { // make generic version of SetSyncVar with field type GenericInstanceMethod gm = new GenericInstanceMethod(WeaverTypes.setSyncVarReference); gm.GenericArguments.Add(fd.FieldType); // invoke SetSyncVar worker.Emit(OpCodes.Call, gm); } MethodDefinition hookMethod = GetHookMethod(td, fd); if (hookMethod != null) { //if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit)) Instruction label = worker.Create(OpCodes.Nop); worker.Emit(OpCodes.Call, WeaverTypes.NetworkServerGetLocalClientActive); worker.Emit(OpCodes.Brfalse, label); worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldc_I8, dirtyBit); worker.Emit(OpCodes.Call, WeaverTypes.getSyncVarHookGuard); worker.Emit(OpCodes.Brtrue, label); // setSyncVarHookGuard(dirtyBit, true); worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldc_I8, dirtyBit); worker.Emit(OpCodes.Ldc_I4_1); worker.Emit(OpCodes.Call, WeaverTypes.setSyncVarHookGuard); // call hook (oldValue, newValue) // Generates: OnValueChanged(oldValue, value); WriteCallHookMethodUsingArgument(worker, hookMethod, oldValue); // setSyncVarHookGuard(dirtyBit, false); worker.Emit(OpCodes.Ldarg_0); worker.Emit(OpCodes.Ldc_I8, dirtyBit); worker.Emit(OpCodes.Ldc_I4_0); worker.Emit(OpCodes.Call, WeaverTypes.setSyncVarHookGuard); worker.Append(label); } worker.Append(endOfMethod); worker.Emit(OpCodes.Ret); set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType)); set.SemanticsAttributes = MethodSemanticsAttributes.Setter; return(set); }
static MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable, int recursionCount) { GenericInstanceType genericInstance = (GenericInstanceType)variable; TypeReference elementType = genericInstance.GenericArguments[0]; MethodReference elementReadFunc = GetReadFunc(elementType, recursionCount + 1); if (elementReadFunc == null) { return(null); } string functionName = "_ReadArraySegment_" + variable.GetElementType().Name + "_"; if (variable.DeclaringType != null) { functionName += variable.DeclaringType.Name; } else { functionName += "None"; } // create new reader for this type MethodDefinition readerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, variable); readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType))); // int lengh readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type)); // T[] array readerFunc.Body.Variables.Add(new VariableDefinition(elementType.MakeArrayType())); // int i; readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type)); readerFunc.Body.InitLocals = true; ILProcessor worker = readerFunc.Body.GetILProcessor(); // int length = reader.ReadPackedInt32(); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, GetReadFunc(Weaver.int32Type))); worker.Append(worker.Create(OpCodes.Stloc_0)); // T[] array = new int[length] worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Newarr, elementType)); worker.Append(worker.Create(OpCodes.Stloc_1)); // loop through array and deserialize each element // generates code like this // for (int i=0; i< length ; i++) // { // value[i] = reader.ReadXXX(); // } worker.Append(worker.Create(OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Stloc_2)); Instruction labelHead = worker.Create(OpCodes.Nop); worker.Append(worker.Create(OpCodes.Br, labelHead)); // loop body Instruction labelBody = worker.Create(OpCodes.Nop); worker.Append(labelBody); // value[i] = reader.ReadT(); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldelema, elementType)); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, elementReadFunc)); worker.Append(worker.Create(OpCodes.Stobj, elementType)); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldc_I4_1)); worker.Append(worker.Create(OpCodes.Add)); worker.Append(worker.Create(OpCodes.Stloc_2)); // loop while check worker.Append(labelHead); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Blt, labelBody)); // return new ArraySegment<T>(array); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Newobj, Weaver.ArraySegmentConstructorReference.MakeHostInstanceGeneric(genericInstance))); worker.Append(worker.Create(OpCodes.Ret)); return(readerFunc); }
private static void EmitObjectStoreGeneric(ILProcessor body, TypeReference originalType, TypeReference newType, TypeRewriteContext enclosingType, int argumentIndex) { // input stack: object address, target address // output: nothing var imports = enclosingType.AssemblyContext.Imports; body.Emit(OpCodes.Ldtoken, newType); body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == nameof(Type.GetTypeFromHandle)))); body.Emit(OpCodes.Dup); body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.IsValueType)) !.GetMethod !.Name))); var finalNop = body.Create(OpCodes.Nop); var stringNop = body.Create(OpCodes.Nop); var valueTypeNop = body.Create(OpCodes.Nop); var storePointerNop = body.Create(OpCodes.Nop); body.Emit(OpCodes.Brtrue, valueTypeNop); body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.FullName)) !.GetMethod !.Name))); body.Emit(OpCodes.Ldstr, "System.String"); body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(TargetTypeSystemHandler.String.Methods.Single(it => it.Name == nameof(String.Equals) && it.IsStatic && it.Parameters.Count == 2))); body.Emit(OpCodes.Brtrue_S, stringNop); body.Emit(OpCodes.Ldarg, argumentIndex); body.Emit(OpCodes.Box, newType); body.Emit(OpCodes.Isinst, imports.Il2CppObjectBase); body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer); body.Emit(OpCodes.Dup); body.Emit(OpCodes.Brfalse_S, storePointerNop); body.Emit(OpCodes.Dup); body.Emit(OpCodes.Call, imports.ObjectGetClass); body.Emit(OpCodes.Call, imports.ClassIsValueType); body.Emit(OpCodes.Brfalse_S, storePointerNop); body.Emit(OpCodes.Dup); var tempLocal = new VariableDefinition(imports.IntPtr); body.Body.Variables.Add(tempLocal); body.Emit(OpCodes.Stloc, tempLocal); body.Emit(OpCodes.Call, imports.ObjectUnbox); body.Emit(OpCodes.Ldloc, tempLocal); body.Emit(OpCodes.Call, imports.ObjectGetClass); body.Emit(OpCodes.Ldc_I4_0); body.Emit(OpCodes.Conv_U); body.Emit(OpCodes.Call, imports.ValueSizeGet); body.Emit(OpCodes.Cpblk); body.Emit(OpCodes.Pop); body.Emit(OpCodes.Br_S, finalNop); body.Append(storePointerNop); body.Emit(OpCodes.Call, imports.WriteFieldWBarrier); body.Emit(OpCodes.Br_S, finalNop); body.Append(stringNop); body.Emit(OpCodes.Ldarg, argumentIndex); body.Emit(OpCodes.Box, newType); body.Emit(OpCodes.Isinst, imports.String); body.Emit(OpCodes.Call, imports.StringToNative); body.Emit(OpCodes.Call, imports.WriteFieldWBarrier); body.Emit(OpCodes.Br_S, finalNop); body.Append(valueTypeNop); body.Emit(OpCodes.Pop); // pop extra typeof(T) body.Emit(OpCodes.Ldarg, argumentIndex); body.Emit(OpCodes.Stobj, newType); body.Emit(OpCodes.Pop); body.Append(finalNop); }
public static void WriteCreateWriter(ILProcessor worker) { // create writer worker.Append(worker.Create(OpCodes.Newobj, Weaver.NetworkWriterCtor)); worker.Append(worker.Create(OpCodes.Stloc_0)); }
public static MethodDefinition ProcessSyncVarGet(FieldDefinition fd, string originalName, FieldDefinition netFieldId) { //Create the get method MethodDefinition get = new MethodDefinition( "get_Network" + originalName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, fd.FieldType); ILProcessor getWorker = get.Body.GetILProcessor(); // [SyncVar] GameObject? if (fd.FieldType.FullName == Weaver.gameObjectType.FullName) { // return this.GetSyncVarGameObject(ref field, uint netId); getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); // this. getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); getWorker.Append(getWorker.Create(OpCodes.Ldfld, netFieldId)); getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); getWorker.Append(getWorker.Create(OpCodes.Ldflda, fd)); getWorker.Append(getWorker.Create(OpCodes.Call, Weaver.getSyncVarGameObjectReference)); getWorker.Append(getWorker.Create(OpCodes.Ret)); } // [SyncVar] NetworkIdentity? else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName) { // return this.GetSyncVarNetworkIdentity(ref field, uint netId); getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); // this. getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); getWorker.Append(getWorker.Create(OpCodes.Ldfld, netFieldId)); getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); getWorker.Append(getWorker.Create(OpCodes.Ldflda, fd)); getWorker.Append(getWorker.Create(OpCodes.Call, Weaver.getSyncVarNetworkIdentityReference)); getWorker.Append(getWorker.Create(OpCodes.Ret)); } // [SyncVar] int, string, etc. else { getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); getWorker.Append(getWorker.Create(OpCodes.Ldfld, fd)); getWorker.Append(getWorker.Create(OpCodes.Ret)); } get.Body.Variables.Add(new VariableDefinition(fd.FieldType)); get.Body.InitLocals = true; get.SemanticsAttributes = MethodSemanticsAttributes.Getter; return(get); }
void GenerateConstants() { if (commands.Count == 0 && clientRpcs.Count == 0 && targetRpcs.Count == 0 && eventRpcs.Count == 0 && syncObjects.Count == 0) { return; } Weaver.DLog(netBehaviourSubclass, " GenerateConstants "); // find static constructor MethodDefinition cctor = null; bool cctorFound = false; foreach (MethodDefinition md in netBehaviourSubclass.Methods) { if (md.Name == ".cctor") { cctor = md; cctorFound = true; } } if (cctor != null) { // remove the return opcode from end of function. will add our own later. if (cctor.Body.Instructions.Count != 0) { Instruction ret = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1]; if (ret.OpCode == OpCodes.Ret) { cctor.Body.Instructions.RemoveAt(cctor.Body.Instructions.Count - 1); } else { Weaver.Error($"{netBehaviourSubclass} has invalid class constructor"); return; } } } else { // make one! cctor = new MethodDefinition(".cctor", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Static, Weaver.voidType); } // find instance constructor MethodDefinition ctor = null; foreach (MethodDefinition md in netBehaviourSubclass.Methods) { if (md.Name == ".ctor") { ctor = md; Instruction ret = ctor.Body.Instructions[ctor.Body.Instructions.Count - 1]; if (ret.OpCode == OpCodes.Ret) { ctor.Body.Instructions.RemoveAt(ctor.Body.Instructions.Count - 1); } else { Weaver.Error($"{netBehaviourSubclass} has invalid constructor"); return; } break; } } if (ctor == null) { Weaver.Error($"{netBehaviourSubclass} has invalid constructor"); return; } ILProcessor ctorWorker = ctor.Body.GetILProcessor(); ILProcessor cctorWorker = cctor.Body.GetILProcessor(); for (int i = 0; i < commands.Count; ++i) { GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerCommandDelegateReference, commandInvocationFuncs[i], commands[i].Name); } for (int i = 0; i < clientRpcs.Count; ++i) { GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerRpcDelegateReference, clientRpcInvocationFuncs[i], clientRpcs[i].Name); } for (int i = 0; i < targetRpcs.Count; ++i) { GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerRpcDelegateReference, targetRpcInvocationFuncs[i], targetRpcs[i].Name); } for (int i = 0; i < eventRpcs.Count; ++i) { GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerEventDelegateReference, eventRpcInvocationFuncs[i], eventRpcs[i].Name); } foreach (FieldDefinition fd in syncObjects) { SyncObjectInitializer.GenerateSyncObjectInitializer(ctorWorker, fd); } cctorWorker.Append(cctorWorker.Create(OpCodes.Ret)); if (!cctorFound) { netBehaviourSubclass.Methods.Add(cctor); } // finish ctor ctorWorker.Append(ctorWorker.Create(OpCodes.Ret)); // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit; }
private void ReplaceFixedArrayStatement(MethodDefinition Method, ILProcessor IlProcessor, Instruction fixedtoPatch) { TypeReference ParamT = ((GenericInstanceMethod)fixedtoPatch.Operand).GenericArguments[0]; // Preparing locals // local(0) T* Method.Body.Variables.Add(new VariableDefinition("pin", new PinnedType(new ByReferenceType(ParamT)))); Int32 Index = Method.Body.Variables.Count - 1; Instruction LdlocFixed; Instruction StlocFixed; switch (Index) { case 0: StlocFixed = IlProcessor.Create(OpCodes.Stloc_0); LdlocFixed = IlProcessor.Create(OpCodes.Ldloc_0); break; case 1: StlocFixed = IlProcessor.Create(OpCodes.Stloc_1); LdlocFixed = IlProcessor.Create(OpCodes.Ldloc_1); break; case 2: StlocFixed = IlProcessor.Create(OpCodes.Stloc_2); LdlocFixed = IlProcessor.Create(OpCodes.Ldloc_2); break; case 3: StlocFixed = IlProcessor.Create(OpCodes.Stloc_3); LdlocFixed = IlProcessor.Create(OpCodes.Ldloc_3); break; default: StlocFixed = IlProcessor.Create(OpCodes.Stloc, Index); LdlocFixed = IlProcessor.Create(OpCodes.Ldloc, Index); break; } Instruction InstructionLdci40 = IlProcessor.Create(OpCodes.Ldc_I4_0); IlProcessor.InsertBefore(fixedtoPatch, InstructionLdci40); Instruction InstructionLdElema = IlProcessor.Create(OpCodes.Ldelema, ParamT); IlProcessor.InsertBefore(fixedtoPatch, InstructionLdElema); IlProcessor.InsertBefore(fixedtoPatch, StlocFixed); IlProcessor.Replace(fixedtoPatch, LdlocFixed); }
void GenerateSerialization() { Weaver.DLog(netBehaviourSubclass, " GenerateSerialization"); foreach (MethodDefinition m in netBehaviourSubclass.Methods) { if (m.Name == "OnSerialize") { return; } } if (syncVars.Count == 0) { // no synvars, no need for custom OnSerialize return; } MethodDefinition serialize = new MethodDefinition("OnSerialize", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.boolType); serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkWriterType))); serialize.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, Weaver.boolType)); ILProcessor serWorker = serialize.Body.GetILProcessor(); serialize.Body.InitLocals = true; // loc_0, this local variable is to determine if any variable was dirty VariableDefinition dirtyLocal = new VariableDefinition(Weaver.boolType); serialize.Body.Variables.Add(dirtyLocal); MethodReference baseSerialize = Resolvers.ResolveMethodInParents(netBehaviourSubclass.BaseType, Weaver.CurrentAssembly, "OnSerialize"); if (baseSerialize != null) { serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); // forceAll serWorker.Append(serWorker.Create(OpCodes.Call, baseSerialize)); serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); // set dirtyLocal to result of base.OnSerialize() } // Generates: if (forceAll); Instruction initialStateLabel = serWorker.Create(OpCodes.Nop); serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); // forceAll serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel)); foreach (FieldDefinition syncVar in syncVars) { // Generates a writer call for each sync variable serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // this serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar)); MethodReference writeFunc = Writers.GetWriteFunc(syncVar.FieldType); if (writeFunc != null) { serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc)); } else { Weaver.Error($"{syncVar} has unsupported type. Use a supported Mirror type instead"); return; } } // always return true if forceAll // Generates: return true serWorker.Append(serWorker.Create(OpCodes.Ldc_I4_1)); serWorker.Append(serWorker.Create(OpCodes.Ret)); // Generates: end if (forceAll); serWorker.Append(initialStateLabel); // write dirty bits before the data fields // Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ()); serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference)); serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePackedUInt64)); // generate a writer call for any dirty variable in this class // start at number of syncvars in parent int dirtyBit = Weaver.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName); foreach (FieldDefinition syncVar in syncVars) { Instruction varLabel = serWorker.Create(OpCodes.Nop); // Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL) serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference)); serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit)); // 8 bytes = long serWorker.Append(serWorker.Create(OpCodes.And)); serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel)); // Generates a call to the writer for that field serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar)); MethodReference writeFunc = Writers.GetWriteFunc(syncVar.FieldType); if (writeFunc != null) { serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc)); } else { Weaver.Error($"{syncVar} has unsupported type. Use a supported Mirror type instead"); return; } // something was dirty serWorker.Append(serWorker.Create(OpCodes.Ldc_I4_1)); serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); // set dirtyLocal to true serWorker.Append(varLabel); dirtyBit += 1; } if (Weaver.GenerateLogErrors) { serWorker.Append(serWorker.Create(OpCodes.Ldstr, "Injected Serialize " + netBehaviourSubclass.Name)); serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.logErrorReference)); } // generate: return dirtyLocal serWorker.Append(serWorker.Create(OpCodes.Ldloc_0)); serWorker.Append(serWorker.Create(OpCodes.Ret)); netBehaviourSubclass.Methods.Add(serialize); }
static void GenerateSerialization(TypeDefinition td) { Weaver.DLog(td, " GenerateSerialization"); MethodDefinition existingMethod = td.GetMethodWith1Arg("Serialize", WeaverTypes.Import <NetworkWriter>()); // do nothing if method exists and is abstract or not empty if (existingMethod != null && (existingMethod.IsAbstract || !existingMethod.Body.IsEmptyDefault())) { return; } if (td.Fields.Count == 0) { return; } // check for self-referencing types foreach (FieldDefinition field in td.Fields) { if (field.FieldType.FullName == td.FullName) { Weaver.Error($"{td.Name} has field {field.Name} that references itself", field); return; } } MethodDefinition serializeFunc = existingMethod ?? new MethodDefinition("Serialize", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, WeaverTypes.Import(typeof(void))); //only add to new method if (existingMethod == null) { serializeFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, WeaverTypes.Import <NetworkWriter>())); } ILProcessor worker = serializeFunc.Body.GetILProcessor(); if (existingMethod != null) { //remove default nop&ret from existing empty interface method worker.Body.Instructions.Clear(); } // if it is not a struct, call base if (!td.IsValueType) { // call base CallBase(td, worker, "Serialize"); } foreach (FieldDefinition field in td.Fields) { if (field.IsStatic || field.IsPrivate || field.IsSpecialName) { continue; } CallWriter(worker, field); } worker.Append(worker.Create(OpCodes.Ret)); //only add if not just replaced body if (existingMethod == null) { td.Methods.Add(serializeFunc); } }
void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize) { // check for Hook function if (!SyncVarProcessor.CheckForHookFunction(netBehaviourSubclass, syncVar, out MethodDefinition foundMethod)) { return; } if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName || syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName) { // GameObject/NetworkIdentity SyncVar: // OnSerialize sends writer.Write(go); // OnDeserialize reads to __netId manually so we can use // lookups in the getter (so it still works if objects // move in and out of range repeatedly) FieldDefinition netIdField = syncVarNetIds[syncVar]; VariableDefinition tmpValue = new VariableDefinition(Weaver.uint32Type); deserialize.Body.Variables.Add(tmpValue); // read id and store in a local variable serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkReaderReadPackedUInt32)); serWorker.Append(serWorker.Create(OpCodes.Stloc, tmpValue)); if (foundMethod != null) { // call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32())) // because we send/receive the netID, not the GameObject/NetworkIdentity serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // this. serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue)); serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar)); if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName) { serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.getSyncVarGameObjectReference)); } else if (syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName) { serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.getSyncVarNetworkIdentityReference)); } serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod)); } // set the netid field serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue)); serWorker.Append(serWorker.Create(OpCodes.Stfld, netIdField)); } else { MethodReference readFunc = Readers.GetReadFunc(syncVar.FieldType); if (readFunc == null) { Weaver.Error($"{syncVar} has unsupported type. Use a supported Mirror type instead"); return; } VariableDefinition tmpValue = new VariableDefinition(syncVar.FieldType); deserialize.Body.Variables.Add(tmpValue); // read value and put it in a local variable serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); serWorker.Append(serWorker.Create(OpCodes.Call, readFunc)); serWorker.Append(serWorker.Create(OpCodes.Stloc, tmpValue)); if (foundMethod != null) { // call hook serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue)); serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod)); } // set the property serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue)); serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar)); } }
static MethodDefinition GenerateArrayReadFunc(TypeReference variable, int recursionCount) { if (!variable.IsArrayType()) { Weaver.Error($"{variable} is an unsupported type. Jagged and multidimensional arrays are not supported"); return(null); } TypeReference elementType = variable.GetElementType(); MethodReference elementReadFunc = GetReadFunc(elementType, recursionCount + 1); if (elementReadFunc == null) { return(null); } string functionName = "_ReadArray" + variable.GetElementType().Name + "_"; if (variable.DeclaringType != null) { functionName += variable.DeclaringType.Name; } else { functionName += "None"; } // create new reader for this type MethodDefinition readerFunc = new MethodDefinition(functionName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, variable); readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType))); readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type)); readerFunc.Body.Variables.Add(new VariableDefinition(variable)); readerFunc.Body.Variables.Add(new VariableDefinition(Weaver.int32Type)); readerFunc.Body.InitLocals = true; ILProcessor worker = readerFunc.Body.GetILProcessor(); // int length = reader.ReadPackedInt32(); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, GetReadFunc(Weaver.int32Type))); worker.Append(worker.Create(OpCodes.Stloc_0)); // if (length < 0) { // return null // } worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Ldc_I4_0)); Instruction labelEmptyArray = worker.Create(OpCodes.Nop); worker.Append(worker.Create(OpCodes.Bge, labelEmptyArray)); // return null worker.Append(worker.Create(OpCodes.Ldnull)); worker.Append(worker.Create(OpCodes.Ret)); worker.Append(labelEmptyArray); // T value = new T[length]; worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Newarr, variable.GetElementType())); worker.Append(worker.Create(OpCodes.Stloc_1)); // for (int i=0; i< length ; i++) { worker.Append(worker.Create(OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Stloc_2)); Instruction labelHead = worker.Create(OpCodes.Nop); worker.Append(worker.Create(OpCodes.Br, labelHead)); // loop body Instruction labelBody = worker.Create(OpCodes.Nop); worker.Append(labelBody); // value[i] = reader.ReadT(); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldelema, variable.GetElementType())); worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Call, elementReadFunc)); worker.Append(worker.Create(OpCodes.Stobj, variable.GetElementType())); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldc_I4_1)); worker.Append(worker.Create(OpCodes.Add)); worker.Append(worker.Create(OpCodes.Stloc_2)); // loop while check worker.Append(labelHead); worker.Append(worker.Create(OpCodes.Ldloc_2)); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Blt, labelBody)); // return value; worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ret)); return(readerFunc); }
public static void Weave(ModuleDefinition module, Dictionary <ushort, MethodDefinition> methods, TypeDefinition protocol) { if (module == null || methods.Count == 0 || protocol == null) { return; } FieldReference connectionField = module.ImportReference(ResolveHelper.ResolveField(protocol.BaseType, "m_Connection")); { //public void Register(); MethodDefinition registerMethod = ResolveHelper.ResolveMethod(protocol, "Register"); registerMethod.Body.Variables.Clear(); registerMethod.Body.Instructions.Clear(); ILProcessor registerProcessor = registerMethod.Body.GetILProcessor(); registerProcessor.Append(registerProcessor.Create(OpCodes.Nop)); foreach (ushort key in methods.Keys) { MethodDefinition method = methods[key]; if (!CheckHelper.CheckMethodFirstParams(WeaverProgram.Server, method)) { continue; } MethodDefinition protoMethodImpl = MethodFactory.CreateMethod(module, protocol, "OnProtocol_" + key, MethodAttributes.Private | MethodAttributes.HideBySig, true); protoMethodImpl.Parameters.Add(new ParameterDefinition("msg", ParameterAttributes.None, module.ImportReference(WeaverProgram.ChannelMessageType))); protoMethodImpl.Body.Variables.Add(new VariableDefinition(module.ImportReference(WeaverProgram.ByteBufferType))); { ILProcessor processor = protoMethodImpl.Body.GetILProcessor(); processor.Append(processor.Create(OpCodes.Nop)); processor.Append(processor.Create(OpCodes.Ldarg_1)); processor.Append(processor.Create(OpCodes.Ldfld, module.ImportReference(WeaverProgram.ChannelMessageBufferField))); processor.Append(processor.Create(OpCodes.Stloc_0)); List <int> indexs = new List <int>(); Collection <ParameterDefinition> parms = method.Parameters; for (int i = 0; i < parms.Count; ++i) { if (i > 0) { ParameterDefinition parm = parms[i]; TypeDefinition parmType = parm.ParameterType.Resolve(); protoMethodImpl.Body.Variables.Add(new VariableDefinition(module.ImportReference(parm.ParameterType))); int index = protoMethodImpl.Body.Variables.Count - 1; indexs.Add(index); if (parm.ParameterType.FullName == typeof(byte[]).FullName) { processor.Append(processor.Create(OpCodes.Ldloc_0)); processor.Append(processor.Create(OpCodes.Call, module.ImportReference(WeaverProgram.ByteUtilsReadMethod))); processor.Append(processor.Create(OpCodes.Stloc, index)); continue; } if (parm.ParameterType.FullName == typeof(ByteBuffer).FullName) { processor.Append(processor.Create(OpCodes.Ldloc_0)); processor.Append(processor.Create(OpCodes.Call, module.ImportReference(WeaverProgram.ByteBufferUtilsReadMethod))); processor.Append(processor.Create(OpCodes.Stloc, index)); continue; } if (parm.ParameterType.IsArray) { ArrayReadFactory.CreateMethodVariableReadInstruction(module, protoMethodImpl, processor, parmType); continue; } if (BaseTypeFactory.IsBaseType(parmType)) { processor.Append(processor.Create(OpCodes.Ldloc_0)); processor.Append(BaseTypeFactory.CreateReadInstruction(module, processor, parmType)); processor.Append(processor.Create(OpCodes.Stloc, index)); continue; } if (parmType.IsValueType) { MethodDefinition deserialize = StructMethodFactory.CreateDeserialize(module, parmType); processor.Append(processor.Create(OpCodes.Ldloca, index)); processor.Append(processor.Create(OpCodes.Initobj, module.ImportReference(parmType))); processor.Append(processor.Create(OpCodes.Ldloca, index)); processor.Append(processor.Create(OpCodes.Ldloc_0)); processor.Append(processor.Create(OpCodes.Call, module.ImportReference(deserialize))); } } } processor.Append(processor.Create(OpCodes.Ldarg_0)); processor.Append(processor.Create(OpCodes.Ldfld, connectionField)); for (int i = 0; i < indexs.Count; ++i) { processor.Append(processor.Create(OpCodes.Ldloc, indexs[i])); } processor.Append(processor.Create(OpCodes.Call, method)); processor.Append(processor.Create(OpCodes.Nop)); processor.Append(processor.Create(OpCodes.Ret)); } registerProcessor.Append(registerProcessor.Create(OpCodes.Ldarg_0)); registerProcessor.Append(registerProcessor.Create(OpCodes.Ldfld, connectionField)); registerProcessor.Append(registerProcessor.Create(OpCodes.Ldc_I4, key)); registerProcessor.Append(registerProcessor.Create(OpCodes.Ldarg_0)); registerProcessor.Append(registerProcessor.Create(OpCodes.Ldftn, protoMethodImpl)); registerProcessor.Append(registerProcessor.Create(OpCodes.Newobj, module.ImportReference(typeof(ChannelMessageDelegate).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })))); registerProcessor.Append(registerProcessor.Create(OpCodes.Callvirt, module.ImportReference(WeaverProgram.IConnectionRegisterHandlerMethod))); } registerProcessor.Append(registerProcessor.Create(OpCodes.Ret)); } { //public void Unregister(); MethodDefinition unregisterMethod = ResolveHelper.ResolveMethod(protocol, "UnRegister"); unregisterMethod.Body.Variables.Clear(); unregisterMethod.Body.Instructions.Clear(); ILProcessor unregisterProcessor = unregisterMethod.Body.GetILProcessor(); unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Nop)); foreach (short key in methods.Keys) { unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Ldarg_0)); unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Ldfld, connectionField)); unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Ldc_I4, key)); unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Callvirt, module.ImportReference(WeaverProgram.IConnectionUnregisterHandlerMethod))); } unregisterProcessor.Append(unregisterProcessor.Create(OpCodes.Ret)); } }