/// <summary> /// Add switch registering to a class. /// </summary> /// <param name="clazz">The class to register switch.</param> /// <param name="context">The weaving context.</param> /// <param name="switchData">Data of switches.</param> /// <param name="statistics">Weaving statistics.</param> public static void Weave(TypeDefinition clazz, IWeavingContext context, IReadOnlyList <SwitchInitializingData> switchData, IClassWeavingStatisticsBuilder statistics) { #if DEBUG if (clazz == null) { throw new ArgumentNullException("clazz"); } if (context == null) { throw new ArgumentNullException("context"); } if (switchData == null || !switchData.Any()) { throw new ArgumentNullException("switchData"); } if (statistics == null) { throw new ArgumentNullException("statistics"); } #endif var staticConstructor = clazz.Methods.FirstOrDefault(mthd => mthd.IsStaticConstructor()); MethodDefinition method = null; ILProcessor processor = null; if (staticConstructor == null) { method = new MethodDefinition( ".cctor", MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, context.GetTypeReference(typeof(void))); processor = method.Body.GetILProcessor(); method.Body.Instructions.Add(processor.Create(OpCodes.Ret)); clazz.Methods.Add(method); } else { method = staticConstructor; processor = method.Body.GetILProcessor(); } var typeName = clazz.GetFullName(); var instructions = new List <Instruction>(); foreach (var data in switchData) { RegisterSwitch(instructions, processor, context, data, typeName); statistics.AddSwitchWeavingRecord(StatisticsFactory.InitializeSwitchWeavingRecord(typeName, data.Property, data.MethodSignature, data.Aspect, data.Field.Name, data.Value)); } CompleteSwitchRegistration(method, instructions, processor, context, typeName); }
private void CallAdvice(MethodDefinition method, ILProcessor processor, IAdviceInfo advice, List <Instruction> instructions, string propertyName, string methodSignature) { if (advice == null) { throw new ArgumentNullException("advice"); } var pendingSwitchIndex = context.PendingSwitchIndex; var firstIndex = instructions.Count; var needContextVariable = advice.ParameterFlag.Contains(AdviceParameterFlag.Context); var needExecutionVariable = advice.ParameterFlag.Contains(AdviceParameterFlag.Execution); var needReturnVariable = advice.ParameterFlag.Contains(AdviceParameterFlag.Return); if (advice.IsSwitchedOn.HasValue) { var field = switchHandlerBuilder.GetSwitchField( propertyName, methodSignature, advice.AspectName, advice.IsSwitchedOn.Value); var index = context.GetLocalVariableForField(field); if (index < 0) { index = method.Body.Variables.Count; method.Body.Variables.Add(new VariableDefinition(context.GetTypeReference(typeof(bool)))); context.RecordLocalVariableForField(field, index); } if (needContextVariable) { context.ExecutionContextSwitches.RegisterSwitch(index); } if (needExecutionVariable) { context.ExecutionSwitches.RegisterSwitch(index); } if (needReturnVariable) { context.ReturnSwitches.RegisterSwitch(index); } instructions.Add(processor.Create(OpCodes.Ldloc, index)); // the null instruction is to be filled in later context.PendingSwitchIndex = instructions.Count; instructions.Add(null); } else { if (needContextVariable) { context.ExecutionContextSwitches.SetUnSwitchable(); } if (needExecutionVariable) { context.ExecutionSwitches.SetUnSwitchable(); } if (needReturnVariable) { context.ReturnSwitches.SetUnSwitchable(); } } if (needContextVariable) { instructions.Add(processor.Create(OpCodes.Ldloc, context.ExecutionContextVariableIndex)); } if (needExecutionVariable) { instructions.Add(processor.Create(OpCodes.Ldloc, context.ExecutionVariableIndex)); } if (advice.ParameterFlag.Contains(AdviceParameterFlag.Exception)) { instructions.Add(processor.Create(OpCodes.Ldloc, context.ExceptionVariableIndex)); } if (needReturnVariable) { instructions.Add(processor.Create(OpCodes.Ldloc, context.ReturnVariableIndex)); } if (advice.ParameterFlag.Contains(AdviceParameterFlag.HasException)) { instructions.Add(processor.Create(OpCodes.Ldloc, context.HasExceptionVariableIndex)); } instructions.Add(processor.Create(OpCodes.Call, context.GetMethodReference(advice.Advice))); // apply switch from last advice call if (pendingSwitchIndex >= 0) { // here brfalse_S is safe, considering only several instructions are inserted after break instruction. instructions[pendingSwitchIndex] = processor.Create(OpCodes.Brfalse_S, instructions[firstIndex]); // reset pending switch index if no switch this time if (!advice.IsSwitchedOn.HasValue) { context.PendingSwitchIndex = -1; } } }