private static void AddInstanceMethodInitialiser(ModuleDefinition md, TypeDefinition type, PropertyDefinition instanceMethods, MethodDefinition method) { return; var composer = new InstructionComposer(md) .LoadArg_0() .StaticCall(new Method { ParentType = typeof(CodeChangeHandler), MethodName = nameof(CodeChangeHandler.GetInitialInstanceMethods), ParameterSignature = new[] { typeof(IInstanceClass) } }) .NoOperation(); var ilProcessor = method.Body.GetILProcessor(); var baseConstructorCall = method.Body.Instructions.Where(x => x.OpCode == OpCodes.Call) .FirstOrDefault(x => { if (x.Operand is MethodReference methodReference) { return(methodReference.Name == ".ctor"); } return(false); }); var last = baseConstructorCall; foreach (var instruction in composer.Instructions) { ilProcessor.InsertAfter(last, instruction); last = instruction; } }
private static PropertyDefinition CreateInstanceMethodsProperty(ModuleDefinition md, TypeDefinition type, out MethodDefinition instanceMethodGetters) { var instaceMethodType = md.ImportReference(typeof(Dictionary <string, Delegate>)); var field = type.CreateField(md, "instanceMethods", instaceMethodType); var fieldReference = field.GetReference(); var returnComposer = new InstructionComposer(md) .Load_1() .Return(); var getFieldComposer = new InstructionComposer(md) .LoadArg_0() .Load(fieldReference) .Store_1() .MoveTo(returnComposer.Instructions.First()); var initializeField = new InstructionComposer(md) .NoOperation() .LoadArg_0() .LoadArg_0() .StaticCall(new Method { ParentType = typeof(Runtime), MethodName = nameof(Runtime.GetInitialInstanceMethods), ParameterSignature = new[] { typeof(IInstanceClass) } }) .Store(fieldReference) .NoOperation(); var getterComposer = new InstructionComposer(md); getterComposer.LoadArg_0() .Load(fieldReference) .LoadNull() .CompareEqual() .Store_0() .Load_0() .MoveToWhenFalse(getFieldComposer.Instructions.First()) .Append(initializeField) .Append(getFieldComposer) .Append(returnComposer); instanceMethodGetters = type.CreateGetter(md, "InstanceMethods", instaceMethodType, getterComposer.Instructions, vir: true); var boolVariable = new VariableDefinition(md.ImportReference(typeof(bool))); instanceMethodGetters.Body.Variables.Add(boolVariable); var delegateVariable = new VariableDefinition(md.ImportReference(typeof(Delegate))); instanceMethodGetters.Body.Variables.Add(delegateVariable); return(type.CreateProperty("InstanceMethods", instaceMethodType, instanceMethodGetters, null)); }
private static MethodDefinition CreateBaseCallMethod(ModuleDefinition md, MethodReference baseMethod) { var methodKey = Core.Helper.GetMethodKey(baseMethod.Name, baseMethod.Parameters.Select(x => x.ParameterType.FullName).ToArray()); var methodName = "HotReloadingBase_" + baseMethod.Name; var hotReloadingBaseMethod = new MethodDefinition(methodName, MethodAttributes.Private | MethodAttributes.HideBySig, md.ImportReference(typeof(void))); foreach (var parameter in baseMethod.GenericParameters) { hotReloadingBaseMethod.GenericParameters.Add(parameter); } hotReloadingBaseMethod.ReturnType = baseMethod.ReturnType; foreach (var parameter in baseMethod.Parameters) { TypeReference parameterType = parameter.ParameterType; hotReloadingBaseMethod.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, parameterType) { IsIn = parameter.IsIn, IsOut = parameter.IsOut, IsOptional = parameter.IsOptional }); } var retVar = new VariableDefinition(md.ImportReference(typeof(object))); var baseCallComposer = new InstructionComposer(md) .LoadArg_0(); foreach (var parameter in hotReloadingBaseMethod.Parameters) { baseCallComposer.LoadArg(parameter); } baseCallComposer.BaseCall(baseMethod); if (hotReloadingBaseMethod.ReturnType.FullName != "System.Void") { var returnVariable = new VariableDefinition(hotReloadingBaseMethod.ReturnType); hotReloadingBaseMethod.Body.Variables.Add(returnVariable); baseCallComposer.Store(returnVariable); baseCallComposer.Load(returnVariable); } baseCallComposer.Return(); foreach (var instruction in baseCallComposer.Instructions) { hotReloadingBaseMethod.Body.GetILProcessor().Append(instruction); } return(hotReloadingBaseMethod); }
public InstructionComposer Append(InstructionComposer composer2) { Instructions.AddRange(composer2.Instructions); return(this); }
private static MethodDefinition CreateGetInstanceMethod(ModuleDefinition md, MethodReference instanceMethodGetter, TypeDefinition type, bool hasImplementedIInstanceClass) { var getInstanceMethod = new MethodDefinition(Constants.GetInstanceMethodName, MethodAttributes.Family, md.ImportReference(typeof(Delegate))); var methodName = new ParameterDefinition("methodName", ParameterAttributes.None, md.ImportReference(typeof(string))); getInstanceMethod.Parameters.Add(methodName); var boolVariable = new VariableDefinition(md.ImportReference(typeof(bool))); getInstanceMethod.Body.Variables.Add(boolVariable); var delegateVariable = new VariableDefinition(md.ImportReference(typeof(Delegate))); getInstanceMethod.Body.Variables.Add(delegateVariable); var composer1 = new InstructionComposer(md) .Load(delegateVariable) .Return(); var composer2 = new InstructionComposer(md).LoadNull() .Store(delegateVariable) .MoveTo(composer1.Instructions.First()); var composer = new InstructionComposer(md) .LoadArg_0() .InstanceCall(instanceMethodGetter) .Load(methodName) .InstanceCall(new Method { ParentType = typeof(Dictionary <string, Delegate>), MethodName = "ContainsKey", ParameterSignature = new[] { typeof(Dictionary <string, Delegate>).GetGenericArguments()[0] } }) .Store(boolVariable) .Load(boolVariable) .MoveToWhenFalse(composer2.Instructions.First()) .LoadArg_0() .InstanceCall(instanceMethodGetter) .Load(methodName) .InstanceCall(new Method { ParentType = typeof(Dictionary <string, Delegate>), MethodName = "get_Item", ParameterSignature = new[] { typeof(Dictionary <string, Delegate>).GetGenericArguments()[0] } }) .Store(delegateVariable) .MoveTo(composer1.Instructions.First()) .Append(composer2) .Append(composer1); var ilProcessor = getInstanceMethod.Body.GetILProcessor(); foreach (var instruction in composer.Instructions) { ilProcessor.Append(instruction); } if (!type.IsAbstract & !hasImplementedIInstanceClass) { type.Methods.Add(getInstanceMethod); } return(getInstanceMethod); }
private static void ComposeStaticMethodInstructions(TypeDefinition type, MethodDefinition method, VariableDefinition delegateVariable, VariableDefinition boolVariable, VariableDefinition methodKeyVariable, Instruction firstInstruction, ParameterDefinition[] parameters, InstructionComposer composer) { composer .Load(method.Name) .LoadArray(parameters.Length, typeof(string), parameters.Select(x => x.ParameterType.FullName).ToArray()) .StaticCall(new Method { ParentType = typeof(Core.Helper), MethodName = nameof(Core.Helper.GetMethodKey), ParameterSignature = new[] { typeof(string), typeof(string[]) } }). Store(methodKeyVariable) .Load(type) .StaticCall(new Method { ParentType = typeof(Type), MethodName = nameof(Type.GetTypeFromHandle), ParameterSignature = new[] { typeof(RuntimeTypeHandle) } }) .Load(methodKeyVariable) .StaticCall(new Method { ParentType = typeof(Runtime), MethodName = nameof(Runtime.GetMethodDelegate), ParameterSignature = new[] { typeof(Type), typeof(string) } }) .Store(delegateVariable) .Load(delegateVariable) .IsNotNull() .Store(boolVariable) .Load(boolVariable) .MoveToWhenFalse(firstInstruction) .NoOperation() .Load(delegateVariable) .LoadArray(parameters) .InstanceCall(new Method { ParentType = typeof(Delegate), MethodName = nameof(Delegate.DynamicInvoke), ParameterSignature = new[] { typeof(object[]) } }); }
private void ComposeInstanceMethodInstructions(TypeDefinition type, MethodDefinition method, VariableDefinition delegateVariable, VariableDefinition boolVariable, VariableDefinition methodKeyVariable, Instruction firstInstruction, ParameterDefinition[] parameters, InstructionComposer composer, MethodReference getInstanceMethod, ModuleDefinition md) { if (method.IsConstructor) { var arrayListConstructor = typeof(ArrayList).GetConstructor(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, null, new Type[] { }, null); var arrayListConstructorReference = md.ImportReference(arrayListConstructor); composer .LoadArg_0() .NewObject(arrayListConstructorReference) .Store(ctorParameters); foreach (var parameter in method.Parameters) { composer.LoadArg_0() .Load(ctorParameters) .LoadArg(parameter); if (parameter.ParameterType.IsValueType) { composer.Box(md.ImportReference(parameter.ParameterType)); } composer .InstanceCall(new Method { ParentType = typeof(ArrayList), MethodName = "Add", ParameterSignature = new Type[] { typeof(Object) } }) .Pop(); } } composer .Load(method.Name) .LoadArray(parameters.Length, typeof(string), parameters.Select(x => x.ParameterType.FullName).ToArray()) .StaticCall(new Method { ParentType = typeof(Core.Helper), MethodName = nameof(Core.Helper.GetMethodKey), ParameterSignature = new[] { typeof(string), typeof(string[]) } }). Store(methodKeyVariable) .LoadArg_0() .Load(methodKeyVariable) .InstanceCall(getInstanceMethod) .Store(delegateVariable) .Load(delegateVariable) .IsNotNull() .Store(boolVariable) .Load(boolVariable) .MoveToWhenFalse(firstInstruction) .NoOperation() .Load(delegateVariable) .LoadArray(parameters, true) .InstanceCall(new Method { ParentType = typeof(Delegate), MethodName = nameof(Delegate.DynamicInvoke), ParameterSignature = new[] { typeof(object[]) } }); }
private void WrapMethod(ModuleDefinition md, TypeDefinition type, MethodDefinition method, MethodReference getInstanceMethod) { Logger.LogMessage("\tWeaving Method " + method.Name); var methodKeyVariable = new VariableDefinition(md.ImportReference(typeof(string))); method.Body.Variables.Add(methodKeyVariable); var delegateVariable = new VariableDefinition(md.ImportReference(typeof(Delegate))); method.Body.Variables.Add(delegateVariable); var boolVariable = new VariableDefinition(md.ImportReference(typeof(bool))); method.Body.Variables.Add(boolVariable); var instructions = method.Body.Instructions; var ilprocessor = method.Body.GetILProcessor(); Instruction loadInstructionForReturn = null; if (method.ReturnType.FullName != "System.Void" && instructions.Count > 1) { var secondLastInstruction = instructions.ElementAt(instructions.Count - 2); if (secondLastInstruction.IsLoadInstruction()) { loadInstructionForReturn = secondLastInstruction; } } var retInstruction = instructions.Last(); List <Instruction> constructorInitialCode = new List <Instruction>(); if (method.IsConstructor) { foreach (var i in method.Body.Instructions) { if (i.OpCode != OpCodes.Call) { constructorInitialCode.Add(i); } else { constructorInitialCode.Add(i); break; } } } var oldInstruction = method.Body.Instructions.Where(x => x != retInstruction && x != loadInstructionForReturn && !constructorInitialCode.Contains(x)).ToList(); var lastInstruction = retInstruction; method.Body.Instructions.Clear(); if (loadInstructionForReturn != null) { method.Body.Instructions.Add(loadInstructionForReturn); lastInstruction = loadInstructionForReturn; } method.Body.Instructions.Add(retInstruction); foreach (var instruction in oldInstruction) { ilprocessor.InsertBefore(lastInstruction, instruction); } method.Body.InitLocals = true; var firstInstruction = method.Body.Instructions.First(); var parameters = method.Parameters.ToArray(); var composer = new InstructionComposer(md); if (method.IsStatic) { ComposeStaticMethodInstructions(type, method, delegateVariable, boolVariable, methodKeyVariable, firstInstruction, parameters, composer); } else { ComposeInstanceMethodInstructions(type, method, delegateVariable, boolVariable, methodKeyVariable, firstInstruction, parameters, composer, getInstanceMethod, md); } if (method.ReturnType.FullName == "System.Void") { composer.Pop(); } else if (method.ReturnType.IsValueType) { composer.Unbox_Any(method.ReturnType); } else { composer.Cast(method.ReturnType); } if (loadInstructionForReturn != null) { Instruction storeInstructionForReturn = loadInstructionForReturn.GetStoreInstruction(); composer.Append(storeInstructionForReturn); } composer.MoveTo(lastInstruction); foreach (var instruction in composer.Instructions) { ilprocessor.InsertBefore(firstInstruction, instruction); } foreach (var instruction in constructorInitialCode) { ilprocessor.InsertBefore(composer.Instructions[0], instruction); } }
private void AddOverrideMethod(TypeDefinition type, ModuleDefinition md, MethodReference getInstanceMethod, List <MethodDefinition> existingMethods) { if (type.BaseType == null) { return; } var overridableMethods = GetOverridableMethods(type, md); var baseMethodCalls = new List <MethodReference>(); foreach (var overridableMethod in overridableMethods) { if (existingMethods.Any(x => x.FullName == overridableMethod.Method.FullName)) { continue; } var baseMethod = overridableMethod.BaseMethodReference; //Ignore method with ref parameter if (baseMethod.Parameters.Any(x => x.ParameterType is ByReferenceType)) { continue; } baseMethodCalls.Add(baseMethod); if (!type.Methods.Any(x => x.IsEqual(overridableMethod.Method))) { var method = overridableMethod.Method; var returnType = method.ReturnType; var composer = new InstructionComposer(md); composer.LoadArg_0(); foreach (var parameter in method.Parameters) { composer.LoadArg(parameter); } composer.BaseCall(baseMethod); if (overridableMethod.Method.ReturnType.FullName != "System.Void") { var returnVariable = new VariableDefinition(returnType); method.Body.Variables.Add(returnVariable); composer.Store(returnVariable); composer.Load(returnVariable); } composer.Return(); foreach (var instruction in composer.Instructions) { method.Body.GetILProcessor().Append(instruction); } WrapMethod(md, type, method, getInstanceMethod); method.DeclaringType = type; type.Methods.Add(method); } } foreach (var baseMethod in baseMethodCalls) { //Ignore optional if (baseMethod.Parameters.Any(x => x.IsOptional)) { continue; } var hotReloadingBaseMethod = CreateBaseCallMethod(md, baseMethod); type.Methods.Add(hotReloadingBaseMethod); } }
private static void ComposeInstanceMethodInstructions(TypeDefinition type, MethodDefinition method, VariableDefinition delegateVariable, VariableDefinition boolVariable, Instruction firstInstruction, ParameterDefinition[] parameters, InstructionComposer composer, MethodDefinition getInstanceMethod) { composer.LoadArg_0() .LoadStr(method.Name) .InstanceCall(getInstanceMethod) .Store(delegateVariable) .Load(delegateVariable) .IsNotNull() .Store(boolVariable) .Load(boolVariable) .MoveToWhenFalse(firstInstruction) .NoOperation() .Load(delegateVariable) .LoadArray(parameters, true) .InstanceCall(new Method { ParentType = typeof(Delegate), MethodName = nameof(Delegate.DynamicInvoke), ParameterSignature = new[] { typeof(object[]) } }); }
private static void WrapMethod(ModuleDefinition md, TypeDefinition type, MethodDefinition method, MethodDefinition getInstanceMethod) { var delegateVariable = new VariableDefinition(md.ImportReference(typeof(Delegate))); method.Body.Variables.Add(delegateVariable); var boolVariable = new VariableDefinition(md.ImportReference(typeof(bool))); method.Body.Variables.Add(boolVariable); var instructions = method.Body.Instructions; var ilprocessor = method.Body.GetILProcessor(); Instruction loadInstructionForReturn = null; if (method.ReturnType.FullName != "System.Void" && instructions.Count > 1) { var secondLastInstruction = instructions.ElementAt(instructions.Count - 2); if (IsLoadInstruction(secondLastInstruction)) { loadInstructionForReturn = secondLastInstruction; } } var retInstruction = instructions.Last(); var oldInstruction = method.Body.Instructions.Where(x => x != retInstruction && x != loadInstructionForReturn).ToList(); var lastInstruction = retInstruction; method.Body.Instructions.Clear(); if (loadInstructionForReturn != null) { method.Body.Instructions.Add(loadInstructionForReturn); lastInstruction = loadInstructionForReturn; } method.Body.Instructions.Add(retInstruction); foreach (var instruction in oldInstruction) { ilprocessor.InsertBefore(lastInstruction, instruction); } method.Body.InitLocals = true; var firstInstruction = method.Body.Instructions.First(); var parameters = method.Parameters.ToArray(); var composer = new InstructionComposer(md); if (method.IsStatic) { ComposeStaticMethodInstructions(type, method, delegateVariable, boolVariable, firstInstruction, parameters, composer); } else { ComposeInstanceMethodInstructions(type, method, delegateVariable, boolVariable, firstInstruction, parameters, composer, getInstanceMethod); } if (method.ReturnType.FullName == "System.Void") { composer.Pop(); } else if (method.ReturnType.IsValueType) { composer.Unbox_Any(method.ReturnType); } else { composer.Cast(method.ReturnType); } if (loadInstructionForReturn != null) { Instruction storeInstructionForReturn = GetStoreInstruction(loadInstructionForReturn); composer.Append(storeInstructionForReturn); } composer.MoveTo(lastInstruction); foreach (var instruction in composer.Instructions) { ilprocessor.InsertBefore(firstInstruction, instruction); } }
private void AddOverrideMethod(TypeDefinition type, ModuleDefinition md, MethodReference getInstanceMethod) { if (type.BaseType == null) { return; } var overridableMethods = GetOverridableMethods(type, md); var baseMethodCalls = new List <MethodReference>(); foreach (var overridableMethod in overridableMethods) { MethodReference baseMethod = GetBaseMethod(overridableMethod); //Ignore method with ref parameter if (baseMethod.Parameters.Any(x => x.ParameterType is ByReferenceType)) { continue; } baseMethodCalls.Add(baseMethod); if (!type.Methods.Any(x => x.IsEqual(overridableMethod.Method))) { var method = overridableMethod.Method; var returnType = method.ReturnType; var composer = new InstructionComposer(md); composer.LoadArg_0(); foreach (var parameter in method.Parameters) { composer.LoadArg(parameter); } composer.BaseCall(baseMethod); if (overridableMethod.Method.ReturnType.FullName != "System.Void") { var returnVariable = new VariableDefinition(returnType); method.Body.Variables.Add(returnVariable); composer.Store(returnVariable); composer.Load(returnVariable); } composer.Return(); foreach (var instruction in composer.Instructions) { method.Body.GetILProcessor().Append(instruction); } WrapMethod(md, type, method, getInstanceMethod); method.DeclaringType = type; type.Methods.Add(method); } } foreach (var baseMethod in baseMethodCalls) { //Ignore optional if (baseMethod.Parameters.Any(x => x.IsOptional)) { continue; } var methodKey = Core.Helper.GetMethodKey(baseMethod.Name, baseMethod.Parameters.Select(x => x.ParameterType.FullName).ToArray()); var methodName = "HotReloadingBase_" + baseMethod.Name; var hotReloadingBaseMethod = new MethodDefinition(methodName, MethodAttributes.Private | MethodAttributes.HideBySig, md.ImportReference(typeof(void))); foreach (var parameter in baseMethod.GenericParameters) { hotReloadingBaseMethod.GenericParameters.Add(parameter); } hotReloadingBaseMethod.ReturnType = baseMethod.ReturnType; foreach (var parameter in baseMethod.Parameters) { TypeReference parameterType = parameter.ParameterType; hotReloadingBaseMethod.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, parameterType) { IsIn = parameter.IsIn, IsOut = parameter.IsOut, IsOptional = parameter.IsOptional }); } var retVar = new VariableDefinition(md.ImportReference(typeof(object))); var baseCallComposer = new InstructionComposer(md) .LoadArg_0(); foreach (var parameter in hotReloadingBaseMethod.Parameters) { baseCallComposer.LoadArg(parameter); } baseCallComposer.BaseCall(baseMethod); if (hotReloadingBaseMethod.ReturnType.FullName != "System.Void") { var returnVariable = new VariableDefinition(hotReloadingBaseMethod.ReturnType); hotReloadingBaseMethod.Body.Variables.Add(returnVariable); baseCallComposer.Store(returnVariable); baseCallComposer.Load(returnVariable); } baseCallComposer.Return(); foreach (var instruction in baseCallComposer.Instructions) { hotReloadingBaseMethod.Body.GetILProcessor().Append(instruction); } type.Methods.Add(hotReloadingBaseMethod); } }