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 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 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 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 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); } }