/// <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) { MethodReference methodToCall; // Get JoinPointContext VariableDefinition jpcVar = visitor.CreateJoinPointContextLocal(); // Get the methodReference MethodReference methodReference = (MethodReference)originalCall; TypeDefinition parentType = CecilUtilities.ResolveTypeDefinition(visitor.Method.DeclaringType); // Get method to call methodToCall = GetMethodToCall(visitor, filterAction, parentType); if (methodToCall == null) { throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture, Properties.Resources.AdviceMethodNotFound, getSelector(filterAction), getTarget(filterAction))); } // Set JoinPointContext WeaveStrategyUtilities.SetJoinPointContext(visitor, methodReference, filterAction); // Check if it is an innercall and set innercall context: if (getTarget(filterAction).Equals(FilterAction.InnerTarget)) { WeaveStrategyUtilities.SetInnerCall(visitor, methodToCall); } // Do the advice-call AdviceActionWeaveStrategy.CallAdvice(visitor, filterAction, parentType, methodToCall, jpcVar); // Add nop to enable debugging visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Nop)); }
public static void SetJoinPointContext( ICecilInliningInstructionVisitor visitor, MethodReference originalCall, FilterAction filterAction) { VariableDefinition jpcVar = visitor.CreateJoinPointContextLocal(); // Store current target if (filterAction.Target.Equals(FilterAction.InnerTarget) || filterAction.Target.Equals(FilterAction.SelfTarget)) { visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, CachedMethodDefinition.JoinPointContextGetStartTarget))); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, CachedMethodDefinition.JoinPointContextSetCurrentTarget))); } else if (visitor.Method.HasThis) { TypeDefinition parentType = CecilUtilities.ResolveTypeDefinition(visitor.Method.DeclaringType); FieldDefinition field = parentType.Fields.GetField(filterAction.Target); if (field == null) { throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture, Properties.Resources.FieldNotFound, filterAction.Target)); } visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldarg, visitor.Method.This)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldfld, field)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, CachedMethodDefinition.JoinPointContextSetCurrentTarget))); } else { // set to null for static methods visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldnull)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, CachedMethodDefinition.JoinPointContextSetCurrentTarget))); } // store current selector visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldstr, filterAction.Selector)); visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, CachedMethodDefinition.JoinPointContextSetCurrentSelector))); // Store substitution target //if (filterAction.SubstitutionTarget.Equals(FilterAction.InnerTarget) || // filterAction.SubstitutionTarget.Equals(FilterAction.SelfTarget)) //{ // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, // CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, // CachedMethodDefinition.JoinPointContextGetStartTarget))); // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, // CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, // CachedMethodDefinition.JoinPointContextGetSubstitutionTarget))); //} //else if (visitor.Method.HasThis) //{ // TypeDefinition parentType = CecilUtilities.ResolveTypeDefinition(visitor.Method.DeclaringType); // FieldDefinition field = parentType.Fields.GetField(filterAction.SubstitutionTarget); // if (field == null) // { // throw new ILWeaverException(String.Format(CultureInfo.CurrentCulture, // Properties.Resources.FieldNotFound, filterAction.SubstitutionTarget)); // } // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldarg, visitor.Method.This)); // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldfld, field)); // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, // CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, // CachedMethodDefinition.JoinPointContextSetSubstitutionTarget))); //} //else //{ // // set to null for static methods // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldnull)); // visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, // CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, // CachedMethodDefinition.JoinPointContextSetSubstitutionTarget))); //} // store substitution selector // TODO no longer relevant //visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldloc, jpcVar)); //visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Ldstr, filterAction.SubstitutionSelector)); //visitor.Instructions.Add(visitor.Worker.Create(OpCodes.Callvirt, // CecilUtilities.CreateMethodReference(visitor.TargetAssemblyDefinition, // CachedMethodDefinition.JoinPointContextSetSubstitutionSelector))); }
/// <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))); }
/// <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); }
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)); }