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(); }
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(); }
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(); }