private Instruction ApplySwitches(ILProcessor processor, IReadOnlyList <int> switches, ISwitchableSection section) { if (switches != null && switches.Any() && section.HasSetStartEndInstruction) { var count = switches.Count; var instructions = new List <Instruction>(count * 2); var sectionOffset = GetTransferOffset(section.StartInstruction, section.EndInstruction); var offset = 0; var instruction = processor.Create(OffsetIsShort(sectionOffset) ? OpCodes.Brfalse_S : OpCodes.Brfalse, section.EndInstruction); offset += instruction.GetSize(); instructions.Add(instruction); instruction = processor.Create(OpCodes.Ldloc, switches[count - 1]); offset += instruction.GetSize(); instructions.Add(instruction); for (var i = count - 2; i >= 0; i--) { instruction = processor.Create(OffsetIsShort(offset) ? OpCodes.Brtrue_S : OpCodes.Brtrue, section.StartInstruction); offset += instruction.GetSize(); instructions.Add(instruction); instruction = processor.Create(OpCodes.Ldloc, switches[i]); offset += instruction.GetSize(); instructions.Add(instruction); } instructions.Reverse(); var result = instructions.First(); IlUtilities.PersistentInstructions(instructions, processor, section.StartInstruction); return(result); } return(null); }
private void CompleteWeavingException(MethodDefinition method, List <Instruction> instructions, ILProcessor processor) { if (instructions.Any()) { FixReturnInstructions(method, processor); var rethrowInstruction = processor.Create(OpCodes.Rethrow); processor.InsertBefore(context.EndingInstruction, rethrowInstruction); var handleExceptionInstruction = context.ExceptionVariableIndex >= 0 ? processor.Create(OpCodes.Stloc, context.ExceptionVariableIndex) : processor.Create(OpCodes.Pop); processor.InsertBefore(rethrowInstruction, handleExceptionInstruction); // apply switch from last advice call if (context.PendingSwitchIndex >= 0) { // here Brfalse_S is safe considering only several instructions are inserted after break instruction. instructions[context.PendingSwitchIndex] = processor.Create(OpCodes.Brfalse_S, rethrowInstruction); context.PendingSwitchIndex = -1; } // instruction persistent IlUtilities.PersistentInstructions(instructions, processor, rethrowInstruction); var handler = new ExceptionHandler(ExceptionHandlerType.Catch) { CatchType = context.GetTypeReference(typeof(Exception)), TryStart = context.TryStartInstruction, TryEnd = handleExceptionInstruction, HandlerStart = handleExceptionInstruction, HandlerEnd = context.EndingInstruction, }; context.ExceptionHandlerIndex = method.Body.ExceptionHandlers.Count; method.Body.ExceptionHandlers.Add(handler); } }
private static void CompleteSwitchRegistration(MethodDefinition method, List <Instruction> instructions, ILProcessor processor, IWeavingContext context, string clazz) { instructions.Add(processor.Create(OpCodes.Call, context.BaseReference.BackStage.BuilderGetterReference)); instructions.Add(processor.Create(OpCodes.Ldstr, clazz)); instructions.Add(processor.Create(OpCodes.Callvirt, context.BaseReference.Builder.CompleteMethod)); IlUtilities.PersistentInstructions(instructions, processor, method.Body.Instructions.First()); }
private void WeaveSwitchInitialization(MethodDefinition method, ILProcessor processor) { var instructions = new List <Instruction>(); var dict = context.LocalVariableSwitchFieldDictionary; if (dict.Any()) { foreach (var fieldVariable in dict) { instructions.Add(processor.Create(OpCodes.Call, context.BaseReference.BackStage.GlancerGetterReference)); instructions.Add(processor.Create(OpCodes.Ldsfld, fieldVariable.Key)); instructions.Add(processor.Create(OpCodes.Callvirt, context.BaseReference.Glancer.IsOnMethod)); instructions.Add(processor.Create(OpCodes.Stloc, fieldVariable.Value)); } IlUtilities.PersistentInstructions(instructions, processor, method.Body.Instructions.First()); } // hasException is only one bool value, swithcing it on and off costs more than just leaving it being set, don't switch it var executionVariableSwitches = context.ExecutionSwitches.Switches; var returnVariableSwitches = context.ReturnSwitches.Switches; var executionContextVariableSwitches = context.ExecutionContextSwitches.Switches; // inject with reverse order from declaration to adjust jump to statement // local variables var originalStart = context.ReturnVariableSwitchableSection.StartInstruction; var newStart = ApplySwitches(processor, returnVariableSwitches, context.ReturnVariableSwitchableSection); if (newStart != null) { context.ExecutionVariableSwitchableSection.AdjustEndInstruction(originalStart, newStart); } originalStart = context.ExecutionVariableSwitchableSection.StartInstruction ?? originalStart; newStart = ApplySwitches(processor, executionVariableSwitches, context.ExecutionVariableSwitchableSection) ?? newStart; if (newStart != null) { context.ExecutionContextVariableSwitchableSection.AdjustEndInstruction(originalStart, newStart); } ApplySwitches(processor, executionContextVariableSwitches, context.ExecutionContextVariableSwitchableSection); // finally block originalStart = context.ReturnFinallySwitchableSection.StartInstruction; newStart = ApplySwitches(processor, returnVariableSwitches, context.ReturnFinallySwitchableSection); // new start can't be null if original start isn't null if (newStart != null) { AdjustExceptionFinallyBorder(method, originalStart, newStart); } }
private void CompleteAddingLocalVariableInstructions(MethodDefinition method, List <Instruction> instructions, ILProcessor processor) { if (instructions.Any()) { method.Body.InitLocals = true; } context.TryStartInstruction = method.Body.Instructions.First(); context.ExecutionContextVariableSwitchableSection.SetInstructions(instructions, context.TryStartInstruction); context.ExecutionVariableSwitchableSection.SetInstructions(instructions, context.TryStartInstruction); context.ReturnVariableSwitchableSection.SetInstructions(instructions, context.TryStartInstruction); IlUtilities.PersistentInstructions(instructions, processor, context.TryStartInstruction); }
private void CompleteWeavingExit(MethodDefinition method, List <Instruction> instructions, ILProcessor processor) { if (instructions.Any()) { // must add end finally instruction at the end var endFinally = processor.Create(OpCodes.Endfinally); instructions.Add(endFinally); FixReturnInstructions(method, processor); // return variable switching context.ReturnFinallySwitchableSection.SetInstructions(instructions, endFinally); // apply switch from last advice call if (context.PendingSwitchIndex >= 0) { // here Brfalse_S is safe considering only several instructions are inserted after break instruction. instructions[context.PendingSwitchIndex] = processor.Create(OpCodes.Brfalse_S, endFinally); context.PendingSwitchIndex = -1; } var tryEndInstruction = instructions.First(); IlUtilities.PersistentInstructions(instructions, processor, context.EndingInstruction); // if catch block exists, it's handler end must be updated if (context.ExceptionHandlerIndex >= 0) { method.Body.ExceptionHandlers[context.ExceptionHandlerIndex].HandlerEnd = tryEndInstruction; } context.FinallyHandlerIndex = method.Body.ExceptionHandlers.Count; var handler = new ExceptionHandler(ExceptionHandlerType.Finally) { CatchType = context.GetTypeReference(typeof(Exception)), TryStart = context.TryStartInstruction, TryEnd = tryEndInstruction, HandlerStart = tryEndInstruction, HandlerEnd = context.EndingInstruction, }; method.Body.ExceptionHandlers.Add(handler); } }
private void CompleteWeavingEntry(List <Instruction> instructions, ILProcessor processor) { // apply switch from last advice call if (context.PendingSwitchIndex >= 0) { // here Brfalse_S is safe considering only several instructions are inserted after break instruction. instructions[context.PendingSwitchIndex] = processor.Create(OpCodes.Brfalse_S, context.TryStartInstruction); context.PendingSwitchIndex = -1; } var firstEntryInstruction = instructions.FirstOrDefault(); IlUtilities.PersistentInstructions(instructions, processor, context.TryStartInstruction); if (firstEntryInstruction != null) { var originalTryStart = context.TryStartInstruction; context.TryStartInstruction = firstEntryInstruction; context.ExecutionContextVariableSwitchableSection.AdjustEndInstruction(originalTryStart, firstEntryInstruction); context.ExecutionVariableSwitchableSection.AdjustEndInstruction(originalTryStart, firstEntryInstruction); context.ReturnVariableSwitchableSection.AdjustEndInstruction(originalTryStart, firstEntryInstruction); } }
private void AddExecutionVariable(MethodDefinition method, List <Instruction> instructions, ILProcessor processor) { // evaluation stack: bottom method.Body.Variables.Add(new VariableDefinition(context.BaseReference.Execution.TypeReference)); context.ExecutionVariableSwitchableSection.StartIndex = instructions.Count; instructions.Add(processor.Create(OpCodes.Ldstr, method.Module.Assembly.FullName)); instructions.Add(processor.Create(OpCodes.Ldstr, method.DeclaringType.Namespace)); instructions.Add(processor.Create(OpCodes.Ldstr, method.DeclaringType.FullName)); instructions.Add(processor.Create(OpCodes.Ldstr, method.DeclaringType.Name)); if (method.HasThis) { instructions.Add(processor.Create(OpCodes.Ldarg_0)); instructions.Add(processor.Create(OpCodes.Callvirt, context.GetMethodReference(getHashCodeMethod))); } else { instructions.Add(processor.Create(OpCodes.Ldc_I4_0)); } instructions.Add(processor.Create(OpCodes.Ldstr, method.FullName)); instructions.Add(processor.Create(OpCodes.Ldstr, method.Name)); instructions.Add(processor.Create(OpCodes.Ldstr, method.ReturnType.FullName)); // evaluation stack after the following statement: bottom->ICanAddParameters instructions.Add(processor.Create(OpCodes.Call, context.BaseReference.MetadataFactory.InitializeExecutionMethod)); if (method.HasParameters) { foreach (var parameter in method.Parameters) { // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters instructions.Add(processor.Create(OpCodes.Dup)); instructions.Add(processor.Create(OpCodes.Ldstr, parameter.Name)); instructions.Add(processor.Create(OpCodes.Ldstr, parameter.ParameterType.FullName)); instructions.Add(processor.Create(OpCodes.Ldc_I4, parameter.Sequence)); instructions.Add(processor.Create(OpCodes.Ldarg, parameter.Sequence)); // insert indirect load instruction if (parameter.ParameterType.IsByReference && parameter.ParameterType is TypeSpecification) { instructions.Add(processor.CreateIndirectLoadInstruction(parameter.ParameterType)); } // insert box instruction if (parameter.ParameterType.IsValueType) { instructions.Add(processor.CreateBoxValueTypeInstruction(parameter.ParameterType)); } // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->ICanAddCustomAttribute instructions.Add(processor.Create(OpCodes.Call, context.BaseReference.MetadataFactory.InitializeParameterMethod)); if (parameter.HasCustomAttributes) { for (var i = 0; i < parameter.CustomAttributes.Count; i++) { var attribute = parameter.CustomAttributes[i]; // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->ICanAddCustomAttribute->ICanAddCustomAttribute instructions.Add(processor.Create(OpCodes.Dup)); instructions.Add(processor.Create(OpCodes.Ldstr, attribute.AttributeType.FullName)); instructions.Add(processor.Create(OpCodes.Ldc_I4, i)); // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->ICanAddCustomAttribute->ICanAddCustomAttribute->ICanAddAttributeProperty instructions.Add(processor.Create(OpCodes.Call, context.BaseReference.MetadataFactory.InitializeCustomAttributeMethod)); if (attribute.HasProperties) { for (var j = 0; j < attribute.Properties.Count; j++) { var property = attribute.Properties[j]; if (IlUtilities.CustomAttributePropertyTypeIsSupported(property.Argument)) { // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->ICanAddCustomAttribute->ICanAddCustomAttribute->ICanAddAttributeProperty->ICanAddAttributeProperty instructions.Add(processor.Create(OpCodes.Dup)); instructions.Add(processor.Create(OpCodes.Ldstr, property.Name)); instructions.Add(processor.Create(OpCodes.Ldstr, property.Argument.Type.FullName)); instructions.Add(processor.Create(OpCodes.Ldc_I4, j)); instructions.Add(processor.CreateLoadCustomAttributePropertyValueInstruction(property.Argument)); if (property.Argument.Type.IsValueType) { instructions.Add(processor.CreateBoxValueTypeInstruction(property.Argument.Type)); } // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->ICanAddCustomAttribute->ICanAddCustomAttribute->ICanAddAttributeProperty->ICanAddAttributeProperty->IAttributeProperty instructions.Add(processor.Create(OpCodes.Call, context.BaseReference.MetadataFactory.InitializeAttributePropertyMethod)); // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->ICanAddCustomAttribute->ICanAddCustomAttribute->ICanAddAttributeProperty instructions.Add(processor.Create(OpCodes.Callvirt, context.BaseReference.CustomAttribute.AddAttributePropertyMethod)); } } } // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->ICanAddCustomAttribute->ICanAddCustomAttribute->ICustomAttribute instructions.Add(processor.Create(OpCodes.Callvirt, context.BaseReference.CustomAttribute.BuildMethod)); // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->ICanAddCustomAttribute instructions.Add(processor.Create(OpCodes.Callvirt, context.BaseReference.Parameter.AddCustomAttributeMethod)); } } // evaluation stack after the following statement: bottom->ICanAddParameters->ICanAddParameters->IParameter instructions.Add(processor.Create(OpCodes.Callvirt, context.BaseReference.Parameter.BuildMethod)); // evaluation stack after the following statement: bottom->ICanAddParameters instructions.Add(processor.Create(OpCodes.Callvirt, context.BaseReference.Execution.AddParameterMethod)); } } // evaluation stack after the following statement: bottom->IMethodExecution instructions.Add(processor.Create(OpCodes.Callvirt, context.BaseReference.Execution.BuildMethod)); context.ExecutionVariableIndex = method.Body.Variables.Count; method.Body.Variables.Add(new VariableDefinition(context.BaseReference.Execution.ReadOnlyTypeReference)); instructions.Add(processor.Create(OpCodes.Stloc, context.ExecutionVariableIndex)); // evaluation stack after the following statement: bottom context.ExecutionVariableSwitchableSection.EndIndex = instructions.Count; }