コード例 #1
0
ファイル: AroundBody.cs プロジェクト: leftouterjoin/loj-prj1
        public void Cleanup()
        {
            foreach (DictionaryEntry entry in m_InterceptorsToWeave) {
                MethodDefinition containerMethod = entry.Key as MethodDefinition;
                TypeDefinition containerType = (TypeDefinition)containerMethod.DeclaringType;

                // Methods can be removed. In that case, they don't have a declaring type any more
                if (containerType != null) {
                    // Clone and rename the target method
                    MethodDefinition targetMethod = containerMethod.Clone();
                    targetMethod.Name += Joinpoints.OperationJoinPoint.WrappedMethodSuffix + "Body_" + Cil.GetNextId();
                    targetMethod.IsNewSlot = false;
                    targetMethod.IsFinal = false;
                    targetMethod.IsRuntimeSpecialName = targetMethod.IsSpecialName = false;
                    containerType.Methods.Add(targetMethod);

                    // Clear containerMethod
                    containerMethod.Body.InitLocals = true;
                    containerMethod.Body.ExceptionHandlers.Clear();
                    containerMethod.Body.Variables.Clear();
                    containerMethod.Body.Instructions.Clear();

                    // Reify arguments and call interceptors in the original (now target) method
                    EmittingContext ctx = new EmittingContext(containerMethod);
                    VariableDefinition tmpObj = null;

                    if (! Cil.IsStatic(targetMethod)) {
                        ctx.Emit(OpCodes.Ldarg_0);

                        if (targetMethod.DeclaringType.IsValueType) {
                            ctx.Emit(OpCodes.Ldobj, targetMethod.DeclaringType);
                            ctx.Emit(OpCodes.Box, targetMethod.DeclaringType);

                            // Tmp object to store boxed value types when passed along call interceptors and then unwrapped after calls
                            //tmpObj = new VariableDefinition(new ReferenceType(targetMethod.DeclaringType));
                            tmpObj = new VariableDefinition(Cil.GetTypeReference(typeof(object)));
                            containerMethod.Body.Variables.Add(tmpObj);
                            ctx.Emit(OpCodes.Stloc, tmpObj);
                            ctx.Emit(OpCodes.Ldloc, tmpObj);
                        }
                    }

                    VariableDefinition arrayDef = new VariableDefinition(Cil.GetTypeReference(typeof(object[])));
                    containerMethod.Body.Variables.Add(arrayDef);
                    ParameterDefinitionCollection containerParameters = containerMethod.Parameters;
                    ParameterDefinitionCollection targetParameters = targetMethod.Parameters;

                    // Instantiate an array of the right size
                    ctx.Emit(OpCodes.Ldc_I4, containerParameters.Count);
                    ctx.Emit(OpCodes.Newarr, Cil.GetTypeReference(typeof(object)));
                    ctx.Emit(OpCodes.Stloc, arrayDef);

                    // Load the array with data coming from the current parameters
                    for (int i = containerParameters.Count-1; i >= 0; i--) {
                        ParameterDefinition p = containerParameters[i];
                        ctx.Emit(OpCodes.Ldloc, arrayDef);
                        ctx.Emit(OpCodes.Ldc_I4, i);
                        ctx.Emit(OpCodes.Ldarg, p);
                        Cil.BoxIfRequired(p.ParameterType, ctx);
                        ctx.Emit(OpCodes.Stelem_Ref);
                    }

                    // Pass real parameter values (taken from the stack) as the next parameter
                    ctx.Emit(OpCodes.Ldloc, arrayDef);
                    // end of Reify parameters

                    ArrayList interceptors = entry.Value as ArrayList;
                    Cil.InvokeInterceptors(containerMethod, ctx, targetMethod, interceptors);
                    Cil.UnboxIfRequired(targetMethod.ReturnType.ReturnType, ctx);

                    if (!Cil.IsStatic(targetMethod) && targetMethod.DeclaringType.IsValueType) {
                        ctx.Emit(OpCodes.Ldarg_0);
                        ctx.Emit(OpCodes.Ldloc, tmpObj);
                        Cil.UnboxIfRequired(targetMethod.DeclaringType, ctx);
                        ctx.Emit(OpCodes.Stobj, targetMethod.DeclaringType);
                    }

                    // Cast (to satisfy PEVerify)
                    Cil.CastIfRequired(containerMethod.ReturnType.ReturnType, ctx);

                    ctx.Emit(OpCodes.Ret);
                }
            }
        }
コード例 #2
0
ファイル: Cil.cs プロジェクト: pusp/o2platform
 public static void CastIfRequired(TypeReference someType, EmittingContext ctx) {
     if ((someType.FullName != "System.Void" && !someType.IsValueType) || someType.Name.EndsWith("]"))
         ctx.Emit(OpCodes.Castclass, someType);
 }
コード例 #3
0
ファイル: Cil.cs プロジェクト: pusp/o2platform
        public static void InvokeInterceptors(MethodDefinition containerMethod, EmittingContext ctx, MethodReference targetMethod, IList interceptors) {
            // Pass the target method meta-data as the next parameter
            ctx.Emit(OpCodes.Ldtoken, targetMethod);
#if DOTNETTWO
            ctx.Emit(OpCodes.Ldtoken, targetMethod.DeclaringType);
            ctx.Emit(OpCodes.Call, GetGenericMethodFromHandle);
#else
            ctx.Emit(OpCodes.Call, GetMethodFromHandle);
#endif

            // Create the joinpoint
            MethodReference joinPointFactory = 
                IsConstructor(targetMethod) ? ConstructorJoinPointFactory:
                IsStatic(targetMethod) ? StaticMethodJoinPointFactory:
                InstanceMethodJoinPointFactory;
            ctx.Emit(OpCodes.Newobj, joinPointFactory);

            // Duplicate the joinpoint and add each interceptor
            foreach (MethodReference aspectMethod in interceptors) {
                ctx.Emit(OpCodes.Ldtoken, TargetMainModule.Import(aspectMethod));
                ctx.Emit(OpCodes.Call, GetMethodFromHandle);
                ctx.Emit(OpCodes.Call, Cil.AddInterceptorMethod);
            }

            // Invoke "Proceed" on the joinpoint
            ctx.Emit(OpCodes.Call, Cil.ProceedMethod);
        }
コード例 #4
0
ファイル: Cil.cs プロジェクト: pusp/o2platform
 public static void BoxIfRequired(TypeReference typeRef, EmittingContext ctx) {
     if ((typeRef.IsValueType && !typeRef.Name.EndsWith("]")) || typeRef.Name.EndsWith("&")) 
         ctx.Emit(OpCodes.Box, typeRef);
 }
コード例 #5
0
ファイル: Cil.cs プロジェクト: pusp/o2platform
        public static void UnboxIfRequired(TypeReference typeRef, EmittingContext ctx) {
            if (typeRef.FullName == "System.Void") ctx.Emit(OpCodes.Pop);
            else if (typeRef.IsValueType && !typeRef.Name.EndsWith("]")) {
                ctx.Emit(OpCodes.Unbox, typeRef);

                OpCode op = OpCodes.Nop;
                switch (typeRef.FullName) {
                    // Unsigned integers
                    case "System.Boolean":
                    case "System.Byte": op = OpCodes.Ldind_U1; break;
                    case "System.UInt16": op = OpCodes.Ldind_U2; break;
                    case "System.UInt32": op = OpCodes.Ldind_U4; break;
                    case "System.UInt64": op = OpCodes.Ldind_R8; break; // ind U8 is an alias to ind R8. Same opcode

                    // Signed integers
                    case "System.SByte": op = OpCodes.Ldind_I1; break;
                    case "System.Int16": op = OpCodes.Ldind_I2; break;
                    case "System.Int32": op = OpCodes.Ldind_I4; break;
                    case "System.Int64": op = OpCodes.Ldind_I8; break;

                    // Unsigned floating point
                    case "System.Single": op = OpCodes.Ldind_R4; break;
                    case "System.Double": op = OpCodes.Ldind_R8; break;

                    // Unsigned floating point
                    case "System.IntPtr": op = OpCodes.Ldind_I; break;
                }

                if (op != OpCodes.Nop) ctx.Emit(op);
                else { // handle struct unbox
                    ctx.Emit(OpCodes.Ldobj, typeRef);
                    VariableDefinition tmpVar = new VariableDefinition(typeRef);
                    ctx.Method.Body.Variables.Add(tmpVar);
                    ctx.Emit(OpCodes.Stloc, tmpVar);
                    ctx.Emit(OpCodes.Ldloc, tmpVar);
                }
            }
        }
コード例 #6
0
ファイル: Cil.cs プロジェクト: pusp/o2platform
        public static void ReifyParameters(MethodDefinition containerMethod, EmittingContext ctx, IMethodReference targetMethod) {
            int nbTargetParams = targetMethod.Parameters.Count;

            // Interceptor called from a modified constructor (around body) : the first argument is "this", not a param
            if (nbTargetParams == 1 && containerMethod.IsConstructor) 
                ctx.Emit(OpCodes.Ldnull);
            else if (nbTargetParams == 0){
                VariableDefinition arrayDef = new VariableDefinition(GetTypeReference(typeof(object[])));
                containerMethod.Body.Variables.Add(arrayDef);

                ParameterDefinitionCollection currentParameters = containerMethod.Parameters;

                // Instantiate an array of the right size
                ctx.Emit(OpCodes.Ldc_I4, currentParameters.Count);
                ctx.Emit(OpCodes.Newarr, GetTypeReference(typeof(object)));
                ctx.Emit(OpCodes.Stloc, arrayDef);

                // Load the array with data coming from the current parameters
                for (int i = currentParameters.Count - 1; i >= 0; i--) {
                    ctx.Emit(OpCodes.Ldloc, arrayDef);
                    ctx.Emit(OpCodes.Ldc_I4, i);
                    ParameterDefinition p = currentParameters[i];
                    ctx.Emit(OpCodes.Ldarg, p);
                    BoxIfRequired(p.ParameterType, ctx);
                    ctx.Emit(OpCodes.Stelem_Ref);
                }

                // Pass real parameter values (taken from the stack) as the next parameter
                ctx.Emit(OpCodes.Ldloc, arrayDef);
            }
        }
コード例 #7
0
ファイル: AroundCall.cs プロジェクト: pusp/o2platform
        private static void PopulateInterceptor(ToBeWeaved tbw, Instruction call, MethodReference targetMethod, MethodDefinition tplMethod) {
            EmittingContext ctx = new EmittingContext(tplMethod);
            VariableDefinition tmpObj = null;
            int offset = 0;

            // Interceptor signature must be : 
            if (call.OpCode == OpCodes.Newobj) { 
                // new object -> static ctorDeclaringType interceptor(ctorParametersList);
                tplMethod.ReturnType.ReturnType = targetMethod.DeclaringType;
                ctx.Emit(OpCodes.Ldnull); // create a brand new object, don't initialize an existing one
            } else if (Cil.IsStatic(targetMethod)) {  
                // call static method  -> static methodReturnType interceptor(methodParametersList);
                tplMethod.ReturnType.ReturnType = targetMethod.ReturnType.ReturnType;
            } else { 
                //call instance method  -> static methodReturnType interceptor(methodDeclaringType, methodParametersList);
                tplMethod.ReturnType.ReturnType = targetMethod.ReturnType.ReturnType;
                offset = 1;
                ctx.Emit(OpCodes.Ldarg_0); // load "this", which is the first parameter of the tplMethod
                if (!targetMethod.DeclaringType.IsValueType) {
                    tplMethod.Parameters.Add(new ParameterDefinition(targetMethod.DeclaringType));
                } else {
                    tplMethod.Parameters.Add(new ParameterDefinition(new ReferenceType(targetMethod.DeclaringType)));

                    ctx.Emit(OpCodes.Ldobj, targetMethod.DeclaringType);
                    ctx.Emit(OpCodes.Box, targetMethod.DeclaringType);

                    // Tmp object to store boxed value types when passed along call interceptors and then unwrapped after calls
                    //                    tmpObj = new VariableDefinition(new ReferenceType(targetMethod.DeclaringType));
                    tmpObj = new VariableDefinition(Cil.GetTypeReference(typeof(object)));
                    tplMethod.Body.Variables.Add(tmpObj);
                    ctx.Emit(OpCodes.Stloc, tmpObj);
                    ctx.Emit(OpCodes.Ldloc, tmpObj);

                }
            } 

            foreach (ParameterDefinition p in targetMethod.Parameters)
                tplMethod.Parameters.Add(new ParameterDefinition(p.ParameterType));

            ParameterDefinitionCollection tplParameters = tplMethod.Parameters;
            ParameterDefinitionCollection targetParameters = targetMethod.Parameters;

            int nbParams = tplParameters.Count - offset;
            if (nbParams == 0)
                // Load an empty array
                ctx.Emit(OpCodes.Ldnull);
            else {
                // Instantiate an array of the right size
                VariableDefinition arrayDef = new VariableDefinition(Cil.GetTypeReference(typeof(object[])));
                tplMethod.Body.Variables.Add(arrayDef);

                ctx.Emit(OpCodes.Ldc_I4, nbParams);
                ctx.Emit(OpCodes.Newarr, Cil.GetTypeReference(typeof(object)));
                ctx.Emit(OpCodes.Stloc, arrayDef);

                // Load the array with data coming from the current parameters
                for (int i = tplParameters.Count - 1; i >= offset; i--) {
                    ctx.Emit(OpCodes.Ldloc, arrayDef);
                    ctx.Emit(OpCodes.Ldc_I4, i - offset);
                    ParameterDefinition p = tplParameters[i];
                    ctx.Emit(OpCodes.Ldarg, p);
                    Cil.BoxIfRequired(p.ParameterType, ctx);
                    ctx.Emit(OpCodes.Stelem_Ref);
                }
                ctx.Emit(OpCodes.Ldloc, arrayDef);
            }
            // end of reify parameters

            Cil.InvokeInterceptors(tplMethod, ctx, targetMethod, tbw.Interceptors);

            if (call.OpCode != OpCodes.Newobj)
                Cil.UnboxIfRequired(targetMethod.ReturnType.ReturnType, ctx);

            if (call.OpCode != OpCodes.Newobj && !Cil.IsStatic(targetMethod) && targetMethod.DeclaringType.IsValueType) {
                ctx.Emit(OpCodes.Ldarg_0);
                ctx.Emit(OpCodes.Ldloc, tmpObj);
                ctx.Emit(OpCodes.Unbox, targetMethod.DeclaringType);
                ctx.Emit(OpCodes.Ldobj, targetMethod.DeclaringType);
                ctx.Emit(OpCodes.Stobj, targetMethod.DeclaringType);
            }

            // Cast (to satisfy PEVerify)
            Cil.CastIfRequired(tplMethod.ReturnType.ReturnType, ctx);

            ctx.Emit(OpCodes.Ret);
        }
コード例 #8
0
ファイル: AroundField.cs プロジェクト: leftouterjoin/loj-prj1
        private void PopulateInterceptor(ToBeWeaved tbw, Instruction fieldAccessInstruction, FieldReference field, MethodDefinition tplMethod)
        {
            tplMethod.ReturnType.ReturnType = IsGetter ? field.FieldType : Cil.GetTypeReference(typeof(void));

            bool isStaticField = fieldAccessInstruction.OpCode == OpCodes.Stsfld || fieldAccessInstruction.OpCode == OpCodes.Ldsfld;

            // The target object is already on the stack if we access an instance field
            if (!isStaticField)
                if (field.DeclaringType.IsValueType)
                    tplMethod.Parameters.Add(new ParameterDefinition(new ReferenceType(field.DeclaringType)));
                else
                    tplMethod.Parameters.Add(new ParameterDefinition(field.DeclaringType));

            // The value to assign is already on the stack as well
            if (!IsGetter)
                tplMethod.Parameters.Add(new ParameterDefinition(field.FieldType));

            EmittingContext ctx = new EmittingContext(tplMethod);

            VariableDefinition tmpObj = null;
            if (!isStaticField) {
                ctx.Emit(OpCodes.Ldarg_0); // load "this", which is the first parameter of the tplMethod

                if (field.DeclaringType.IsValueType) {
                    ctx.Emit(OpCodes.Ldobj, field.DeclaringType);
                    ctx.Emit(OpCodes.Box, field.DeclaringType);

                    // Tmp object to store boxed value types when passed along call interceptors and then unwrapped after calls
            //                    tmpObj = new VariableDefinition(new ReferenceType(field.DeclaringType));
                    tmpObj = new VariableDefinition(Cil.GetTypeReference(typeof(object)));
                    tplMethod.Body.Variables.Add(tmpObj);
                    ctx.Emit(OpCodes.Stloc, tmpObj);
                    ctx.Emit(OpCodes.Ldloc, tmpObj);
                }

                if (!IsGetter) {
                    ctx.Emit(OpCodes.Ldarg, tplMethod.Parameters[1]);
                    Cil.BoxIfRequired(field.FieldType, ctx);
                }
            } else { // Static field
                if (!IsGetter) {
                    ctx.Emit(OpCodes.Ldarg, tplMethod.Parameters[0]);
                    Cil.BoxIfRequired(field.FieldType, ctx);
                }
            }

            // Pass the field representation as the last parameter
            ctx.Emit(OpCodes.Ldtoken, field);
            #if DOTNETTWO
            ctx.Emit(OpCodes.Ldtoken, field.DeclaringType);
            ctx.Emit(OpCodes.Call, Cil.GetGenericFieldFromHandle);
            #else
            ctx.Emit(OpCodes.Call, Cil.GetFieldFromHandle);
            #endif

            // Create the JoinPoint
            MethodReference joinPointFactory;
            OpCode opCode = fieldAccessInstruction.OpCode;
            if (opCode == OpCodes.Stsfld) joinPointFactory = Cil.StaticFieldSetterJoinPointFactory;
            else if (opCode == OpCodes.Ldsfld) joinPointFactory = Cil.StaticFieldGetterJoinPointFactory;
            else if (opCode == OpCodes.Stfld) joinPointFactory = Cil.FieldSetterJoinPointFactory;
            else if (opCode == OpCodes.Ldfld) joinPointFactory = Cil.FieldGetterJoinPointFactory;
            else throw new NotSupportedException("This kind of field accessor is not supported : " + opCode);

            ctx.Emit(OpCodes.Newobj, joinPointFactory);

            // Add each interceptor
            foreach (MethodReference aspectMethod in tbw.Interceptors) {
                ctx.Emit(OpCodes.Ldtoken, Cil.TargetMainModule.Import(aspectMethod));
                ctx.Emit(OpCodes.Call, Cil.GetMethodFromHandle);
                ctx.Emit(OpCodes.Call, Cil.AddInterceptorMethod);
            }

            // Invoke "proceed" on the joinpoint
            ctx.Emit(OpCodes.Call, Cil.ProceedMethod);
            Cil.UnboxIfRequired(tplMethod.ReturnType.ReturnType, ctx);

            if (! isStaticField && field.DeclaringType.IsValueType) { // Unbox and update "this"
                ctx.Emit(OpCodes.Ldarg_0);
                ctx.Emit(OpCodes.Ldloc, tmpObj);
                ctx.Emit(OpCodes.Unbox, field.DeclaringType);
                ctx.Emit(OpCodes.Ldobj, field.DeclaringType);
                ctx.Emit(OpCodes.Stobj, field.DeclaringType);
            }

            // Cast (to satisfy PEVerify)
            Cil.CastIfRequired(tplMethod.ReturnType.ReturnType, ctx);

            ctx.Emit(OpCodes.Ret);
        }