123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- using System;
- using Mono.CecilX;
- using Mono.CecilX.Cil;
- namespace Mirror.Weaver
- {
- public static class PropertySiteProcessor
- {
- public static void Process(ModuleDefinition moduleDef)
- {
- DateTime startTime = DateTime.Now;
- //Search through the types
- foreach (TypeDefinition td in moduleDef.Types)
- {
- if (td.IsClass)
- {
- ProcessSiteClass(td);
- }
- }
- Console.WriteLine(" ProcessSitesModule " + moduleDef.Name + " elapsed time:" + (DateTime.Now - startTime));
- }
- static void ProcessSiteClass(TypeDefinition td)
- {
- //Console.WriteLine(" ProcessSiteClass " + td);
- foreach (MethodDefinition md in td.Methods)
- {
- ProcessSiteMethod(md);
- }
- foreach (TypeDefinition nested in td.NestedTypes)
- {
- ProcessSiteClass(nested);
- }
- }
- static void ProcessSiteMethod(MethodDefinition md)
- {
- // process all references to replaced members with properties
- //Weaver.DLog(td, " ProcessSiteMethod " + md);
- if (md.Name == ".cctor" ||
- md.Name == NetworkBehaviourProcessor.ProcessedFunctionName ||
- md.Name.StartsWith(Weaver.InvokeRpcPrefix))
- return;
- if (md.IsAbstract)
- {
- return;
- }
- if (md.Body != null && md.Body.Instructions != null)
- {
- for (int iCount = 0; iCount < md.Body.Instructions.Count;)
- {
- Instruction instr = md.Body.Instructions[iCount];
- iCount += ProcessInstruction(md, instr, iCount);
- }
- }
- }
- // replaces syncvar write access with the NetworkXYZ.get property calls
- static void ProcessInstructionSetterField(MethodDefinition md, Instruction i, FieldDefinition opField)
- {
- // don't replace property call sites in constructors
- if (md.Name == ".ctor")
- return;
- // does it set a field that we replaced?
- if (Weaver.WeaveLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement))
- {
- //replace with property
- //DLog(td, " replacing " + md.Name + ":" + i);
- i.OpCode = OpCodes.Call;
- i.Operand = replacement;
- //DLog(td, " replaced " + md.Name + ":" + i);
- }
- }
- // replaces syncvar read access with the NetworkXYZ.get property calls
- static void ProcessInstructionGetterField(MethodDefinition md, Instruction i, FieldDefinition opField)
- {
- // don't replace property call sites in constructors
- if (md.Name == ".ctor")
- return;
- // does it set a field that we replaced?
- if (Weaver.WeaveLists.replacementGetterProperties.TryGetValue(opField, out MethodDefinition replacement))
- {
- //replace with property
- //DLog(td, " replacing " + md.Name + ":" + i);
- i.OpCode = OpCodes.Call;
- i.Operand = replacement;
- //DLog(td, " replaced " + md.Name + ":" + i);
- }
- }
- static int ProcessInstruction(MethodDefinition md, Instruction instr, int iCount)
- {
- if (instr.OpCode == OpCodes.Stfld && instr.Operand is FieldDefinition opFieldst)
- {
- // this instruction sets the value of a field. cache the field reference.
- ProcessInstructionSetterField(md, instr, opFieldst);
- }
- if (instr.OpCode == OpCodes.Ldfld && instr.Operand is FieldDefinition opFieldld)
- {
- // this instruction gets the value of a field. cache the field reference.
- ProcessInstructionGetterField(md, instr, opFieldld);
- }
- if (instr.OpCode == OpCodes.Ldflda && instr.Operand is FieldDefinition opFieldlda)
- {
- // loading a field by reference, watch out for initobj instruction
- // see https://github.com/vis2k/Mirror/issues/696
- return ProcessInstructionLoadAddress(md, instr, opFieldlda, iCount);
- }
- return 1;
- }
- static int ProcessInstructionLoadAddress(MethodDefinition md, Instruction instr, FieldDefinition opField, int iCount)
- {
- // don't replace property call sites in constructors
- if (md.Name == ".ctor")
- return 1;
- // does it set a field that we replaced?
- if (Weaver.WeaveLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement))
- {
- // we have a replacement for this property
- // is the next instruction a initobj?
- Instruction nextInstr = md.Body.Instructions[iCount + 1];
- if (nextInstr.OpCode == OpCodes.Initobj)
- {
- // we need to replace this code with:
- // var tmp = new MyStruct();
- // this.set_Networkxxxx(tmp);
- ILProcessor worker = md.Body.GetILProcessor();
- VariableDefinition tmpVariable = new VariableDefinition(opField.FieldType);
- md.Body.Variables.Add(tmpVariable);
- worker.InsertBefore(instr, worker.Create(OpCodes.Ldloca, tmpVariable));
- worker.InsertBefore(instr, worker.Create(OpCodes.Initobj, opField.FieldType));
- worker.InsertBefore(instr, worker.Create(OpCodes.Ldloc, tmpVariable));
- worker.InsertBefore(instr, worker.Create(OpCodes.Call, replacement));
- worker.Remove(instr);
- worker.Remove(nextInstr);
- return 4;
- }
- }
- return 1;
- }
- }
- }
|