Ejemplo n.º 1
0
 void CreateCustomAttribute(string attrName, out TypeReference attrType,
                            Mono.Collections.Generic.Collection <TypeDefinition> types)
 {
     attrName = "java.attr." + attrName;
     if (typeMap.TryGetValue(attrName, out attrType))
     {
         typeMap.Remove(attrName);
     }
     else
     {
         var attrTypeDef = CreateCustomAttribute(attrName);
         types.Add(attrTypeDef);
         attrType = attrTypeDef;
     }
 }
Ejemplo n.º 2
0
    static Instruction findNextRet(Mono.Collections.Generic.Collection <Instruction> instructions, Instruction pos)
    {
        bool posFound = false;

        for (int i = 0; i < instructions.Count; i++)
        {
            if (posFound && instructions[i].OpCode == OpCodes.Ret)
            {
                return(instructions[i]);
            }
            else if (instructions[i] == pos)
            {
                posFound = true;
            }
        }
        return(null);
    }
Ejemplo n.º 3
0
    public static string[] GetGenericName(Mono.Collections.Generic.Collection <TypeReference> types, int offset, int count, bool bFull)
    {
        string[] results = new string[count];

        for (int i = 0; i < count; i++)
        {
            int pos = i + offset;

            if (types[pos].IsGenericInstance)
            {
                results[i] = GetGenericName(types[pos], bFull);
            }
            else
            {
                results[i] = GetTypeName(types[pos]);
            }
        }

        return(results);
    }
Ejemplo n.º 4
0
        public MethodInfo(AssemblyInfo assembly, MethodDefinition methodDef, SourceFile source)
        {
            this.Assembly  = assembly;
            this.methodDef = methodDef;
            this.source    = source;

            Mono.Collections.Generic.Collection <SequencePoint> sps = DebugInformation.SequencePoints;
            if (sps == null || sps.Count < 1)
            {
                return;
            }

            SequencePoint start = sps[0];
            SequencePoint end   = sps[0];

            foreach (SequencePoint sp in sps)
            {
                if (sp.StartLine < start.StartLine)
                {
                    start = sp;
                }
                else if (sp.StartLine == start.StartLine && sp.StartColumn < start.StartColumn)
                {
                    start = sp;
                }

                if (sp.EndLine > end.EndLine)
                {
                    end = sp;
                }
                else if (sp.EndLine == end.EndLine && sp.EndColumn > end.EndColumn)
                {
                    end = sp;
                }
            }

            StartLocation = new SourceLocation(this, start);
            EndLocation   = new SourceLocation(this, end);
        }
Ejemplo n.º 5
0
    /// <summary>
    /// Update the given method IL to include the interception logic
    /// </summary>
    /// <param name="method">Method</param>
    /// <param name="typeImp">Static Type to add logic for caching method info to</param>
    /// <param name="cctorIL">Static IL Processor</param>
    /// <param name="attrs">Custom Attribute for the given method</param>
    /// <param name="aspects">Collection of aspect discovered for the given method</param>
    /// <param name="type">Original Method Type to use for inteception logic</param>
    private void UpdateMethodIL(MethodDefinition method, TypeDefinition typeImp, ILProcessor cctorIL, IEnumerable <CustomAttribute> attrs, Dictionary <string, FieldDefinition> aspects, TypeDefinition type)
    {
        //Check if aspect ignore
        var ignoreAspect = method.CustomAttributes.Any(x => x.AttributeType.FullName == typeof(AspectIgnoreAttribute).FullName);

        var methAttrs = attrs;

        // No Aspect required
        if (ignoreAspect || !methAttrs.Any())
        {
            return;
        }

        var origMethod = CloneMethod(method, type);

        type.Methods.Add(origMethod);

        var declaringType   = method.DeclaringType;
        var returnType      = method.ReturnType;
        var isGeneric       = declaringType.HasGenericParameters;
        var isStatic        = method.IsStatic;
        var parameterOffset = isStatic ? 0 : 1;
        var isTask          = returnType.FullName.StartsWith("Task`1") || returnType.FullName == typeof(Task).FullName;

        //Define method info
        var methodField = new FieldDefinition("_meth_" + (++Counter), FieldAttributes.Public | FieldAttributes.Static, ModuleDefinition.Import(typeof(System.Reflection.MethodBase)));

        cctorIL.Emit(OpCodes.Ldtoken, method);
        if (isGeneric)
        {
            cctorIL.Emit(OpCodes.Ldtoken, declaringType);
        }
        cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(System.Reflection.MethodBase).GetMethod("GetMethodFromHandle",
                                                                                                          isGeneric ? new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) } : new Type[] { typeof(RuntimeMethodHandle) }
                                                                                                          )));
        cctorIL.Emit(OpCodes.Stsfld, methodField);

        typeImp.Fields.Add(methodField);

        var paramType = ModuleDefinition.Import(typeof(AspectMethodParameterInfo));
        var paramCtor = ModuleDefinition.Import(paramType.Resolve().GetConstructors().First());

        //Define method parameters
        var paramsLocal = new VariableDefinition(ModuleDefinition.Import(typeof(List <AspectMethodParameterInfo>)));
        var paramsField = new FieldDefinition("_meth_param" + (++Counter), FieldAttributes.Public | FieldAttributes.Static, ModuleDefinition.Import(typeof(ReadOnlyCollection <AspectMethodParameterInfo>)));
        var paramAdd    = ModuleDefinition.Import(typeof(List <AspectMethodParameterInfo>).GetMethod("Add", new[] { typeof(AspectMethodParameterInfo) }));

        var methodAttributesField = new FieldDefinition("_meth_attr_" + (++Counter), FieldAttributes.Public | FieldAttributes.Static, ModuleDefinition.Import(typeof(IList <Attribute>)));

        cctorIL.Emit(OpCodes.Ldtoken, method);
        if (isGeneric)
        {
            cctorIL.Emit(OpCodes.Ldtoken, declaringType);
        }
        cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(System.Reflection.MethodBase).GetMethod("GetMethodFromHandle",
                                                                                                          isGeneric ? new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) } : new Type[] { typeof(RuntimeMethodHandle) }
                                                                                                          )));
        cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("GetAttributes")));
        cctorIL.Emit(OpCodes.Stsfld, methodAttributesField);

        typeImp.Fields.Add(methodAttributesField);
        typeImp.Fields.Add(paramsField);

        // Add params local for method parameter information
        cctorIL.Body.Variables.Add(paramsLocal);

        cctorIL.Emit(OpCodes.Newobj, ModuleDefinition.Import(typeof(List <AspectMethodParameterInfo>).GetConstructor(Type.EmptyTypes)));
        cctorIL.Emit(OpCodes.Stloc, paramsLocal);

        foreach (var param in method.Parameters)
        {
            var paramName  = param.Name;
            var paramLocal = new VariableDefinition(paramType);
            cctorIL.Body.Variables.Add(paramLocal);

            cctorIL.Emit(OpCodes.Newobj, paramCtor);
            cctorIL.Emit(OpCodes.Stloc, paramLocal);

            //Set parameter name
            cctorIL.Emit(OpCodes.Ldloc, paramLocal);
            cctorIL.Emit(OpCodes.Ldstr, paramName);
            cctorIL.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodParameterInfo).GetProperty("Name").GetSetMethod()));

            //Set parameter isRef
            cctorIL.Emit(OpCodes.Ldloc, paramLocal);
            cctorIL.Emit(OpCodes.Ldc_I4, param.ParameterType.IsByReference ? 1 : 0);
            cctorIL.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodParameterInfo).GetProperty("IsRef").GetSetMethod()));

            //Set parameter type
            cctorIL.Emit(OpCodes.Ldloc, paramLocal);
            if ((param.ParameterType.ContainsGenericParameter || param.ParameterType.HasGenericParameters || param.ParameterType.IsGenericParameter))
            {
                cctorIL.Emit(OpCodes.Ldnull);
            }
            else
            {
                cctorIL.Emit(OpCodes.Ldtoken, param.ParameterType);
                cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) })));
            }

            cctorIL.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodParameterInfo).GetProperty("Type").GetSetMethod()));

            //Set parameter attributes
            cctorIL.Emit(OpCodes.Ldloc, paramLocal);
            cctorIL.Emit(OpCodes.Ldtoken, method);
            if (isGeneric)
            {
                cctorIL.Emit(OpCodes.Ldtoken, declaringType);
            }
            cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(System.Reflection.MethodBase).GetMethod("GetMethodFromHandle",
                                                                                                              isGeneric ? new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) } : new Type[] { typeof(RuntimeMethodHandle) }
                                                                                                              )));
            cctorIL.Emit(OpCodes.Ldc_I4, param.Index);
            cctorIL.Emit(OpCodes.Call, ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("GetParameterAttributes")));
            cctorIL.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodParameterInfo).GetProperty("Attributes").GetSetMethod()));

            //Add parameter to list
            cctorIL.Emit(OpCodes.Ldloc, paramsLocal);
            cctorIL.Emit(OpCodes.Ldloc, paramLocal);
            cctorIL.Emit(OpCodes.Callvirt, paramAdd);
        }


        cctorIL.Emit(OpCodes.Ldloc, paramsLocal);
        cctorIL.Emit(OpCodes.Newobj, ModuleDefinition.Import(typeof(ReadOnlyCollection <AspectMethodParameterInfo>).GetConstructor(new[] { typeof(IList <AspectMethodParameterInfo>) })));
        cctorIL.Emit(OpCodes.Stsfld, paramsField);

        var oldBody = method.Body;
        var newBody = new MethodBody(method);
        var ret     = Instruction.Create(OpCodes.Ret);

        ret.SequencePoint = oldBody.Instructions.Last().SequencePoint;
        Instruction        local  = null;
        VariableDefinition result = returnType == TypeSystem.Void ? null : new VariableDefinition(returnType);
        var instructions          = oldBody.Instructions;
        var count         = instructions.Count;
        var startIndex    = 0;
        var usedVariables = new List <VariableDefinition>();
        var usedHash      = new HashSet <int>();


        var il = newBody.GetILProcessor();

        //Add initial logic for constructors
        if (!declaringType.IsSequentialLayout && declaringType.IsClass && method.IsConstructor)
        {
            for (var i = 0; i < count; i++)
            {
                var instruction = instructions[i];
                var opCode      = instruction.OpCode.ToString();
                var variable    = instruction.Operand as VariableReference;

                if (variable != null && !usedHash.Contains(variable.Index))
                {
                    usedHash.Add(variable.Index);
                    usedVariables.Add(variable.Resolve());
                }
                else if (opCode.IndexOf("stloc", StringComparison.OrdinalIgnoreCase) >= 0)
                {
                    var token = opCode.Split('.');
                    var index = Int32.Parse(token[1]);
                    if (!usedHash.Contains(index))
                    {
                        usedHash.Add(index);
                        usedVariables.Add(oldBody.Variables[index]);
                    }
                }

                if (instruction.OpCode == OpCodes.Call && (instruction.Operand as MethodReference).Resolve().IsConstructor)
                {
                    startIndex = i + 1;
                    il.Append(instruction);
                    break;
                }
                il.Append(instruction);
            }
        }

        if (origMethod != null)
        {
            oldBody.Variables.Clear();

            foreach (var variable in usedVariables)
            {
                newBody.Variables.Add(variable);
            }
        }
        else
        {
            foreach (var variable in oldBody.Variables)
            {
                newBody.Variables.Add(variable);
            }
        }

        //Add new variable for result if needed
        if (result != null)
        {
            newBody.Variables.Add(result);
        }


        //Define method context
        var aspectMethodInfo     = ModuleDefinition.Import(typeof(AspectMethodInfo));
        var context              = new VariableDefinition(aspectMethodInfo);
        var aspectMethodInfoCtor = ModuleDefinition.Import(aspectMethodInfo.Resolve().GetConstructors().First());

        //Add variable for context
        newBody.Variables.Add(context);

        //Create context instance
        il.Emit(OpCodes.Newobj, aspectMethodInfoCtor);
        il.Emit(OpCodes.Stloc, context);

        //Set method info to context
        il.Emit(OpCodes.Ldloc, context);
        il.Emit(OpCodes.Ldsfld, methodField);
        il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Method").GetSetMethod()));

        //Set method attributes to context
        il.Emit(OpCodes.Ldloc, context);
        il.Emit(OpCodes.Ldsfld, methodAttributesField);
        il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Attributes").GetSetMethod()));

        //Set instance to context
        if (!isStatic)
        {
            il.Emit(OpCodes.Ldloc, context);
            il.Emit(OpCodes.Ldarg_0);
            if (declaringType.IsValueType)
            {
                il.Emit(OpCodes.Ldobj, declaringType);
                il.Emit(OpCodes.Box, declaringType);
            }

            il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Instance").GetSetMethod()));
        }

        //Set parameters to context
        il.Emit(OpCodes.Ldloc, context);
        il.Emit(OpCodes.Ldsfld, paramsField);
        il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Parameters").GetSetMethod()));

        var argumentsLocal = new VariableDefinition(ModuleDefinition.Import(typeof(List <object>)));

        newBody.Variables.Add(argumentsLocal);
        var argumentsAdd = ModuleDefinition.Import(typeof(List <object>).GetMethod("Add", new[] { typeof(object) }));

        il.Emit(OpCodes.Ldloc, context);
        il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Arguments").GetGetMethod()));
        il.Emit(OpCodes.Stloc, argumentsLocal);

        //Set arguments to context
        foreach (var param in method.Parameters)
        {
            //Set argument value
            il.Emit(OpCodes.Ldloc, argumentsLocal);
            if (param.IsOut)
            {
                il.Emit(OpCodes.Ldnull);
            }
            else
            {
                il.Emit(OpCodes.Ldarg, param.Index + parameterOffset);
                if (param.ParameterType.IsByReference)
                {
                    var elementType = param.ParameterType.GetElementType();
                    if (!elementType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }
                    else if (elementType.FullName == ModuleDefinition.Import(typeof(int)).FullName)
                    {
                        il.Emit(OpCodes.Ldind_I4);
                    }
                    else if (elementType.FullName == ModuleDefinition.Import(typeof(byte)).FullName)
                    {
                        il.Emit(OpCodes.Ldind_I1);
                    }
                    else if (elementType.FullName == ModuleDefinition.Import(typeof(short)).FullName)
                    {
                        il.Emit(OpCodes.Ldind_I2);
                    }
                    else if (elementType.FullName == ModuleDefinition.Import(typeof(long)).FullName)
                    {
                        il.Emit(OpCodes.Ldind_I8);
                    }
                    else if (elementType.FullName == ModuleDefinition.Import(typeof(float)).FullName)
                    {
                        il.Emit(OpCodes.Ldind_R4);
                    }
                    else if (elementType.FullName == ModuleDefinition.Import(typeof(double)).FullName)
                    {
                        il.Emit(OpCodes.Ldind_R8);
                    }
                    else if (elementType.FullName == ModuleDefinition.Import(typeof(ushort)).FullName)
                    {
                        il.Emit(OpCodes.Ldind_U2);
                    }
                    else if (elementType.FullName == ModuleDefinition.Import(typeof(uint)).FullName)
                    {
                        il.Emit(OpCodes.Ldind_U4);
                    }

                    if (elementType.IsValueType)
                    {
                        il.Emit(OpCodes.Box, elementType);
                    }
                }

                if (param.ParameterType.IsValueType || (param.ParameterType.ContainsGenericParameter || param.ParameterType.HasGenericParameters || param.ParameterType.IsGenericParameter))
                {
                    il.Emit(OpCodes.Box, param.ParameterType);
                }
            }

            il.Emit(OpCodes.Callvirt, argumentsAdd);
        }

        //Call on intercept for context
        foreach (var attr in methAttrs)
        {
            FieldDefinition def;
            if (aspects.TryGetValue(attr.AttributeType.FullName, out def))
            {
                il.Emit(OpCodes.Ldsfld, def);
                il.Emit(OpCodes.Ldloc, context);
                il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnEnter")));
            }
        }

        var startFinally = Instruction.Create(OpCodes.Nop);

        il.Append(startFinally);

        //Call clone method here
        var startInvoke   = Instruction.Create(OpCodes.Nop);
        var continueLabel = Instruction.Create(OpCodes.Nop);

        il.Append(startInvoke);

        //Execute if continue of context is true
        il.Emit(OpCodes.Ldloc, context);
        il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Continue").GetGetMethod()));
        il.Emit(OpCodes.Brfalse, continueLabel);

        //Load this
        if (!isStatic)
        {
            il.Emit(OpCodes.Ldarg_0);
        }

        //Load Arguments
        for (var i = 0; i < method.Parameters.Count; i++)
        {
            il.Emit(OpCodes.Ldarg, parameterOffset + i);
        }

        //Invoke clone
        if (origMethod != null)
        {
            var cloneMethod       = ToGenericMethod(origMethod, declaringType);
            var invokeInstruction = Instruction.Create(isStatic || declaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, cloneMethod);

            il.Append(invokeInstruction);
        }
        else
        {
            instructions = new Mono.Collections.Generic.Collection <Instruction>(instructions.Skip(startIndex).ToList());
            instructions = new Mono.Collections.Generic.Collection <Instruction>(instructions.Take(instructions.Count - 1).ToList());
            foreach (var instruction in instructions)
            {
                il.Append(instruction);
            }
        }


        if (result == null)
        {
            //Call on success for context
            foreach (var attr in methAttrs)
            {
                FieldDefinition def;
                if (aspects.TryGetValue(attr.AttributeType.FullName, out def))
                {
                    il.Emit(OpCodes.Ldsfld, def);
                    il.Emit(OpCodes.Ldloc, context);
                    il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnSuccess")));
                }
            }

            //end of continue check
            il.Append(continueLabel);
        }
        else if (result != null)
        {
            //Create ldloc for local
            local = Instruction.Create(OpCodes.Ldloc, result);

            //Store result
            il.Emit(OpCodes.Stloc, result);


            //Set continuation for exception
            if (isTask)
            {
                MethodReference handleTaskError = ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("HandleTaskError"));

                //handle on error for task
                foreach (var attr in methAttrs)
                {
                    FieldDefinition def;
                    if (aspects.TryGetValue(attr.AttributeType.FullName, out def))
                    {
                        il.Emit(OpCodes.Ldsfld, def);
                        il.Emit(OpCodes.Ldloc, context);
                        il.Emit(OpCodes.Ldloc, result);
                        il.Emit(OpCodes.Call, handleTaskError);
                        il.Emit(OpCodes.Stloc, result);
                    }
                }
            }

            //Set result to context
            il.Emit(OpCodes.Ldloc, context);
            il.Emit(OpCodes.Ldloc, result);

            if (returnType.IsValueType || (returnType.ContainsGenericParameter || returnType.HasGenericParameters || returnType.IsGenericInstance))
            {
                il.Emit(OpCodes.Box, returnType);
            }

            il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Returns").GetSetMethod()));

            if (isTask)
            {
                MethodReference handleTaskSuccess = ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("HandleTaskSuccess"));

                //Handle on success for task
                foreach (var attr in methAttrs)
                {
                    FieldDefinition def;
                    if (aspects.TryGetValue(attr.AttributeType.FullName, out def))
                    {
                        il.Emit(OpCodes.Ldsfld, def);
                        il.Emit(OpCodes.Ldloc, context);
                        il.Emit(OpCodes.Ldloc, result);
                        il.Emit(OpCodes.Call, handleTaskSuccess);
                        il.Emit(OpCodes.Stloc, result);
                    }
                }
            }
            else
            {
                //Call on success for context
                foreach (var attr in methAttrs)
                {
                    FieldDefinition def;
                    if (aspects.TryGetValue(attr.AttributeType.FullName, out def))
                    {
                        il.Emit(OpCodes.Ldsfld, def);
                        il.Emit(OpCodes.Ldloc, context);
                        il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnSuccess")));
                    }
                }
            }

            if (isTask)
            {
                MethodReference handleTaskExit = ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("HandleTaskExit"));

                //Handle on exit for task
                foreach (var attr in methAttrs.Reverse())
                {
                    FieldDefinition def;
                    if (aspects.TryGetValue(attr.AttributeType.FullName, out def))
                    {
                        il.Emit(OpCodes.Ldsfld, def);
                        il.Emit(OpCodes.Ldloc, context);
                        il.Emit(OpCodes.Ldloc, result);
                        il.Emit(OpCodes.Call, handleTaskExit);
                        il.Emit(OpCodes.Stloc, result);
                    }
                }
            }

            //end of continue check
            il.Append(continueLabel);

            //Update return value if needed
            if (!isTask)
            {
                GenericInstanceMethod genReturn = new GenericInstanceMethod(ModuleDefinition.Import(typeof(ModuleWeaver).GetMethod("GetReturn")));
                genReturn.GenericArguments.Add(returnType);

                il.Emit(OpCodes.Ldloc, context);
                il.Emit(OpCodes.Call, genReturn);
                il.Emit(OpCodes.Stloc, result);
            }
        }

        il.Emit(OpCodes.Leave, local ?? ret);

        //catch
        var catRet  = Instruction.Create(OpCodes.Nop);
        var exLocal = new VariableDefinition(ModuleDefinition.Import(typeof(Exception)));

        newBody.Variables.Add(exLocal);
        il.Append(catRet);
        il.Emit(OpCodes.Stloc, exLocal);

        //Set exception to context
        il.Emit(OpCodes.Ldloc, context);
        il.Emit(OpCodes.Ldloc, exLocal);
        il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("Exception").GetSetMethod()));

        //Call on error for context
        foreach (var attr in methAttrs)
        {
            FieldDefinition def;
            if (aspects.TryGetValue(attr.AttributeType.FullName, out def))
            {
                il.Emit(OpCodes.Ldsfld, def);
                il.Emit(OpCodes.Ldloc, context);
                il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnError")));
            }
        }

        var throwLabel = Instruction.Create(OpCodes.Nop);

        il.Emit(OpCodes.Ldloc, context);
        il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(AspectMethodInfo).GetProperty("ReThrow").GetGetMethod()));
        il.Emit(OpCodes.Brfalse, throwLabel);

        il.Emit(OpCodes.Rethrow);

        il.Append(throwLabel);

        var endCatch = Instruction.Create(OpCodes.Leave, local ?? ret);

        il.Emit(OpCodes.Leave, endCatch);

        il.Append(endCatch);

        //finally
        var finallyRet = Instruction.Create(OpCodes.Nop);

        il.Append(finallyRet);

        if (!isTask)
        {
            //Call on exit for context
            foreach (var attr in methAttrs.Reverse())
            {
                FieldDefinition def;
                if (aspects.TryGetValue(attr.AttributeType.FullName, out def))
                {
                    il.Emit(OpCodes.Ldsfld, def);
                    il.Emit(OpCodes.Ldloc, context);
                    il.Emit(OpCodes.Callvirt, ModuleDefinition.Import(typeof(BaseAspect).GetMethod("OnExit")));
                    var nop      = Instruction.Create(OpCodes.Nop);
                    var lastItem = instructions.LastOrDefault(x => x.SequencePoint != null);
                    if (lastItem != null)
                    {
                        nop.SequencePoint = lastItem.SequencePoint;
                    }
                    il.Append(nop);
                }
            }
        }

        il.Emit(OpCodes.Endfinally);

        if (result != null)
        {
            il.Append(local);
        }

        il.Append(ret);

        var @catch = new ExceptionHandler(ExceptionHandlerType.Catch)
        {
            TryStart     = startInvoke,
            TryEnd       = catRet,
            HandlerStart = catRet,
            HandlerEnd   = endCatch,
            CatchType    = ModuleDefinition.Import(typeof(Exception))
        };

        var @finally = new ExceptionHandler(ExceptionHandlerType.Finally)
        {
            TryStart     = startFinally,
            TryEnd       = finallyRet,
            HandlerStart = finallyRet,
            HandlerEnd   = local ?? ret
        };

        newBody.ExceptionHandlers.Add(@catch);
        newBody.ExceptionHandlers.Add(@finally);
        newBody.InitLocals = true;
        newBody.OptimizeMacros();

        method.Body = newBody;
        // Mark the re-written method (if not already marked) so that the debugger doesn't try to stop in generated code.
        if (!method.CustomAttributes.Any(attr => attr.Constructor.FullName == debuggerStepThroughAttributeCtor.FullName))
        {
            method.CustomAttributes.Add(new CustomAttribute(debuggerStepThroughAttributeCtor));
        }
    }
Ejemplo n.º 6
0
    /// <summary>
    /// Create a clone of given method and add to the specified type
    /// </summary>
    /// <param name="method">Method</param>
    /// <param name="type">Type</param>
    /// <returns>MethodDefinition</returns>
    private MethodDefinition CloneMethod(MethodDefinition method, TypeDefinition type)
    {
        var methodAttribute = MethodAttributes.Private;

        if (method.IsStatic)
        {
            methodAttribute |= MethodAttributes.Static;
        }

        var meth = new MethodDefinition(method.Name + "_☈_", methodAttribute, method.ReturnType);

        meth.CallingConvention = method.CallingConvention;
        meth.ImplAttributes    = method.ImplAttributes;
        meth.IsGetter          = method.IsGetter;
        meth.IsSetter          = method.IsSetter;
        meth.HasThis           = method.HasThis;

        var body    = meth.Body;
        var oldBody = method.Body;
        var il      = body.GetILProcessor();

        var instructions = oldBody.Instructions;
        var count        = instructions.Count;
        var startIndex   = 0;

        if (method.HasGenericParameters)
        {
            foreach (var generic in method.GenericParameters)
            {
                var genericParameter = new GenericParameter(generic.Name, meth);
                generic.Constraints.ToList().ForEach(x => genericParameter.Constraints.Add(x));
                generic.CustomAttributes.ToList().ForEach(x => genericParameter.CustomAttributes.Add(x));
                genericParameter.Attributes = generic.Attributes;
                generic.GenericParameters.ToList().ForEach(x => genericParameter.GenericParameters.Add(new GenericParameter(x.Name, meth)));

                meth.GenericParameters.Add(genericParameter);
            }
        }

        foreach (var param in method.Parameters)
        {
            var paramAttributes = param.Attributes;
            paramAttributes &= ~ParameterAttributes.HasDefault;
            meth.Parameters.Add(new ParameterDefinition(param.Name, paramAttributes, param.ParameterType));
        }

        foreach (var variable in method.Body.Variables)
        {
            body.Variables.Add(variable);
        }


        if (!method.DeclaringType.IsSequentialLayout && method.DeclaringType.IsClass && method.IsConstructor)
        {
            for (var i = 0; i < count; i++)
            {
                var instruction = instructions[i];
                if (instruction.OpCode == OpCodes.Call && (instruction.Operand as MethodReference).Resolve().IsConstructor)
                {
                    startIndex = i + 1;
                    break;
                }
            }
        }

        instructions = new Mono.Collections.Generic.Collection <Instruction>(instructions.Skip(startIndex).ToList());

        foreach (var instruction in instructions)
        {
            il.Append(instruction);
        }

        foreach (var handler in oldBody.ExceptionHandlers)
        {
            body.ExceptionHandlers.Add(handler);
        }

        body.InitLocals = true;
        body.OptimizeMacros();

        return(meth);
    }
Ejemplo n.º 7
0
    public static void Test()
    {
        string             path     = "./Library/ScriptAssemblies/Assembly-CSharp.dll";
        AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(path);
        bool haveInjected           = false;

        if (assembly.MainModule.Types.Any(t => t.Name == "__HOTFIXE_FLAG"))
        {
            Debug.Log("had injected!");
            haveInjected = true;
        }
        TypeReference objType = assembly.MainModule.Import(typeof(object));

        assembly.MainModule.Types.Add(new TypeDefinition("__HOTFIX_GEN", "__HOTFIXE_FLAG", Mono.Cecil.TypeAttributes.Class,
                                                         objType));

        var AAAttribute = assembly.MainModule.Types.Single(t => t.FullName == "HotFixAttribute");
        List <TypeDefinition> hotfix_delegates = (from module in assembly.Modules
                                                  from type in module.Types
                                                  where type.CustomAttributes.Any(ca => ca.AttributeType == AAAttribute)
                                                  select type).ToList();

        /*var hotfixAttributeType = assembly.MainModule.Types.Single(t => t.FullName == "AAAttribute");
         * foreach (var type in (from module in assembly.Modules from type in module.Types select type))
         * {
         *  Debug.Log("OK");
         * } */

        List <MethodDefinition> ms = (from module in assembly.Modules
                                      from type in module.Types
                                      from method in type.Methods
                                      where method.Name == "InjectMethod"
                                      select method).ToList();

        //List<MethodDefinition> testCalls = (from module in assembly.Modules
        //                             from type in module.Types
        //                             from method in type.Methods
        //                             where type.FullName=="TT.TestChangeMethod" && method.Name == "testCall"
        //                             select method).ToList();
        //MethodDefinition testCall = testCalls [0];

        var voidType = assembly.MainModule.Import(typeof(void));

        foreach (TypeDefinition td in hotfix_delegates)
        {
            Mono.Collections.Generic.Collection <MethodDefinition> methods = td.Methods;
            foreach (MethodDefinition method in methods)
            {
                //构造函数,和基本返回类型不处理
                if (!haveInjected && !method.IsConstructor && (!method.ReturnType.IsValueType))
                {
                    //方法的参数的个数
                    int param_count = method.Parameters.Count + (method.IsStatic ? 0 : 1);

                    string name = (td.FullName + "_" + method.Name);
                    name = name.Replace(".", "_");
                    var insertPoint = method.Body.Instructions[0];
                    var processor   = method.Body.GetILProcessor();

                    if (method.IsConstructor)
                    {
                        insertPoint = findNextRet(method.Body.Instructions, insertPoint);
                    }

                    Instruction para = processor.Create(OpCodes.Ldstr, name);
                    processor.InsertBefore(insertPoint, para);

                    processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, param_count));
                    processor.InsertBefore(insertPoint, processor.Create(OpCodes.Newarr, objType));

                    for (int i = 0; i < param_count; i++)
                    {
                        processor.InsertBefore(insertPoint, processor.Create(OpCodes.Dup));
                        processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldc_I4, i));
                        if (i < ldargs.Length)
                        {
                            //将参数装入列表
                            processor.InsertBefore(insertPoint, processor.Create(ldargs[i]));
                        }
                        else
                        {
                            processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldarg, (short)i));
                        }
                        int index = i;
                        if (!method.IsStatic)
                        {
                            index -= 1;
                        }
                        if (index >= 0 && method.Parameters[index].ParameterType.IsValueType)
                        {
                            processor.InsertBefore(insertPoint, processor.Create(OpCodes.Box, method.Parameters[index].ParameterType));
                        }
                        processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stelem_Ref));
                    }
                    Instruction ii = processor.Create(OpCodes.Call, ms[0].GetElementMethod());
                    processor.InsertBefore(insertPoint, ii);

                    //处理结果
                    var keyVPType = assembly.MainModule.Import(typeof(KeyValuePair <bool, object>));
                    var mr        = new VariableDefinition(keyVPType);
                    method.Body.Variables.Add(mr);
                    method.Body.InitLocals = true;
                    processor.InsertBefore(insertPoint, processor.Create(OpCodes.Stloc, mr));
                    processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloca_S, mr));
                    var met = assembly.MainModule.Import(typeof(KeyValuePair <bool, object>).GetMethod("get_Key"));
                    processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, met));
                    processor.InsertBefore(insertPoint, processor.Create(OpCodes.Brfalse, insertPoint));

                    if (method.ReturnType.FullName == voidType.FullName)
                    {
                        //如果返回时空,则弹出所有的栈。已经没有栈了,上面的判断用过了。
                        //processor.InsertBefore(insertPoint,processor.Create(OpCodes.Pop));
                    }
                    else
                    {
                        processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ldloca_S, mr));
                        met = assembly.MainModule.Import(typeof(KeyValuePair <bool, object>).GetMethod("get_Value"));
                        processor.InsertBefore(insertPoint, processor.Create(OpCodes.Call, met));

                        //返回类型转换。
                        //if(method.ReturnType.IsValueType)
                        //{
                        //基础类型,不处理。
                        //processor.InsertBefore(insertPoint,processor.Create(OpCodes.Unbox_Any,method.ReturnType));
                        //}else{
                        //processor.InsertBefore(insertPoint,processor.Create(OpCodes.Castclass,method.ReturnType));
                        //}
                    }
                    processor.InsertBefore(insertPoint, processor.Create(OpCodes.Ret));
                    //直接复制testCall从stloc.0直到第一个return开始的部分

                    /*bool start = false;
                     * foreach(Instruction ins in testCall.Body.Instructions)
                     * {
                     *      if(ins.OpCode == OpCodes.Stloc_0)
                     *      {
                     *              //复制开始
                     *              start = true;
                     *      }
                     *      if(start)
                     *      {
                     *              processor.InsertBefore(insertPoint,ins);
                     *      }
                     *      if(ins.OpCode == OpCodes.Ret)
                     *      {
                     *              //结束复制
                     *              break;
                     *      }
                     * }*/

                    Debug.Log("canFix : " + name);
                }
            }
        }
        if (!haveInjected)
        {
            assembly.Write(path);
        }
    }
Ejemplo n.º 8
0
    static void PrepareExceptions(Mono.Collections.Generic.Collection <ExceptionHandler> excHandlers,
                                  Dictionary <int, List <string> > excStrings)
    {
        if (excHandlers == null)
        {
            foreach (var kvp in excStrings)
            {
                if (kvp.Value.Count == 0)
                {
                    kvp.Value.Add("    }");
                }
            }

            return;
        }

        var           prevBlock = (First : -1, Last : -1);
        var           currBlock = prevBlock;
        List <string> strs;

        foreach (var exc in excHandlers)
        {
            currBlock = (exc.TryStart.Offset, exc.TryEnd.Offset);

            if (currBlock != prevBlock)
            {
                if (!excStrings.TryGetValue(currBlock.First, out strs))
                {
                    strs = new List <string>();
                }
                strs.Insert(0, $"try {{ // {currBlock.First:X4}..{currBlock.Last:X4}");
                excStrings[currBlock.First] = strs;

                prevBlock = currBlock;
            }

            if (exc.HandlerStart != null)
            {
                if (!excStrings.TryGetValue(exc.HandlerStart.Offset, out strs))
                {
                    strs = new List <string>();
                }

                string str;

                if (exc.HandlerType == ExceptionHandlerType.Catch)
                {
                    str = $"catch ({exc.CatchType.FullName})";
                }

                else if (exc.HandlerType == ExceptionHandlerType.Filter)
                {
                    str = "filter handler";
                }

                else if (exc.HandlerType == ExceptionHandlerType.Finally)
                {
                    str = "finally";
                }

                else if (exc.HandlerType == ExceptionHandlerType.Fault)
                {
                    str = "fault handler";
                }

                else
                {
                    str = "unknown handler";
                }

                strs.Add($"    }} {str} in block {currBlock.First:X4}..{currBlock.Last:X4} {{");

                excStrings[exc.HandlerStart.Offset] = strs;
            }

            if (exc.FilterStart != null)
            {
                if (!excStrings.TryGetValue(exc.FilterStart.Offset, out strs))
                {
                    strs = new List <string>();
                }

                strs.Add($"    }} filter condition in block {currBlock.First:X4}..{currBlock.Last:X4} {{");

                excStrings[exc.FilterStart.Offset] = strs;
            }

            if (exc.HandlerEnd != null)
            {
                if (!excStrings.TryGetValue(exc.HandlerEnd.Offset, out strs))
                {
                    excStrings[exc.HandlerEnd.Offset] = new List <string>();
                }
            }
        }
    }
Ejemplo n.º 9
0
 static bool HasNullableReferenceType(this Mono.Collections.Generic.Collection <CustomAttribute> value, string attributeTypeName)
 => value.Where(a => a.AttributeType.Name == attributeTypeName)
 .SelectMany(a => a.ConstructorArguments)
 .Where(ca => ca.Type.FullName == SystemByteFullTypeName)
 .Where(ca => (byte)ca.Value == NullableAnnotated)
 .Any();