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