private void WeavePropertySetter(MethodDefinition setter, MethodReference propertyGet)
        {
            setter.Body.InitLocals = true;
            setter.Body.SimplifyMacros();

            if (propertyGet.DeclaringType.HasGenericParameters)
            {
                propertyGet = propertyGet.MakeHostInstanceGeneric(propertyGet.DeclaringType.GenericParameters.Cast <TypeReference>().ToArray());
            }

            Instruction firstInstruction = setter.Body.Instructions.First();
            ILProcessor processor        = setter.Body.GetILProcessor();

            // Add local variables
            int cacheKeyIndex = setter.AddVariable(ModuleDefinition.TypeSystem.String);

            // Generate CacheKeyTemplate
            string cacheKey = CreateCacheKeyString(setter);

            Instruction current = firstInstruction.Prepend(processor.Create(OpCodes.Ldstr, cacheKey), processor);

            // Create set cache key
            current = current.AppendStloc(processor, cacheKeyIndex);

            current = InjectCacheKeyCreatedCode(setter, current, processor, cacheKeyIndex);

            if (LogDebugOutput)
            {
                current = AppendDebugWrite(current, processor, "Clearing cache.");
            }

            if (!propertyGet.Resolve().IsStatic)
            {
                current = current.AppendLdarg(processor, 0);
            }

            current
            .Append(processor.Create(OpCodes.Call, setter.Module.Import(propertyGet)), processor)
            .AppendLdloc(processor, cacheKeyIndex)
            .Append(processor.Create(OpCodes.Callvirt, setter.Module.Import(
                                         CacheTypeGetRemoveMethod(propertyGet.ReturnType.Resolve(), CacheTypeRemoveMethodName))), processor);

            setter.Body.OptimizeMacros();
        }
        private void WeavePropertySetter(MethodDefinition setter, MethodDefinition propertyGet)
        {
            setter.Body.InitLocals = true;
            setter.Body.SimplifyMacros();

            Instruction firstInstruction = setter.Body.Instructions.First();
            ILProcessor processor        = setter.Body.GetILProcessor();

            // Add local variables
            int cacheKeyIndex = setter.AddVariable <string>();

            // Generate CacheKeyTemplate
            string cacheKey = CreateCacheKeyString(setter);

            Instruction current = firstInstruction.Prepend(processor.Create(OpCodes.Ldstr, cacheKey), processor);

            // Create set cache key
            current = current.AppendStloc(processor, cacheKeyIndex);

            current = InjectCacheKeyCreatedCode(setter, current, processor, cacheKeyIndex);

            if (LogDebugOutput)
            {
                current = current.AppendDebugWrite(processor, "Clearing cache.", ModuleDefinition);
            }

            if (!setter.IsStatic)
            {
                current = current.AppendLdarg(processor, 0);
            }

            current.Append(processor.Create(OpCodes.Call, setter.Module.Import(propertyGet)), processor)
            .AppendLdloc(processor, cacheKeyIndex)
            .Append(
                processor.Create(OpCodes.Callvirt,
                                 setter.Module.Import(CacheTypeGetRemoveMethod(propertyGet.ReturnType.Resolve(), CacheTypeRemoveMethodName))),
                processor);

            setter.Body.OptimizeMacros();
        }
Exemple #3
0
 static public VariableDefinition AddVariableOfReturnType(this MethodDefinition item)
 {
     return(item.AddVariable(new VariableDefinition(item.ReturnType)));
 }
Exemple #4
0
        private void WeaveMethod(MethodDefinition methodDefinition, MethodDefinition propertyGet)
        {
            methodDefinition.Body.InitLocals = true;

            methodDefinition.Body.SimplifyMacros();

            Instruction firstInstruction = methodDefinition.Body.Instructions.First();

            ICollection <Instruction> returnInstructions =
                methodDefinition.Body.Instructions.ToList().Where(x => x.OpCode == OpCodes.Ret).ToList();

            if (returnInstructions.Count == 0)
            {
                LogWarning(string.Format("Method {0} does not contain any return statement. Skip weaving of method {0}.",
                                         methodDefinition.Name));
                return;
            }

            // Add local variables
            int cacheKeyIndex    = methodDefinition.AddVariable(ModuleDefinition.TypeSystem.String);
            int resultIndex      = methodDefinition.AddVariable(methodDefinition.ReturnType);
            int objectArrayIndex = methodDefinition.AddVariable(ModuleDefinition.TypeSystem.Object.MakeArrayType());

            ILProcessor processor = methodDefinition.Body.GetILProcessor();

            // Generate CacheKeyTemplate
            string cacheKey = CreateCacheKeyString(methodDefinition);

            Instruction current = firstInstruction.Prepend(processor.Create(OpCodes.Ldstr, cacheKey), processor);

            current = SetCacheKeyLocalVariable(current, methodDefinition, processor, cacheKeyIndex, objectArrayIndex);

            current = InjectCacheKeyCreatedCode(methodDefinition, current, processor, cacheKeyIndex);

            TypeDefinition propertyGetReturnTypeDefinition = propertyGet.ReturnType.Resolve();

            if (!methodDefinition.IsStatic)
            {
                current = current.AppendLdarg(processor, 0);
            }

            MethodReference methodReferenceContain =
                methodDefinition.Module.Import(CacheTypeGetContainsMethod(propertyGetReturnTypeDefinition,
                                                                          CacheTypeContainsMethodName));

            current =
                current.Append(processor.Create(OpCodes.Call, methodDefinition.Module.Import(propertyGet)), processor)
                .AppendLdloc(processor, cacheKeyIndex)
                .Append(processor.Create(OpCodes.Callvirt, methodReferenceContain), processor)
                .Append(processor.Create(OpCodes.Brfalse, firstInstruction), processor);

            // False branche (store value in cache of each return instruction)
            foreach (Instruction returnInstruction in returnInstructions)
            {
                returnInstruction.Previous.AppendStloc(processor, resultIndex);

                if (LogDebugOutput)
                {
                    AppendDebugWrite(returnInstruction.Previous, processor, "Storing to cache.");
                }

                if (!methodDefinition.IsStatic)
                {
                    returnInstruction.Previous.AppendLdarg(processor, 0);
                }

                MethodReference methodReferenceReturn =
                    methodDefinition.Module.Import(CacheTypeGetStoreMethod(propertyGetReturnTypeDefinition, CacheTypeStoreMethodName));

                returnInstruction.Previous.Append(processor.Create(OpCodes.Call, methodDefinition.Module.Import(propertyGet)),
                                                  processor)
                .AppendLdloc(processor, cacheKeyIndex)
                .AppendLdloc(processor, resultIndex)
                .AppendBoxIfNecessary(processor, methodDefinition.ReturnType)
                .Append(processor.Create(OpCodes.Callvirt, methodReferenceReturn), processor)
                .AppendLdloc(processor, resultIndex);
            }

            if (LogDebugOutput)
            {
                current = AppendDebugWrite(current, processor, "Loading from cache.");
            }

            if (!methodDefinition.IsStatic)
            {
                current = current.AppendLdarg(processor, 0);
            }

            // Start of branche true
            MethodReference methodReferenceRetrieve =
                methodDefinition.Module.Import(CacheTypeGetRetrieveMethod(propertyGetReturnTypeDefinition,
                                                                          CacheTypeRetrieveMethodName)).MakeGeneric(new[] { methodDefinition.ReturnType });

            current.Append(processor.Create(OpCodes.Call, methodDefinition.Module.Import(propertyGet)), processor)
            .AppendLdloc(processor, cacheKeyIndex)
            .Append(processor.Create(OpCodes.Callvirt, methodReferenceRetrieve), processor)
            .AppendStloc(processor, resultIndex)
            .Append(processor.Create(OpCodes.Br, returnInstructions.Last().Previous), processor);

            methodDefinition.Body.OptimizeMacros();
        }
Exemple #5
0
 public int AddVariable <T>()
 {
     return(_methodDefinition.AddVariable <T>());
 }
        private void WeaveMethod(MethodDefinition methodDefinition, CustomAttribute attribute, MethodReference propertyGet)
        {
            methodDefinition.Body.InitLocals = true;

            methodDefinition.Body.SimplifyMacros();

            if (propertyGet.DeclaringType.HasGenericParameters)
            {
                propertyGet = propertyGet.MakeHostInstanceGeneric(propertyGet.DeclaringType.GenericParameters.Cast <TypeReference>().ToArray());
            }

            Instruction firstInstruction = methodDefinition.Body.Instructions.First();

            ICollection <Instruction> returnInstructions =
                methodDefinition.Body.Instructions.ToList().Where(x => x.OpCode == OpCodes.Ret).ToList();

            if (returnInstructions.Count == 0)
            {
                LogWarning(string.Format("Method {0} does not contain any return statement. Skip weaving of method {0}.",
                                         methodDefinition.Name));
                return;
            }

            // Add local variables
            int cacheKeyIndex    = methodDefinition.AddVariable(ModuleDefinition.TypeSystem.String);
            int resultIndex      = methodDefinition.AddVariable(methodDefinition.ReturnType);
            int objectArrayIndex = methodDefinition.AddVariable(ModuleDefinition.TypeSystem.Object.MakeArrayType());

            ILProcessor processor = methodDefinition.Body.GetILProcessor();

            // Generate CacheKeyTemplate
            string cacheKey = CreateCacheKeyString(methodDefinition);

            Instruction current = firstInstruction.Prepend(processor.Create(OpCodes.Ldstr, cacheKey), processor);

            current = SetCacheKeyLocalVariable(current, methodDefinition, processor, cacheKeyIndex, objectArrayIndex);

            current = InjectCacheKeyCreatedCode(methodDefinition, current, processor, cacheKeyIndex);

            TypeDefinition propertyGetReturnTypeDefinition = propertyGet.ReturnType.Resolve();

            if (!propertyGet.Resolve().IsStatic)
            {
                current = current.AppendLdarg(processor, 0);
            }

            MethodReference methodReferenceContain =
                methodDefinition.Module.Import(CacheTypeGetContainsMethod(propertyGetReturnTypeDefinition,
                                                                          CacheTypeContainsMethodName));

            current = current
                      .Append(processor.Create(OpCodes.Call, methodDefinition.Module.Import(propertyGet)), processor)
                      .AppendLdloc(processor, cacheKeyIndex)
                      .Append(processor.Create(OpCodes.Callvirt, methodReferenceContain), processor)
                      .Append(processor.Create(OpCodes.Brfalse, firstInstruction), processor);

            // False branche (store value in cache of each return instruction)
            foreach (Instruction returnInstruction in returnInstructions)
            {
                returnInstruction.Previous.AppendStloc(processor, resultIndex);

                if (LogDebugOutput)
                {
                    AppendDebugWrite(returnInstruction.Previous, processor, "Storing to cache.");
                }

                if (!propertyGet.Resolve().IsStatic)
                {
                    returnInstruction.Previous.AppendLdarg(processor, 0);
                }

                MethodReference methodReferenceStore =
                    methodDefinition.Module.Import(CacheTypeGetStoreMethod(propertyGetReturnTypeDefinition, CacheTypeStoreMethodName));

                returnInstruction.Previous
                .Append(processor.Create(OpCodes.Call, methodDefinition.Module.Import(propertyGet)), processor)
                .AppendLdloc(processor, cacheKeyIndex)
                .AppendLdloc(processor, resultIndex)
                .AppendBoxIfNecessary(processor, methodDefinition.ReturnType);

                // Pass parameters to Store method if supported
                if (methodReferenceStore.Parameters.Count == 3)
                {
                    returnInstruction.Previous
                    .Append(processor.Create(OpCodes.Newobj,
                                             methodDefinition.Module.Import(References.DictionaryConstructor)), processor);

                    foreach (CustomAttributeNamedArgument property in attribute.Properties.Union(attribute.Fields))
                    {
                        returnInstruction.Previous
                        .AppendDup(processor)
                        .AppendLdstr(processor, property.Name)
                        .AppendLd(processor, property.Argument, References)
                        .AppendBoxIfNecessary(processor,
                                              property.Argument.Type != ModuleDefinition.TypeSystem.Object
                                                                        ? property.Argument.Type : ((CustomAttributeArgument)property.Argument.Value).Type)
                        .Append(processor.Create(OpCodes.Callvirt, methodDefinition.Module.Import(References.DictionaryAddMethod)),
                                processor);
                    }
                }

                returnInstruction.Previous
                .Append(processor.Create(OpCodes.Callvirt, methodReferenceStore), processor)
                .AppendLdloc(processor, resultIndex);
            }

            if (LogDebugOutput)
            {
                current = AppendDebugWrite(current, processor, "Loading from cache.");
            }

            if (!propertyGet.Resolve().IsStatic)
            {
                current = current.AppendLdarg(processor, 0);
            }

            // Start of branche true
            MethodReference methodReferenceRetrieve =
                methodDefinition.Module.Import(CacheTypeGetRetrieveMethod(propertyGetReturnTypeDefinition,
                                                                          CacheTypeRetrieveMethodName)).MakeGeneric(new[] { methodDefinition.ReturnType });

            current.Append(processor.Create(OpCodes.Call, methodDefinition.Module.Import(propertyGet)), processor)
            .AppendLdloc(processor, cacheKeyIndex)
            .Append(processor.Create(OpCodes.Callvirt, methodReferenceRetrieve), processor)
            .AppendStloc(processor, resultIndex)
            .Append(processor.Create(OpCodes.Br, returnInstructions.Last().Previous), processor);

            methodDefinition.Body.OptimizeMacros();
        }
Exemple #7
0
        void InjectContext(ILProcessor processor, Instruction firstInstruction, MethodDefinition method, ReferenceContainer references)
        {
            /*
             * nop
             * ldstr "Namespace.Class.Method"
             * ldc.i4.1
             * newarr object
             * stloc.s CS$0$0001
             * ldloc.s CS$0$0001
             * ldc.i4.0
             * ldarg.1
             * box int32
             * stelem.ref
             * ldloc.s CS$0$0001
             * call class [Yalf]Yalf.IContext [Yalf]Yalf.Log::MethodContext(string, object[])
             * stloc.0
             */

            contextVar = new VariableDefinition(references.IContextType);
            body.Variables.Insert(0, contextVar);

            int objectParamsArrayIndex = method.AddVariable <object[]>();

            // Generate MethodContext calling method name
            var builder = new StringBuilder();

            builder.Append(string.Join(".",
                                       method.DeclaringType.Namespace,
                                       FormatType(method.DeclaringType),
                                       FormatMethod(method)));

            var current = firstInstruction
                          .Prepend(processor.Create(OpCodes.Ldstr, builder.ToString()), processor);

            // Create object[] for MethodContext
            current = current
                      .AppendLdcI4(processor, method.Parameters.Count)
                      .Append(processor.Create(OpCodes.Newarr, method.Module.ImportType <object>()), processor)
                      .AppendStloc(processor, objectParamsArrayIndex);

            var nonStaticMethodAddOne = method.IsStatic ? 0 : 1;

            // Set object[] values
            for (int i = 0; i < method.Parameters.Count; i++)
            {
                current = current
                          .AppendLdloc(processor, objectParamsArrayIndex)
                          .AppendLdcI4(processor, i);

                var paramType = method.Parameters[i].ParameterType;

                if (paramType.MetadataType == MetadataType.UIntPtr ||
                    paramType.MetadataType == MetadataType.FunctionPointer ||
                    paramType.MetadataType == MetadataType.IntPtr ||
                    paramType.MetadataType == MetadataType.Pointer)
                {
                    // don't store pointer types into object[] (we can't ToString them anyway)
                    // store type name as string instead
                    current = current.AppendLdstr(processor, paramType.FullName);
                }
                else
                {
                    current = current
                              .AppendLdarg(processor, i + nonStaticMethodAddOne)
                              .AppendBoxAndResolveRefIfNecessary(processor, paramType);
                }

                current = current.Append(processor.Create(OpCodes.Stelem_Ref), processor);
            }

            // Call Log.MethodContext
            current
            .AppendLdloc(processor, objectParamsArrayIndex)
            .Append(processor.Create(OpCodes.Call, references.MethodContextMethod), processor)
            .AppendStloc(processor, contextVar.Index);
        }