Пример #1
0
        /// <summary>
        /// Returns the MethodReference to the advice method.
        /// </summary>
        /// <param name="visitor">The visitor.</param>
        /// <param name="filterAction">The filteraction.</param>
        /// <param name="parentType">The type containing the original method.</param>
        /// <returns>
        /// The MethodReference to the advice method.
        /// </returns>
        private MethodReference GetMethodToCall(ICecilInliningInstructionVisitor visitor,
                                                FilterAction filterAction, TypeDefinition parentType)
        {
            MethodReference result       = null;
            string          fargTarget   = getTarget(filterAction);
            string          fargSelector = getSelector(filterAction);

            if (fargTarget.Equals(FilterAction.InnerTarget) ||
                fargTarget.Equals(FilterAction.SelfTarget))
            {
                result = CecilUtilities.ResolveMethod(parentType, fargSelector, m_JpcTypes);
                if (result == null)
                {
                    result = CecilUtilities.ResolveMethod(parentType, fargSelector, m_ObjectTypes);
                }
                if (result == null)
                {
                    result = CecilUtilities.ResolveMethod(parentType, fargSelector, m_NoneTypes);
                }
            }
            else
            {
                FieldDefinition target = parentType.Fields.GetField(fargTarget);
                if (target == null)
                {
                    throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                              Properties.Resources.FieldNotFound, fargTarget));
                }

                MethodDefinition method = CecilUtilities.ResolveMethod(target.FieldType,
                                                                       fargSelector, m_JpcTypes);

                if (method == null)
                {
                    // try func(Object)
                    method = CecilUtilities.ResolveMethod(target.FieldType, fargSelector, m_ObjectTypes);
                }
                if (method == null)
                {
                    // try func()
                    method = CecilUtilities.ResolveMethod(target.FieldType, fargSelector, m_NoneTypes);
                }

                if (method == null)
                {
                    throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                              Properties.Resources.MethodNotFound, target.FieldType, fargSelector));
                }

                return(visitor.TargetAssemblyDefinition.MainModule.Import(method));
            }
            return(result);
        }
Пример #2
0
        public static void SetInnerCall(ICecilInliningInstructionVisitor visitor, MethodReference method)
        {
            MethodDefinition methodDef = CecilUtilities.ResolveMethod(
                visitor.Method.DeclaringType, method.Name, method);

            // Get the weaveMethod to which the innercall is directed
            WeaveMethod weaveMethod = visitor.WeaveType.GetMethod(methodDef.ToString());

            //if(weaveMethod == null)
            //{
            //    // if using MethodReference failed, try using the MethodDefinition (in some cases the ToString
            //    // leads to different signatures).
            //    MethodDefinition methodDef = CecilUtilities.ResolveMethodDefinition(method);
            //    if(methodDef != null)
            //    {
            //        weaveMethod = visitor.WeaveType.GetMethod(method.ToString());
            //    }

            if (weaveMethod == null)
            {
                // If weave method could not be found, this means that the method
                // does not have filters woven and so no inner call context needs
                // to be set.

                return;
            }
            //}

            // Load the this parameter
            if (!visitor.Method.HasThis || visitor.Method.DeclaringType.IsValueType)
            {
                visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldnull));
            }
            else
            {
                visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldarg, visitor.Method.This));
            }

            // Load the methodId
            visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldc_I4, weaveMethod.Id));

            // Call the SetInnerCall
            visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Call, CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, CachedMethodDefinition.SetInnerCall)));
        }
Пример #3
0
        /// <summary>
        /// Visits the condition literal.
        /// </summary>
        /// <remarks>
        /// Generate a call to a condition. This is a call to a boolean method.
        /// </remarks>
        /// <param name="conditionLiteral">The condition literal.</param>
        public void VisitConditionLiteral(ConditionLiteral conditionLiteral)
        {
            // Get the condition
            Condition con = GetConditionByName(conditionLiteral.Name);

            if (con == null)
            {
                throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture, Properties.Resources.ConditionNotFound, conditionLiteral.Name));
            }

            // Get the parenttype
            TypeDefinition parentType = CecilUtilities.ResolveTypeDefinition(_visitor.Method.DeclaringType);

            // Get the method
            MethodReference method;
            FieldDefinition target = null;

            // Check if this is an inner or self target.
            if (con.Reference.Target != null &&
                (con.Reference.Target.Equals(Reference.InnerTarget) ||
                 con.Reference.Target.Equals(Reference.SelfTarget)
                ))
            {
                method = CecilUtilities.ResolveMethod(
                    con.Reference.Selector, WeaveType.Name,
                    con.Reference.Assembly, String.Empty);
            }
            else if (con.Reference.Target != null &&
                     (IsInternal(con.Reference.Target) || IsExternal(con.Reference.Target))
                     )
            {
                if (!Method.HasThis)
                {
                    throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                              Properties.Resources.StaticReferenceInternalExternal,
                                                              Method.Name,
                                                              Method.DeclaringType.FullName));
                }

                target = parentType.Fields.GetField(con.Reference.Target);

                TypeDefinition   fieldType = CecilUtilities.ResolveTypeDefinition(target.FieldType);
                MethodDefinition md        = CecilUtilities.ResolveMethod(fieldType, con.Reference.Selector, new Type[0]);

                // If method with no parameters cannot be found, try to find method with JPC context as parameter
                if (md == null)
                {
                    md = CecilUtilities.ResolveMethod(fieldType, con.Reference.Selector, m_JpcTypes);
                }

                if (md == null)
                {
                    throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture, Properties.Resources.MethodNotFound2, con.Reference.Selector, con.Reference.Target, fieldType.FullName));
                }

                method = _visitor.TargetAssemblyDefinition.MainModule.Import(md);
            }
            else
            {
                method = CecilUtilities.ResolveMethod(
                    con.Reference.Selector,
                    con.Reference.FullTypeName,
                    con.Reference.Assembly, String.Empty);
            }

            // If we could not find the condition method, throw an exception
            if (method == null)
            {
                throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                          Properties.Resources.MethodNotFound,
                                                          con.Reference.Selector,
                                                          con.Reference.FullTypeName,
                                                          con.Reference.Assembly));
            }

            // If it is an inner or self call, we set the InnerCall context
            if (con.Reference.Target != null &&
                (con.Reference.Target.Equals(Reference.InnerTarget) ||
                 con.Reference.Target.Equals(Reference.SelfTarget)
                ))
            {
                // Set innercall context
                if (con.Reference.InnerCallContext >= 0)
                {
                    // Load the this parameter
                    if (!Method.HasThis)
                    {
                        Instructions.Add(Worker.Create(OpCodes.Ldnull));
                    }
                    else
                    {
                        Instructions.Add(Worker.Create(OpCodes.Ldarg, Method.This));
                    }

                    // Load the methodId
                    Instructions.Add(Worker.Create(OpCodes.Ldc_I4, con.Reference.InnerCallContext));

                    // Call the SetInnerCall
                    Instructions.Add(Worker.Create(OpCodes.Call,
                                                   CreateMethodReference(typeof(FilterContext).GetMethod("SetInnerCall",
                                                                                                         new Type[] { typeof(object), typeof(int) }))));
                }

                // Load the this pointer
                Instructions.Add(Worker.Create(OpCodes.Ldarg, Method.This));
            }
            // internal/external and not static:
            else if (target != null && method.HasThis)
            {
                // Load the this pointer
                Instructions.Add(Worker.Create(OpCodes.Ldarg, Method.This));

                // Load the field
                Instructions.Add(Worker.Create(OpCodes.Ldfld, target));
            }
            // else do nothing, because of static call

            // Convert to a method definition so we can inspect the custom attributes
            MethodDefinition methodDef = (MethodDefinition)method;

            if (methodDef != null)
            {
                // Find a custom attribute to use
                foreach (CustomAttribute ca in methodDef.CustomAttributes)
                {
                    // Retrieve the type name of the custom attribute
                    String typeName = ca.Constructor.DeclaringType.ToString();

                    // Check if the custom attribute is called ConditionParameter so we do not activate all kinds of attributes
                    if (typeName.Contains(ConditionParameterName))
                    {
                        // Resolve the CP
                        ConditionParameterAttribute cpa = ResolveConditionParameter(typeName);

                        // Do we have a CPA?
                        if (cpa != null)
                        {
                            // Check if the condition is valid for this code generation
                            if (cpa.IsValidCondition(methodDef))
                            {
                                // Generate the code needed for this condition
                                cpa.Generate(_visitor, Method, methodDef);
                            }
                            else
                            {
                                // Throw an exception since the condition is not valid. We cannot create valid code for this.
                                throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                                          Properties.Resources.ConditionParameterInvalid,
                                                                          typeName, methodDef.ToString(), cpa.RequiredCondition));
                            }
                        }
                        else
                        {
                            // Throw an exception, we cannot create the custom attribute
                            throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                                      Properties.Resources.ConditionParameterNotFound,
                                                                      typeName));
                        }

                        // Quit the for loop. If there are more custom attributes, we simply skip them.
                        break;
                    }
                }
            }

            // Check if we have to add the JPC
            // Legacy code, should be able to do this using the ConditionParameter?
            if (method.Parameters.Count == 1)
            {
                if (method.Parameters[0].ParameterType.FullName.Equals(typeof(JoinPointContext).FullName))
                {
                    VariableDefinition jpcVar = _visitor.CreateJoinPointContextLocal();
                    Instructions.Add(Worker.Create(OpCodes.Ldloc, jpcVar));
                }
            }

            // Create a call instruction
            Instructions.Add(Worker.Create(OpCodes.Call, TargetAssemblyDefinition.MainModule.Import(method)));
        }
Пример #4
0
        /// <summary>
        /// Generate the code which has to be inserted at the place of the filter specified by the visitor.
        /// </summary>
        /// <param name="visitor">The visitor.</param>
        /// <param name="filterAction">The filter action.</param>
        /// <param name="originalCall">The original call.</param>
        public override void Weave(ICecilInliningInstructionVisitor visitor, FilterAction filterAction,
                                   MethodDefinition originalCall)
        {
            // Get JoinPointContext
            VariableDefinition jpcVar = visitor.CreateJoinPointContextLocal();

            FieldDefinition target = null;

            // Get the methodReference
            MethodReference methodReference = null;

            TypeDefinition parentTypeDefinition = (TypeDefinition)(visitor.Method.DeclaringType);
            TypeReference  parentTypeReference  = visitor.Method.DeclaringType;

            if (parentTypeReference.GenericParameters.Count > 0)
            {
                GenericInstanceType git = new GenericInstanceType(visitor.Method.DeclaringType);

                foreach (GenericParameter gp in originalCall.DeclaringType.GenericParameters)
                {
                    git.GenericArguments.Add(gp);
                }

                parentTypeReference = git;
            }

            // Get the called method
            if (filterAction.Target.Equals(FilterAction.InnerTarget) ||
                filterAction.Target.Equals(FilterAction.SelfTarget))
            {
                if (filterAction.Selector.Equals(originalCall.Name))
                {
                    if (parentTypeReference is GenericInstanceType)
                    {
                        methodReference = new MethodReference(originalCall.Name,
                                                              parentTypeReference, originalCall.ReturnType.ReturnType,
                                                              originalCall.HasThis, originalCall.ExplicitThis,
                                                              originalCall.CallingConvention);
                        methodReference.DeclaringType = parentTypeReference;

                        foreach (ParameterDefinition param in originalCall.Parameters)
                        {
                            methodReference.Parameters.Add(param);
                        }

                        methodReference = visitor.TargetAssemblyDefinition.MainModule.Import(methodReference, parentTypeDefinition);

                        /* This piece of code must solve the following problem:
                         *
                         * class<T> Test
                         * {
                         *    void Func(T a)
                         *    {
                         *       // inner call
                         *       Test<T>.Func(a);
                         *    }
                         * }
                         *
                         * Resolving Test<T> to a GenericInstanceType is no problem
                         * The methodReference must use the GenericInstanceType as its base type
                         * Import the new methodReference before use.
                         */
                    }
                    else
                    {
                        methodReference = originalCall;
                    }
                }
                else
                {
                    methodReference = CecilUtilities.ResolveMethod(parentTypeDefinition,
                                                                   filterAction.Selector, originalCall);
                }
            }
            else
            {
                target = parentTypeDefinition.Fields.GetField(filterAction.Target);
                if (target == null)
                {
                    throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                              Properties.Resources.FieldNotFound, filterAction.Target));
                }

                TypeDefinition   fieldType = CecilUtilities.ResolveTypeDefinition(target.FieldType);
                MethodDefinition md        = CecilUtilities.ResolveMethod(fieldType,
                                                                          filterAction.Selector, originalCall);

                if (md == null)
                {
                    throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                              "Method {0} not found in {1}", filterAction.Selector, fieldType.FullName));
                }

                methodReference = visitor.TargetAssemblyDefinition.MainModule.Import(md);
            }

            // If there is no method reference, then we cannot dispatch. Raise an exception.
            if (methodReference == null)
            {
                throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture,
                                                          Properties.Resources.MethodNotFound, parentTypeReference.ToString(), filterAction.Selector));
            }


            // Check if it is an innercall and set innercall context:
            if (filterAction.Target.Equals(FilterAction.InnerTarget))
            {
                WeaveStrategyUtilities.SetInnerCall(visitor, methodReference);
            }


            // Generic arguments; add the generic parameters as generic argument to a GenericInstanceMethod
            if (originalCall.GenericParameters.Count > 0)
            {
                // Original call has generics, so add to the new memberreference
                GenericInstanceMethod gim = new GenericInstanceMethod(methodReference);
                foreach (GenericParameter gp in originalCall.GenericParameters)
                {
                    gim.GenericArguments.Add(gp);
                }
                methodReference = gim;
            }

            // Place the arguments on the stack first

            // Place target on the stack
            if (methodReference.HasThis)
            {
                if (filterAction.Target.Equals(FilterAction.InnerTarget) ||
                    filterAction.Target.Equals(FilterAction.SelfTarget))
                {
                    WeaveStrategyUtilities.LoadSelfObject(visitor, jpcVar);
                }
                else
                {
                    visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldarg, visitor.Method.This));
                    visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldfld, target));
                }
            }

            // Place arguments on the stack
            WeaveStrategyUtilities.LoadArguments(visitor, originalCall, jpcVar);

            // Call the method
            if (filterAction.Target.Equals(FilterAction.InnerTarget) &&
                filterAction.Selector.Equals(originalCall.Name))
            {
                // Because it is an inner call targeting the method itself, we must call the method
                // in the class itself. Therefore we do a Call instead of a Callvirt, to prevent that
                // the call is dispatched to an overriding method in a subclass.
                visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Call, methodReference));
            }
            else if (visitor.CalledMethod.HasThis)
            {
                // Because we dispatch to another method than the original called method, we do a Callvirt
                // so that an overriding method in a subclass may be called.
                visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, methodReference));
            }
            else
            {
                // static method cannot be called with Callvirt.
                visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Call, methodReference));
            }

            // Store the return value:
            WeaveStrategyUtilities.StoreReturnValue(visitor, originalCall, jpcVar);

            // Restore arguments:
            WeaveStrategyUtilities.RestoreArguments(visitor, originalCall, jpcVar);
        }
Пример #5
0
        public override void Weave(ICecilInliningInstructionVisitor visitor, FilterAction filterAction,
                                   MethodDefinition originalCall)
        {
            // The method we have to call, an Execute(JoinPointContext) function.
            MethodReference methodToCall;

            // Create FilterAction object:
            FilterActionElement filterActionElement;

            filterActionElement = DefaultWeaveStrategy.GetFilterActionElement(visitor.WeaveConfiguration.FilterActions, filterAction.FullName);

            if (filterActionElement == null)
            {
                throw new ILWeaverException(string.Format(CultureInfo.CurrentCulture, Properties.Resources.CouldNotResolveFilterAction, filterAction.FullName));
            }

            // Get JoinPointContext
            VariableDefinition jpcVar = null;

            if (filterActionElement.CreateJPC)
            {
                jpcVar = visitor.CreateJoinPointContextLocal();
            }

            // Get the methodReference
            MethodReference methodReference = (MethodReference)originalCall;

            // TypeDefinition parentType = CecilUtilities.ResolveTypeDefinition(methodReference.DeclaringType);

            // Set JoinPointContext
            if (filterActionElement.CreateJPC)
            {
                WeaveStrategyUtilities.SetJoinPointContext(visitor, methodReference, filterAction);
            }

            TypeReference typeRef =
                CecilUtilities.ResolveType(filterAction.FullName, filterActionElement.Assembly, null);
            TypeDefinition typeDef =
                CecilUtilities.ResolveTypeDefinition(typeRef);
            MethodReference constructor = typeDef.Constructors.GetConstructor(false, new Type[0]);

            if (constructor == null)
            {
                throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture, Properties.Resources.TypeNotFound, filterAction.FullName));
            }

            constructor = visitor.TargetAssemblyDefinition.MainModule.Import(constructor);
            visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Newobj, constructor));

            // Get method to call
            methodToCall = CecilUtilities.ResolveMethod(typeDef, "Execute", new Type[] { typeof(JoinPointContext) });

            // Check for null value
            if (methodToCall == null)
            {
                throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture, Properties.Resources.AdviceMethodNotFound, "Execute", filterAction.FullName));
            }

            methodToCall = visitor.TargetAssemblyDefinition.MainModule.Import(methodToCall);

            // Load the JoinPointObject as the parameter if required
            if (filterActionElement.CreateJPC)
            {
                visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar));
            }
            else
            {
                visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldnull));
            }

            // Do the call
            // We can safely emit a callvirt here. The JITter will make the right call.
            visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, methodToCall));
        }