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;
            }
        }
Пример #2
0
        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));
        }
Пример #3
0
        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);
        }
Пример #4
0
 public InstructionComposer Append(InstructionComposer composer2)
 {
     Instructions.AddRange(composer2.Instructions);
     return(this);
 }
Пример #5
0
        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);
        }
Пример #6
0
 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[]) }
     });
 }
Пример #7
0
        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[]) }
            });
        }
Пример #8
0
        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);
            }
        }
Пример #9
0
        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);
            }
        }
Пример #12
0
        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);
            }
        }