public LocaVariableSymbolCollectionTreeNode( InstructionBlock block ) : base( TreeViewImage.Folder, null ) { this.block = block; this.Text = "Symbols"; this.EnableLatePopulate(); }
private static InstructionBlock[] AddBlock(InstructionBlock block, InstructionBlock[] blocks) { InstructionBlock[] destinationArray = new InstructionBlock[blocks.Length + 1]; Array.Copy(blocks, destinationArray, blocks.Length); destinationArray[destinationArray.Length - 1] = block; return destinationArray; }
/// <summary> /// Weaves the specified context. /// </summary> /// <param name="context">The context.</param> /// <param name="block">The block.</param> public void Weave(WeavingContext context, InstructionBlock block) { LocalVariableSymbol parameters = block.DefineLocalVariable(context.Method.Module.FindType(typeof(ParameterDictionary), BindingOptions.Default), NameGenerator.Generate("parameters")); InstructionSequence entrySequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(entrySequence, NodePosition.Before, null); InstructionWriter writer = context.InstructionWriter; writer.AttachInstructionSequence(entrySequence); writer.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden); writer.EmitInstructionMethod(OpCodeNumber.Call, context.Method.Module.FindMethod(typeof(InternalHelperMethods).GetMethod("CreateParameterCollection"), BindingOptions.Default)); IMethod add = context.Method.Module.FindMethod(typeof(ParameterDictionary).GetMethod("Add", new[] { typeof(string), typeof(object) }), BindingOptions.Default); short parameterIndex = context.Method.IsStatic ? (short)0 : (short)1; foreach (var parameter in method.Parameters) { writer.EmitInstruction(OpCodeNumber.Dup); writer.EmitInstructionString(OpCodeNumber.Ldstr, new LiteralString(parameter.Name)); writer.EmitInstructionInt16(OpCodeNumber.Ldarg, parameterIndex++); if (parameter.ParameterType.GetSystemType(null, null).IsValueType) { writer.EmitInstructionType(OpCodeNumber.Box, parameter.ParameterType); } writer.EmitInstructionMethod(OpCodeNumber.Callvirt, add); } writer.EmitInstructionLocalVariable(OpCodeNumber.Stloc, parameters); writer.DetachInstructionSequence(); }
public void Weave(WeavingContext context, InstructionBlock block) { InstructionSequence nextSequence = null; InstructionSequence sequence = null; sequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(sequence, NodePosition.Before, null); context.InstructionWriter.AttachInstructionSequence(sequence); context.InstructionWriter.EmitInstructionParameter(OpCodeNumber.Ldarg, this.paramDef); context.InstructionWriter.EmitInstructionType(OpCodeNumber.Box, this.paramDef.ParameterType); context.InstructionWriter.EmitInstruction(OpCodeNumber.Ldnull); context.InstructionWriter.EmitInstruction(OpCodeNumber.Ceq); nextSequence = context.Method.MethodBody.CreateInstructionSequence(); context.InstructionWriter.EmitBranchingInstruction(OpCodeNumber.Brfalse_S, nextSequence); context.InstructionWriter.EmitInstructionString(OpCodeNumber.Ldstr, this.paramDef.Name); context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Newobj, context.Method.Module.FindMethod( typeof (ArgumentNullException).GetConstructor( new[] {typeof (string)}), BindingOptions.Default)); context.InstructionWriter.EmitInstruction(OpCodeNumber.Throw); context.InstructionWriter.DetachInstructionSequence(); block.AddInstructionSequence(nextSequence, NodePosition.After, sequence); sequence = nextSequence; context.InstructionWriter.AttachInstructionSequence(sequence); context.InstructionWriter.DetachInstructionSequence(); }
public void Weave(WeavingContext context, InstructionBlock block) { InstructionSequence sequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(sequence, NodePosition.After, null); InstructionWriter writer = context.InstructionWriter; writer.AttachInstructionSequence(sequence); context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, context.ReturnValueVariable); context.InstructionWriter.EmitInstructionType(OpCodeNumber.Box, context.ReturnValueVariable.LocalVariable.Type); context.InstructionWriter.EmitInstruction(OpCodeNumber.Ldnull); context.InstructionWriter.EmitInstruction(OpCodeNumber.Ceq); InstructionSequence nextSequence = context.Method.MethodBody.CreateInstructionSequence(); context.InstructionWriter.EmitBranchingInstruction(OpCodeNumber.Brfalse_S, nextSequence); context.InstructionWriter.EmitInstructionString(OpCodeNumber.Ldstr, "return value is null"); context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Newobj, context.Method.Module.FindMethod( typeof (ArgumentNullException).GetConstructor(new[] { typeof ( string ) }), BindingOptions.Default)); context.InstructionWriter.EmitInstruction(OpCodeNumber.Throw); block.AddInstructionSequence(nextSequence, NodePosition.After, sequence); writer.DetachInstructionSequence(); }
/// <summary> /// Checks whether <paramref name="theBlock"/> is a do-finally-check block. /// </summary> /// <remarks> /// Pattern: /// (nop) - sequence of nop blocks /// ldloc* doFinallyVariable /// brfalse* - branch to endfinally - this check varies between compilers /// original handler: /// ............... /// </remarks> /// <param name="theBlock"></param> /// <returns></returns> protected override bool IsFinallyCheckBlock(InstructionBlock theBlock) { Instruction currentInstruction = theBlock.First; while (currentInstruction.OpCode.Code == Code.Nop) { if (currentInstruction == theBlock.Last) { return false; } currentInstruction = currentInstruction.Next; } VariableReference loadedVariable; if (currentInstruction == theBlock.Last || !StateMachineUtilities.TryGetVariableFromInstruction(currentInstruction, methodVariables, out loadedVariable) || loadedVariable != doFinallyVariable) { return false; } currentInstruction = currentInstruction.Next; if (currentInstruction.OpCode.Code == Code.Brfalse || currentInstruction.OpCode.Code == Code.Brfalse_S) { return true; } return IsCSharpDebugCheck(theBlock, currentInstruction) || IsVisualBasicDebugCheck(theBlock, currentInstruction); }
public ControlFlowGraph(Mono.Cecil.Cil.MethodBody body, InstructionBlock[] blocks, Dictionary<int, InstructionData> instructionData, List<ExceptionHandlerData> exception_data, HashSet<int> exception_objects_offsets) { this.body = body; this.blocks = blocks; this.data = instructionData; this.exception_data = exception_data; this.exception_objects_offsets = exception_objects_offsets; }
protected override void ImplementOnEntry(InstructionBlock block, InstructionWriter writer) { foreach (var implementation in GetOnEntryImplementations()) { using (var factory = implementation.CreateExport()) { var instance = factory.Value; instance.Initialize(Context); instance.ImplementOnEntry(block, writer); } } }
public SwitchData(InstructionBlock switchBlock, InstructionBlock defaultCase, IList<InstructionBlock> orderedCases) { SwitchBlock = switchBlock; DefaultCase = defaultCase; OrderedCasesArray = new InstructionBlock[orderedCases.Count]; for (int i = 0; i < orderedCases.Count; i++) { OrderedCasesArray[i] = orderedCases[i]; } }
public InstructionBlockTreeNode( InstructionBlock block, string name ) : base( TreeViewImage.Namespace, block ) { this.Text = name + " " + block.ToString(); this.block = block; if ( this.block.HasChildrenBlocks || this.block.HasExceptionHandlers || this.block.HasLocalVariableSymbols ) { this.EnableLatePopulate(); } }
public static void MarkBlocksDeadIfNeeded(InstructionBlock[] instructionBlocks) { if (Enumerable.Count<InstructionBlock>(instructionBlocks) != 1) { foreach (InstructionBlock block in instructionBlocks) { block.MarkIsDead(); } instructionBlocks[0].MarkIsAliveRecursive(); } }
public void Weave(WeavingContext context, InstructionBlock block) { InstructionSequence sequence = null; sequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(sequence, NodePosition.After, null); context.InstructionWriter.AttachInstructionSequence(sequence); context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Call, context.Method.Module.FindMethod(m_type.Methods.GetOneByName("get_Instance").GetReflectionWrapper(new Type[]{},new Type[]{}),BindingOptions.Default)); context.InstructionWriter.DetachInstructionSequence(); }
public ControlFlowGraph( MethodBody body, InstructionBlock[] blocks, Dictionary<int, InstructionBlock> instructiontoBlockMapping, Dictionary<InstructionBlock, SwitchData> switchBlocksInformation, Dictionary<int, Instruction> offsetToInstruction) { this.MethodBody = body; this.Blocks = blocks; this.InstructionToBlockMapping = instructiontoBlockMapping; this.SwitchBlocksInformation = switchBlocksInformation; this.OffsetToInstruction = offsetToInstruction; }
public static void AddPropertyGuard(PropertyDeclaration property, MethodBodyTransformationContext context, InstructionBlock block, InstructionWriter writer) { var propertyType = property.PropertyType; var methodBody = block.MethodBody; var sequence = block.AddInstructionSequence(null, NodePosition.After, null); if (sequence == null) return; var oldValueVariable = block.DefineLocalVariable(propertyType, string.Format("old{0}Value", property.Name)); var assets = GetTransformationAssets(property.Module); writer.AttachInstructionSequence(sequence); var isLocationBinding = CheckIfIsLocationBinding(methodBody,assets); if (isLocationBinding) { writer.AssignValue_LocalVariable(oldValueVariable , () => writer.Call_MethodOnTarget(property.GetGetter() , () => { //Load the instance parameter of the SetValue method //and convert it to the type writer.EmitInstruction(OpCodeNumber.Ldarg_1); //writer.EmitInstructionLoadIndirect(Assets.ObjectTypeSignature); writer.EmitInstructionType(OpCodeNumber.Ldobj, assets.ObjectTypeSignature); writer.EmitConvertFromObject(property.Parent); } ) ); //On the location binding the value parameter is at psotion 3 writer.EmitInstruction(OpCodeNumber.Ldarg_3); } else { writer.AssignValue_LocalVariable(oldValueVariable, () => writer.Get_PropertyValue(property)); //For a normal property the value parameter is at position 1 writer.EmitInstruction(OpCodeNumber.Ldarg_1); } if (propertyType.IsStruct()) { writer.EmitInstructionType(OpCodeNumber.Box, propertyType); } writer.Box_LocalVariableIfNeeded(oldValueVariable); var isPrimitive = propertyType.IsPrimitive(); if (isPrimitive) { writer.Compare_Primitives(); } else { //TODO: Try and use the equality operator when present writer.Compare_Objects(assets.ObjectEqualsMethod); } //writer.Leave_IfTrue(_context.LeaveBranchTarget); writer.Leave_IfTrue(context.LeaveBranchTarget); writer.DetachInstructionSequence(); }
public void Weave(WeavingContext context, InstructionBlock block) { InstructionSequence entrySequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(entrySequence, NodePosition.Before, null); InstructionWriter writer = context.InstructionWriter; writer.AttachInstructionSequence(entrySequence); writer.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden); Weave(context, writer); writer.DetachInstructionSequence(); }
public void Weave( WeavingContext context, InstructionBlock block ) { switch ( context.JoinPoint.JoinPointKind ) { case JoinPointKinds.BeforeMethodBody: this.WeaveEntry( context, block ); break; case JoinPointKinds.AfterMethodBodySuccess: this.WeaveExit( context, block ); break; default: throw new ArgumentException(string.Format( "Unexpected join point kind: {0}", context.JoinPoint.JoinPointKind ) ); } }
void ProcessBlock(InstructionBlock block) { if (WasProcessed(block)) { return; } var previous_block = current_block; current_block = block; MarkProcessed(block); ProcessInstructions(block); current_block = previous_block; }
/// <summary> /// Checks whether the specified block contains assignment of the state variable. /// </summary> /// <param name="theBlock"></param> /// <returns></returns> private bool ContainsStateVariableSet(InstructionBlock theBlock) { VariableReference varReference; Instruction currentInstruction = theBlock.First; while (currentInstruction != theBlock.Last) { if (IsStloc(currentInstruction) && TryGetVariableFromInstruction(currentInstruction, out varReference) && varReference == this.stateVariable) { return(true); } currentInstruction = currentInstruction.Next; } return(false); }
public void Weave(WeavingContext context, InstructionBlock block) { InstructionSequence nextSequence = null; InstructionSequence sequence = null; sequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(sequence, NodePosition.Before, null); context.InstructionWriter.AttachInstructionSequence(sequence); IMethod isNullOrEmpty = context.Method.Module.FindMethod(typeof (string).GetMethod("IsNullOrEmpty"), BindingOptions.Default); // Checks if not empty context.InstructionWriter.EmitInstructionParameter(OpCodeNumber.Ldarg, paramDef); context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Call, isNullOrEmpty); nextSequence = context.Method.MethodBody.CreateInstructionSequence(); context.InstructionWriter.EmitBranchingInstruction(OpCodeNumber.Brfalse_S, nextSequence); context.InstructionWriter.EmitInstructionString(OpCodeNumber.Ldstr, "Parameter is null or empty."); context.InstructionWriter.EmitInstructionString(OpCodeNumber.Ldstr, this.paramDef.Name); context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Newobj, context.Method.Module.FindMethod( typeof (ArgumentException).GetConstructor(new[] { typeof ( string ), typeof ( string ) }), BindingOptions.Default)); context.InstructionWriter.EmitInstruction(OpCodeNumber.Throw); context.InstructionWriter.DetachInstructionSequence(); block.AddInstructionSequence(nextSequence, NodePosition.After, sequence); sequence = nextSequence; context.InstructionWriter.AttachInstructionSequence(sequence); context.InstructionWriter.DetachInstructionSequence(); }
/// <summary> /// Performs stack analysis on single block. /// </summary> /// <param name="block">The block to be analysed.</param> private void ComputeStackUsage(InstructionBlock block) { List <int> currentStack = new List <int>(blockToInitialStackMap[block.Index]); /// Analyse the stack usage for each instruction. foreach (Instruction instruction in block) { if (instruction.OpCode.Code == Code.Dup) { if (currentStack.Count == 0) { throw new Exception("Invalid evaluation stack"); } currentStack.Add(currentStack[currentStack.Count - 1]); continue; } uint popDelta = GetPopDelta((uint)currentStack.Count, instruction); uint pushDelta = GetPushDelta(instruction); List <int> instructionPopStack = new List <int>(); for (int i = 0; i < popDelta; i++) { int last = currentStack.Count - 1; instructionPopStack.Add(currentStack[last]); currentStack.RemoveAt(last); } if (pushDelta > 0) { stackVariableInstructionsSet.Add(instruction.Offset); } /// Push entries on the evaluation stack as they will be pushed by the instruction. for (int i = 0; i < pushDelta; i++) { currentStack.Add(instruction.Offset); } /// Update the records for the instruction. instructionOffsetToUsedInstructionsMap[instruction.Offset] = new Stack <int>(instructionPopStack); } blockToExitStackMap[block.Index] = currentStack.ToArray(); }
void GetReachableBlocks(IEnumerable <InstructionBlock> startBlocks) { reachableBlocks.UnionWith(startBlocks); Queue <InstructionBlock> traversalQueue = new Queue <InstructionBlock>(startBlocks); while (traversalQueue.Count > 0) { InstructionBlock currentBlock = traversalQueue.Dequeue(); foreach (InstructionBlock successor in currentBlock.Successors) { if (reachableBlocks.Add(successor)) { traversalQueue.Enqueue(successor); } } } }
/// <summary> /// Gets the first control flow block that is not marked for removal. /// </summary> /// <remarks> /// The search for the first block follows the control flow. This method is used only when creating fake switch data, which means /// that there are no controller blocks in the method. This means that only some simple blocks should have been marked for removal /// (e.g. nop blocks, unconditional branch blocks). That's why we presume that there will be no branches during the search, which means /// that a simple while will suffice for the algorithm. /// If we reach a block that is marked for removal but has more than one successor then the method fails (returns false). /// </remarks> /// <param name="methodEntry"></param> /// <returns></returns> private bool GetMethodEntry(out InstructionBlock methodEntry) { InstructionBlock current = theCFG.Blocks[0]; while (toBeRemoved.Contains(current)) { if (current.Successors.Length != 1) { methodEntry = null; return(false); } current = current.Successors[0]; } methodEntry = current; return(true); }
void MoveStatementsToBlock(InstructionBlock start, InstructionBlock limit, BlockStatement block) { for (int i = start.Index; i < limit.Index; i++) { ProcessBlock(cfg.Blocks [i]); var list = this.statements [i]; if (list == null) { continue; } AddRangeToBlock(block, list); list.Clear(); } }
private void ReattachDefaultSuccessor(InstructionBlock initialBlock, InstructionBlock currentBlock) { if (InstructionBlock.op_Inequality(initialBlock, currentBlock)) { this.RedirectNonControllerPredecessors(initialBlock, currentBlock); this.SwapCFGBlocks(initialBlock.get_Index(), currentBlock.get_Index()); V_0 = 0; while (V_0 < (int)this.stateToStartBlock.Length) { if (InstructionBlock.op_Equality(this.stateToStartBlock[V_0], initialBlock)) { this.stateToStartBlock[V_0] = currentBlock; } V_0 = V_0 + 1; } } return; }
private void UpdateCurrentStackVariables(InstructionBlock parent, InstructionBlock successor) { int[] parentExitStack = blockToExitStackMap[parent.Index]; int[] successorEntryStack = blockToInitialStackMap[successor.Index]; if (parentExitStack.Length != successorEntryStack.Length) { /// This coveres the case, when single block can be entered with stacks of different size. /// As this is not allowed by standarts, an exception is thrown. /// No real code has been seen, that has this behavior. Only test that reproduces it is written by hand. throw new ArgumentException("Two paths with different stack states encountered."); } for (int i = 0; i < parentExitStack.Length; i++) { unionFinder.Union(successorEntryStack[i], parentExitStack[i]); } }
bool TryProcessBreak(InstructionBlock block) { var data = PeekLoopData(); if (data == null) { return(false); } if (block.Successors [0].Index == data.Body.End.Index) { store.RemoveAttotation(block.Last, Annotation.Skip); Annotate(block.Last, Annotation.Break); return(true); } return(false); }
protected bool IsConditionExpression(InstructionBlock block) { var last = block.Last; if (!IsConditionalBranch(last)) { return(false); } var child = GetFirstCommonChild(block.Successors [0], block.Successors [1]); if (child == null) { return(false); } return(GetStackBefore(child.First) > 0); }
private bool CheckForIsCompletedCall(InstructionBlock theBlock) { V_0 = theBlock.get_First(); while ((object)V_0 != (object)theBlock.get_Last()) { if (V_0.get_OpCode().get_Code() == 39 || V_0.get_OpCode().get_Code() == 110 && String.op_Equality(((MethodReference)V_0.get_Operand()).get_Name(), "get_IsCompleted")) { if (!StateMachineUtilities.TryGetVariableFromInstruction(V_0.get_Previous(), this.moveNextMethodContext.get_Body().get_Variables(), out V_2)) { return(false); } dummyVar0 = this.awaiterVariables.Add(V_2); return(true); } V_0 = V_0.get_Next(); } return(false); }
private bool BFSRemoveBlocks() { V_0 = new Queue <InstructionBlock>(); V_1 = this.toBeRemoved.GetEnumerator(); try { while (V_1.MoveNext()) { V_2 = V_1.get_Current(); if (V_2.get_Predecessors().get_Count() != 0) { continue; } V_0.Enqueue(V_2); } } finally { ((IDisposable)V_1).Dispose(); } while (V_0.get_Count() > 0) { V_3 = V_0.Dequeue(); if (V_3.get_Index() == -1) { continue; } stackVariable22 = V_3.get_Successors(); this.theCFG.RemoveBlockAt(V_3.get_Index()); V_4 = stackVariable22; V_5 = 0; while (V_5 < (int)V_4.Length) { V_6 = V_4[V_5]; if (V_6.get_Predecessors().get_Count() == 0 && InstructionBlock.op_Inequality(V_6, this.newEntryBlock)) { V_0.Enqueue(V_6); } V_5 = V_5 + 1; } dummyVar0 = this.toBeRemoved.Remove(V_3); } return(this.toBeRemoved.get_Count() == 0); }
public void TestWrongDeclaration() { var v = new Variable(new Range(new StringLocation(0), new StringLocation(1)), "f"); var x = new VariableDeclaration( new Range(new StringLocation(0), new StringLocation(1)), IntType.Instance, "f", null); var fc = new FunctionCall( new Range(new StringLocation(0), new StringLocation(1)), "f", new List <Expression>()); var instructionBlock = new InstructionBlock( new Range(new StringLocation(0), new StringLocation(1)), new List <Expression> { v, x, fc }); var f = new FunctionDeclaration( new Range(new StringLocation(0), new StringLocation(1)), "f", UnitType.Instance, new List <VariableDeclaration>(), instructionBlock, false); var diagnosticsMock = new Moq.Mock <IDiagnostics>(); var diagnostics = diagnosticsMock.Object; var functions = new List <FunctionDeclaration> { f }; var root = new Program( new Range(new StringLocation(0), new StringLocation(1)), new List <StructDeclaration>(), functions); Assert.ThrowsException <NameResolverException>(() => this.nameResolver.Run(root, diagnostics)); MockDiagnostics.Verify( diagnosticsMock, NameResolver.IdentifierNotFoundDiagnostic); }
public void Weave(WeavingContext context, InstructionBlock block) { IList<ParameterDeclaration> args = new List<ParameterDeclaration>(); foreach(ParameterDeclaration p in context.Method.Parameters) { foreach (CustomAttributeDeclaration c in p.CustomAttributes) { object obj = c.ConstructRuntimeObject(); if (obj is NonNullAttribute) { args.Add(p); } } } InstructionSequence nextSequence = null; InstructionSequence sequence = null; sequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(sequence, NodePosition.Before, null); context.InstructionWriter.AttachInstructionSequence(sequence); foreach (ParameterDeclaration p in args) { context.InstructionWriter.EmitInstructionParameter(OpCodeNumber.Ldarg, p); context.InstructionWriter.EmitInstructionType(OpCodeNumber.Box, p.ParameterType); context.InstructionWriter.EmitInstruction(OpCodeNumber.Ldnull); context.InstructionWriter.EmitInstruction(OpCodeNumber.Ceq); nextSequence = context.Method.MethodBody.CreateInstructionSequence(); context.InstructionWriter.EmitBranchingInstruction(OpCodeNumber.Brfalse_S, nextSequence); context.InstructionWriter.EmitInstructionString(OpCodeNumber.Ldstr, (LiteralString)p.Name); context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Newobj, context.Method.Module.FindMethod(typeof(ArgumentNullException).GetConstructor(new Type[] { typeof(string) }), BindingOptions.Default)); context.InstructionWriter.EmitInstruction(OpCodeNumber.Throw); context.InstructionWriter.DetachInstructionSequence(); block.AddInstructionSequence(nextSequence, NodePosition.After, sequence); sequence = nextSequence; context.InstructionWriter.AttachInstructionSequence(sequence); } context.InstructionWriter.DetachInstructionSequence(); }
/// <summary> /// Checks whether the specified block is a dummy controller block. /// </summary> /// <remarks> /// This block looks like a state controller block with the difference that it ends with two pop instructions. /// Generated by the C# compiler in release mode. /// Update: With C# 6.0 the structure of the dummy state controller blocks has changed. The new one is load /// of the state variable, followed by pop and nop instructions. /// </remarks> /// <param name="theBlock"></param> /// <returns></returns> private bool IsDummyStateControllerBlock(InstructionBlock theBlock) { if (this.version == AsyncStateMachineVersion.V1) { if (!ContainsStateFieldLoad(theBlock)) { return(false); } Instruction currentInstruction = theBlock.Last; for (int i = 0; i < 2; i++) { if (currentInstruction == theBlock.First || currentInstruction.OpCode.Code != Code.Pop) { return(false); } currentInstruction = currentInstruction.Previous; } toBeRemoved.Add(theBlock); return(true); } else { Instruction current = theBlock.First; VariableReference variable; if (!TryGetVariableFromInstruction(current, out variable) || variable != stateVariable) { return(false); } if (current.Next.OpCode.Code != Code.Pop || current.Next.Next.OpCode.Code != Code.Nop) { return(false); } if (current.Next.Next != theBlock.Last) { return(false); } return(true); } }
public void TestUnapplication() { var names = new List <string> { "a" }; var functions = new List <FunctionDeclaration>(); var unapplications = new List <UnApplication>(); foreach (var id in names) { var unapplication = new UnApplication( new Range(new StringLocation(0), new StringLocation(1)), "a"); var body = new InstructionBlock( new Range(new StringLocation(0), new StringLocation(1)), new List <Expression> { unapplication }); var fun = new FunctionDeclaration( new Range(new StringLocation(0), new StringLocation(1)), id, UnitType.Instance, new List <VariableDeclaration>(), body, false); unapplications.Add(unapplication); functions.Add(fun); } var root = new Program( new Range(new StringLocation(0), new StringLocation(1)), new List <StructDeclaration>(), functions); var resolver = new NameResolver(); resolver.Run(root, null); var aDeclaration = functions[0]; var expected = new List <FunctionDeclaration> { aDeclaration }; CollectionAssert.AreEqual(expected, unapplications[0].Candidates.ToList()); }
private void ReplaceOperator(TypeDefDeclaration enhancedType, MethodDefDeclaration equalityMethodDef, bool negate) { InstructionBlock originalCode = equalityMethodDef.MethodBody.RootInstructionBlock; originalCode.Detach(); InstructionBlock root = equalityMethodDef.MethodBody.CreateInstructionBlock(); equalityMethodDef.MethodBody.RootInstructionBlock = root; var newSequence = root.AddInstructionSequence(); using (var writer = InstructionWriter.GetInstance()) { writer.AttachInstructionSequence(newSequence); if (enhancedType.IsValueType()) { var canonicalType = enhancedType.GetCanonicalGenericInstance(); writer.EmitInstruction(OpCodeNumber.Ldarg_0); writer.EmitInstructionType(OpCodeNumber.Box, canonicalType); writer.EmitInstruction(OpCodeNumber.Ldarg_1); writer.EmitInstructionType(OpCodeNumber.Box, canonicalType); } else { writer.EmitInstruction(OpCodeNumber.Ldarg_0); writer.EmitInstruction(OpCodeNumber.Ldarg_1); } writer.EmitInstructionMethod(OpCodeNumber.Call, this.staticEqualsMethod); if (negate) { writer.EmitInstruction(OpCodeNumber.Ldc_I4_0); writer.EmitInstruction(OpCodeNumber.Ceq); } writer.EmitInstruction(OpCodeNumber.Ret); writer.DetachInstructionSequence(); } }
/// <summary> /// Checks whether the specified block is a disposing-check block. /// </summary> /// <remarks> /// Pattern: /// ldarg.0 /// ldfld disposingField /// .......... /// conditional branch /// </remarks> /// <param name="theBlock"></param> /// <returns></returns> private bool IsDisposingBlock(InstructionBlock theBlock) { Instruction currentInstruction = theBlock.First; if (currentInstruction.OpCode.Code != Code.Ldarg_0 || currentInstruction == theBlock.Last) { return false; } currentInstruction = currentInstruction.Next; if (currentInstruction.OpCode.Code != Code.Ldfld || ((FieldReference)currentInstruction.Operand).Resolve() != disposingField || currentInstruction == theBlock.Last) { return false; } Instruction lastInstruction = theBlock.Last; return lastInstruction.OpCode.Code == Code.Brfalse || lastInstruction.OpCode.Code == Code.Brfalse_S || lastInstruction.OpCode.Code == Code.Brtrue || lastInstruction.OpCode.Code == Code.Brtrue_S; }
protected override bool IsFinallyCheckBlock(InstructionBlock finallyEntry) { V_0 = finallyEntry.get_First(); if (!StateMachineUtilities.TryGetVariableFromInstruction(V_0, this.methodVariables, out V_1) || (object)V_1 != (object)this.stateVariable) { return(false); } V_0 = V_0.get_Next(); if (V_0.get_OpCode().get_Code() != 22) { return(false); } V_0 = V_0.get_Next(); if (V_0.get_OpCode().get_Code() != 59 && V_0.get_OpCode().get_Code() != 46) { return(false); } return(true); }
public BooleanExpressionCoder Or <T>(T[] collection, Func <BooleanExpressionCoder, T, int, object> code) { if (collection == null || collection.Length == 0) { return(this); } code(this, collection[0], 0); InstructionBlock.CastOrBoxValues(this.instructions, BuilderTypes.Boolean); for (int i = 1; i < collection.Length; i++) { code(this, collection[i], i); InstructionBlock.CastOrBoxValues(this.instructions, BuilderTypes.Boolean); this.instructions.Emit(OpCodes.Or); } return(this); }
/// <summary> /// Process each CFG block to determine which cases lead to try/finally construct. /// </summary> private void DetermineExceptionHandlingStatesFromCFGBlocks() { foreach (InstructionBlock block in theDisposeCFG.Blocks) { int state; if ((!IsBeqInstruction(block.Last) && !IsBneUnInstruction(block.Last)) || !StateMachineUtilities.TryGetOperandOfLdc(block.Last.Previous, out state)) { continue; } Instruction branchTargetInstruction = null; if (IsBeqInstruction(block.Last)) { branchTargetInstruction = block.Last.Operand as Instruction; } else // bne.un* { branchTargetInstruction = block.Last.Next as Instruction; } if (branchTargetInstruction == null) { throw new Exception("branchTargetInstruction cannot be null."); } InstructionBlock targetBlock = SkipSingleNopInstructionBlock(theDisposeCFG.InstructionToBlockMapping[branchTargetInstruction.Offset]); ExceptionHandler theHandler; if (!TryGetExceptionHandler(targetBlock, out theHandler)) { continue; } //We've found an exception handler. if (!this.handlerToStatesMap.ContainsKey(theHandler)) { this.handlerToStatesMap.Add(theHandler, new HashSet <int>()); } this.handlerToStatesMap[theHandler].Add(state); } }
/// <summary> /// Checks whether the specified block contains a call of the get_IsCompleted method. /// </summary> /// <remarks> /// Saves the target variable of the call. /// </remarks> /// <param name="theBlock"></param> /// <returns></returns> private bool CheckForIsCompletedCall(InstructionBlock theBlock) { for (Instruction current = theBlock.First; current != theBlock.Last; current = current.Next) { if ((current.OpCode.Code == Code.Call || current.OpCode.Code == Code.Callvirt) && ((MethodReference)current.Operand).Name == "get_IsCompleted") { VariableReference awaiterVariable; if (StateMachineUtilities.TryGetVariableFromInstruction(current.Previous, moveNextMethodContext.Body.Variables, out awaiterVariable)) { awaiterVariables.Add(awaiterVariable); return(true); } return(false); } } return(false); }
void ProcessBlock(InstructionBlock block) { switch (block.Successors.Length) { case 0: case 1: ProcessSimpleBlock(block); break; case 2: ProcessTwoWayBlock(block); break; default: throw new ArgumentException("n-way block not supported", "block"); } MarkProcessed(block); }
/// <summary> /// Removes the blocks that save the state and then exit the method. /// </summary> /// <remarks> /// We search for the state saving blocks by starting from the last block in the CFG, which should be a block that contains only the ret instruction /// (and some nops when compiled in debug). This block has two predecessors that are not state saving blocks: the second to last block that is used to set /// the result when the state machine terminates (i.e. return in the original code) and the body of the catch clause that is part of the try/catch construct /// that encloses the logic of the state machine. All other predecessors should be state saving blocks. /// We detach the final return block (and we mark it for removal) from these two block in order to avoid creating an unneeded goto from the catch block. /// </remarks> /// <returns></returns> private bool RemoveStateSavingBlocks() { InstructionBlock lastBlock = theCFG.Blocks[theCFG.Blocks.Length - 1]; Instruction currentInstruction = lastBlock.First; while (currentInstruction.OpCode.Code == Code.Nop && currentInstruction != lastBlock.Last) { currentInstruction = currentInstruction.Next; } if (currentInstruction.OpCode.Code != Code.Ret) { return(false); } int detachedPredecessorsCount = 0; HashSet <InstructionBlock> predecessors = new HashSet <InstructionBlock>(lastBlock.Predecessors); foreach (InstructionBlock predecessor in predecessors) { if (predecessor.Successors.Length > 1) { return(false); } if (predecessor.Predecessors.Count == 1 && theCFG.Blocks[theCFG.Blocks.Length - 2] != predecessor) { if (!CheckForStateFieldSet(predecessor) || !TryRemoveStateSavingBlock(predecessor)) { return(false); } } else { predecessor.Successors = new InstructionBlock[0]; detachedPredecessorsCount++; } } toBeRemoved.Add(lastBlock); return(detachedPredecessorsCount == 2); }
private bool IsDisposingBlock(InstructionBlock theBlock) { V_0 = theBlock.get_First(); if (V_0.get_OpCode().get_Code() != 2 || (object)V_0 == (object)theBlock.get_Last()) { return(false); } V_0 = V_0.get_Next(); if (V_0.get_OpCode().get_Code() != 120 || (object)((FieldReference)V_0.get_Operand()).Resolve() != (object)this.disposingField || (object)V_0 == (object)theBlock.get_Last()) { return(false); } V_1 = theBlock.get_Last(); if (V_1.get_OpCode().get_Code() == 56 || V_1.get_OpCode().get_Code() == 43 || V_1.get_OpCode().get_Code() == 57) { return(true); } return(V_1.get_OpCode().get_Code() == 44); }
private TypeDefDeclaration CreateContainingType() { string uniqueName = this.module.Types.GetUniqueName( DebuggerSpecialNames.GetDeclarationSpecialName("LoggingImplementationDetails{0}")); TypeDefDeclaration logCategoriesType = new TypeDefDeclaration { Name = uniqueName, Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed | TypeAttributes.Abstract, BaseType = ((IType)this.module.Cache.GetType("System.Object, mscorlib")) }; this.module.Types.Add(logCategoriesType); // Add [CompilerGenerated] and [DebuggerNonUserCode] to the type this.weavingHelper.AddCompilerGeneratedAttribute(logCategoriesType.CustomAttributes); this.weavingHelper.AddDebuggerNonUserCodeAttribute(logCategoriesType.CustomAttributes); MethodDefDeclaration staticConstructor = new MethodDefDeclaration { Name = ".cctor", Attributes = MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig, }; logCategoriesType.Methods.Add(staticConstructor); staticConstructor.ReturnParameter = new ParameterDeclaration { Attributes = ParameterAttributes.Retval, ParameterType = this.module.Cache.GetIntrinsic(IntrinsicType.Void) }; this.constructorBlock = staticConstructor.MethodBody.RootInstructionBlock = staticConstructor.MethodBody.CreateInstructionBlock(); this.returnSequence = staticConstructor.MethodBody.RootInstructionBlock.AddInstructionSequence(null, NodePosition.After, null); this.writer.AttachInstructionSequence(this.returnSequence); this.writer.EmitInstruction(OpCodeNumber.Ret); this.writer.DetachInstructionSequence(); return(logCategoriesType); }
private FunctionDeclaration FunctionDeclarationToAst(Brunch <KjuAlphabet> branch) { var parameters = new List <VariableDeclaration>(); string identifier = null; DataType type = null; InstructionBlock body = null; bool isForeign = false; foreach (var child in branch.Children) { switch (child.Category) { case KjuAlphabet.FunctionParameter: parameters.Add(this.FunctionParameterToAst((Brunch <KjuAlphabet>)child)); break; case KjuAlphabet.VariableFunctionIdentifier: identifier = ((Token <KjuAlphabet>)child).Text; break; case KjuAlphabet.TypeDeclaration: type = this.TypeDeclarationAst((Brunch <KjuAlphabet>)child); break; case KjuAlphabet.Block: body = this.BlockToAst((Brunch <KjuAlphabet>)child); break; case KjuAlphabet.Import: isForeign = true; break; } } return(new FunctionDeclaration( branch.InputRange, identifier, type, parameters, body, isForeign)); }
/// <summary> /// The method that does the actual analysis. /// </summary> /// <param name="graphEntry">The entry point of the decompiled method.</param> private void AnalyzeStackUsage() { this.traversed = new bool[controlFlowGraph.Blocks.Length]; /// This should pass through all the blocks of the method, missing only the exception handlers. RecursiveDfs(controlFlowGraph.Blocks[0], new int[0]); /// Pass through all the exception handlers. foreach (ExceptionHandler handler in exceptionHandlers) { InstructionBlock handlerBlock = controlFlowGraph.InstructionToBlockMapping[handler.HandlerStart.Offset]; if (handler.HandlerType == ExceptionHandlerType.Fault || handler.HandlerType == ExceptionHandlerType.Finally) { RecursiveDfs(handlerBlock, new int[0]); } else { if (handler.HandlerType == ExceptionHandlerType.Filter) { InstructionBlock filterBlock = controlFlowGraph.InstructionToBlockMapping[handler.FilterStart.Offset]; RecursiveDfs(filterBlock, new int[] { -handler.FilterStart.Offset }); instructionOffsetToVariableDefinitionMap[-handler.FilterStart.Offset] = new VariableDefinition(ExceptionVariablePrefix + exceptionVariableCount++, Utilities.GetCorlibTypeReference(typeof(Exception), methodContext.Method.Module)); exceptionVariableInstructionsSet.Add(-handler.FilterStart.Offset); } RecursiveDfs(handlerBlock, new int[] { -handler.HandlerStart.Offset }); instructionOffsetToVariableDefinitionMap[-handler.HandlerStart.Offset] = new VariableDefinition(ExceptionVariablePrefix + exceptionVariableCount++, handler.CatchType ?? Utilities.GetCorlibTypeReference(typeof(Exception), methodContext.Method.Module)); exceptionVariableInstructionsSet.Add(-handler.HandlerStart.Offset); } } for (int i = 0; i < controlFlowGraph.Blocks.Length; i++) { if (!traversed[i]) { throw new Exception("Unreachable block found"); } } }
/// <summary> /// Creates the controller switch data using the information gathered during the traversal of the state controller blocks. /// </summary> private void CreateControllerSwitchData() { int index = GetIndexOfLastNonNullElement(stateToStartBlock); InstructionBlock[] finalCasesArray = new InstructionBlock[++index]; //Trim the excess elements of the cases array. for (int i = 0; i < index; i++) { if (stateToStartBlock[i] == null) { finalCasesArray[i] = defaultStateEntry; } else { finalCasesArray[i] = stateToStartBlock[i]; } } this.switchData = new SwitchData(null, defaultStateEntry, finalCasesArray); }
/// <summary> /// Process each switch block to determine which cases lead to try/finally constructs. /// </summary> /// <param name="switchBlockInfo"></param> private bool DetermineExceptionHandlingStatesFromSwitchData(SwitchData switchBlockInfo) { //Since the first try/finally that this switch covers can start at state 20, the complier will optimize this by subtracting 20 from the value of //the state field. int stateOffset = 0; Instruction currentInstruction = switchBlockInfo.SwitchBlock.Last.Previous; if (currentInstruction.OpCode.Code == Code.Sub) { currentInstruction = currentInstruction.Previous; if (!StateMachineUtilities.TryGetOperandOfLdc(currentInstruction, out stateOffset)) { return(false); } currentInstruction = currentInstruction.Previous; } InstructionBlock[] orderedCases = switchBlockInfo.OrderedCasesArray; for (int i = 0; i < orderedCases.Length; i++) { InstructionBlock currentCase = GetActualCase(orderedCases[i]); ExceptionHandler theHandler; if (!TryGetExceptionHandler(currentCase, out theHandler)) { continue; } //We've found an exception handler. if (!this.handlerToStatesMap.ContainsKey(theHandler)) { this.handlerToStatesMap.Add(theHandler, new HashSet <int>()); } this.handlerToStatesMap[theHandler].Add(i + stateOffset); } return(true); }
/// <summary> /// Sets the true and false CFG successors of the construct. /// </summary> /// <param name="cfgConditionBlock"></param> private void SetTrueAndFalseSuccessors(CFGBlockLogicalConstruct cfgConditionBlock) { InstructionBlock block = cfgConditionBlock.TheBlock; //The successor at the last index is the near successor (by design). The ExpressionDecompilerStep ensures that the far successor will be //the true successor and the near successor will be the false successor. InstructionBlock trueSuccessorBlock = block.Successors[0]; //The far successor InstructionBlock falseSuccessorBlock = block.Successors[1]; //The near successor foreach (CFGBlockLogicalConstruct cfgSuccessor in cfgConditionBlock.CFGSuccessors) { if (cfgSuccessor.TheBlock == trueSuccessorBlock) { this.TrueCFGSuccessor = cfgSuccessor; } if (cfgSuccessor.TheBlock == falseSuccessorBlock) { this.FalseCFGSuccessor = cfgSuccessor; } } }
void ProcessExpressionBlock(InstructionBlock block, bool skip_first) { MarkProcessed(block); var current = current_block; current_block = block; foreach (var instruction in block) { if (skip_first && instruction == block.First) { continue; } expression_decompiler.Visit(instruction); TryProcessExpression(instruction); } current_block = current; }
private InstructionBlock FindMostDistantSuccessor(InstructionBlock currentBlock) { InstructionBlock mostDistantSuccessor = null; foreach (InstructionBlock successor in currentBlock.Successors) { if (mostDistantSuccessor == null) { if (successor.Index > currentBlock.Index) { mostDistantSuccessor = successor; } } else { if (successor.Index > mostDistantSuccessor.Index) { mostDistantSuccessor = successor; } } } return mostDistantSuccessor; }
protected override bool IsFinallyCheckBlock(InstructionBlock finallyEntry) { Instruction current = finallyEntry.First; VariableReference loadedVariable; if (!StateMachineUtilities.TryGetVariableFromInstruction(current, methodVariables, out loadedVariable) || loadedVariable != this.stateVariable) { return false; } current = current.Next; if (current.OpCode.Code != Code.Ldc_I4_0) { return false; } current = current.Next; if (current.OpCode.Code != Code.Bge && current.OpCode.Code != Code.Bge_S) { return false; } return true; }
private void WeaveSuccess(WeavingContext context, InstructionBlock block) { LogLevel level = this.attribute.ExitLevel; string text = this.attribute.ExitText; this.EmitCheckingAndTemplateLogging(context, block, level, text); }
private void WeaveException(WeavingContext context, InstructionBlock block) { LogLevel level = this.attribute.ExceptionLevel; string text = this.attribute.ExceptionText; // Inject the logging code only if the logging is turned on. if (this.attribute.ExceptionLevel != LogLevel.None) { // Method being woven and the type the method is declared in. MethodDefDeclaration wovenMethod = context.Method; TypeDefDeclaration wovenType = wovenMethod.DeclaringType; // Objects that contain required methods, fields, etc. LogLevelSupportItem supportItem = this.parent.GetSupportItem(level); PerTypeLoggingData perTypeLoggingData = this.parent.GetPerTypeLoggingData(wovenType); // Get the tokens for the message template. StringBuilder messageFormatString = new StringBuilder(); List<IMessageToken> nonStaticTokens = new List<IMessageToken>(); List<IMessageToken> messageParts = TemplateParser.Tokenize(text, wovenMethod, attribute.IncludeParamName); MakeFormatString(messageParts, messageFormatString, nonStaticTokens); // As log4net does not provide an overload for the LogXXX() methods which would accept // both exception and array of arguments for a format string, disallow usage of dynamic // tokens in the template. if (nonStaticTokens.Count > 0) { throw new FormatException("Message for logging exception can contain only placeholders whose value can be expanded at weaving time."); } // Variable that stores the reference to the thrown exception. LocalVariableSymbol exception = block.DefineLocalVariable(context.Method.Module.FindType(typeof(Exception), BindingOptions.Default), "~ex~{0}"); // Sequence that contains code that checks if the logging is enabled and logs the message. InstructionSequence logExceptionSequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(logExceptionSequence, NodePosition.Before, null); // Sequence that contains code that is executed after logging. InstructionSequence afterLoggingSequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(afterLoggingSequence, NodePosition.After, logExceptionSequence); // Emit code that checks if the logging is enabled and logs the message. context.InstructionWriter.AttachInstructionSequence(logExceptionSequence); context.InstructionWriter.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden); context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Stloc_S, exception); EmitLoggingEnabledCheck(context.InstructionWriter, supportItem, perTypeLoggingData, afterLoggingSequence); EmitLogStringException(context.InstructionWriter, perTypeLoggingData.Log, supportItem.LogStringExceptionMethod, messageFormatString.ToString(), exception); context.InstructionWriter.DetachInstructionSequence(); // After logging is finished (or skipped), rethrow the exception. context.InstructionWriter.AttachInstructionSequence(afterLoggingSequence); context.InstructionWriter.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden); context.InstructionWriter.EmitInstruction(OpCodeNumber.Rethrow); context.InstructionWriter.DetachInstructionSequence(); } else { // Logging is turned off, just rethrow the exception. InstructionSequence rethrowSequence = context.Method.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(rethrowSequence, NodePosition.Before, null); context.InstructionWriter.AttachInstructionSequence(rethrowSequence); context.InstructionWriter.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden); context.InstructionWriter.EmitInstruction(OpCodeNumber.Rethrow); context.InstructionWriter.DetachInstructionSequence(); } }
/// <summary> /// Emits the MSIL that creates local variable and initializes it with array of objects representing the specified tokens. /// </summary> /// <param name="context">Context for the weaving.</param> /// <param name="block">Block where the code has to be injected.</param> /// <param name="nonStaticTokens">List of tokens that the object array is created for.</param> /// <returns>Local variable that stores the reference to the array.</returns> /// <exception cref="ArgumentNullException"><paramref name="context"/>, <paramref name="block"/> or <paramref name="nonStaticTokens"/> is <see langword="null"/>.</exception> /// <remarks> /// <para>Code emitted by this method makes no assumptions on the state of the evaluation stack /// and it leaves the stack unmodified.</para> /// </remarks> private LocalVariableSymbol EmitCreateFormatArgumentArray(WeavingContext context, InstructionBlock block, IList<IMessageToken> nonStaticTokens) { if (context == null) { throw new ArgumentNullException("context"); } if (block == null) { throw new ArgumentNullException("block"); } if (nonStaticTokens == null) { throw new ArgumentNullException("nonStaticTokens"); } InstructionWriter emitter = context.InstructionWriter; // Array that store arguments for the formatting. LocalVariableSymbol args = block.DefineLocalVariable(context.Method.Module.FindType(typeof(object[]), BindingOptions.Default), "~args~{0}"); // Create the array for storing agruments for formatting (contains only dyncamic tokens). emitter.EmitInstructionInt32(OpCodeNumber.Ldc_I4, nonStaticTokens.Count); emitter.EmitInstructionType(OpCodeNumber.Newarr, this.parent.ObjectType); // Save the array into the local variable because it will be used multiple times. emitter.EmitInstructionLocalVariable(OpCodeNumber.Stloc, args); // Fill the array with the data. for (int index = 0; index < nonStaticTokens.Count; index++) { // Array to store the data in. emitter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, args); // Position in the array to store the data at. emitter.EmitInstructionInt32(OpCodeNumber.Ldc_I4, index); // Let the token generate the IL that pushes the argument onto the stack. nonStaticTokens[index].Emit(context); // Finally: store the generated object into the array at the given position. emitter.EmitInstruction(OpCodeNumber.Stelem_Ref); } return args; }
/// <summary> /// Emits the MSIL which checks if the logging is enabled and logs the message. /// </summary> /// <param name="context">Weaving context.</param> /// <param name="block">Block where the code has to be injected.</param> /// <param name="level">Level for the message.</param> /// <param name="template">Template that will be tokenized in order to get message text.</param> /// <exception cref="ArgumentNullException"><paramref name="context"/>, <paramref name="block"/> or <paramref name="template"/> is <see langword="null"/>.</exception> /// <exception cref="FormatException">Template is not valid.</exception> /// <remarks> /// <para>If the <paramref name="level"/> is set to <see cref="LogLevel.None"/>, the method emits no code.</para> /// </remarks> private void EmitCheckingAndTemplateLogging(WeavingContext context, InstructionBlock block, LogLevel level, string template) { if (context == null) { throw new ArgumentNullException("context"); } if (block == null) { throw new ArgumentNullException("block"); } if (template == null) { throw new ArgumentNullException("template"); } if (level != LogLevel.None) { // Method being woven and the type the method is declared in. MethodDefDeclaration wovenMethod = context.Method; TypeDefDeclaration wovenType = wovenMethod.DeclaringType; // Objects that contain required methods, fields, etc. LogLevelSupportItem supportItem = this.parent.GetSupportItem(level); PerTypeLoggingData perTypeLoggingData = this.parent.GetPerTypeLoggingData(wovenType); // Get the tokens for the message template. StringBuilder messageFormatString = new StringBuilder(); List<IMessageToken> nonStaticTokens = new List<IMessageToken>(); List<IMessageToken> messageParts = TemplateParser.Tokenize(template, wovenMethod, attribute.IncludeParamName); MakeFormatString(messageParts, messageFormatString, nonStaticTokens); // Sequence that contains the logging check and the logging itself. InstructionSequence logEntrySequence = wovenMethod.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(logEntrySequence, NodePosition.Before, null); // Sequence that follows the logging code. InstructionSequence afterLoggingSequence = wovenMethod.MethodBody.CreateInstructionSequence(); block.AddInstructionSequence(afterLoggingSequence, NodePosition.After, logEntrySequence); // Check if logging is enabled and log the message. context.InstructionWriter.AttachInstructionSequence(logEntrySequence); context.InstructionWriter.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden); EmitLoggingEnabledCheck(context.InstructionWriter, supportItem, perTypeLoggingData, afterLoggingSequence); if (nonStaticTokens.Count == 0) { // There are no dynamic tokens, use the faster logging method. EmitLogString(context.InstructionWriter, perTypeLoggingData.Log, supportItem.LogStringMethod, messageFormatString.ToString()); } else { // There are dynamic tokens, prepare log message at run-time. LocalVariableSymbol args = this.EmitCreateFormatArgumentArray(context, block, nonStaticTokens); EmitLogProviderStringArgs(context.InstructionWriter, perTypeLoggingData.Log, supportItem.LogCultureStringArgsMethod, this.parent.InvariantCultureGetter, messageFormatString.ToString(), args); } context.InstructionWriter.DetachInstructionSequence(); // Logging is finished (or skipped), do nothing. context.InstructionWriter.AttachInstructionSequence(afterLoggingSequence); context.InstructionWriter.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden); context.InstructionWriter.EmitInstruction(OpCodeNumber.Nop); context.InstructionWriter.DetachInstructionSequence(); } }
public void Weave(WeavingContext context, InstructionBlock block) { switch (context.JoinPoint.JoinPointKind) { case JoinPointKinds.AfterMethodBodyException: this.WeaveException(context, block); break; case JoinPointKinds.AfterMethodBodySuccess: this.WeaveSuccess(context, block); break; case JoinPointKinds.BeforeMethodBody: this.WeaveEnter(context, block); break; } }
private void EmitMessage(InstructionBlock block, InstructionWriter writer, MethodDefDeclaration targetMethod, string messageFormatString) { // TODO: nested types string category = targetMethod.DeclaringType.Name; ILoggingCategoryBuilder builder = this.backendInstance.GetCategoryBuilder(category); InstructionSequence sequence = block.AddInstructionSequence(null, NodePosition.After, null); writer.AttachInstructionSequence(sequence); if (builder.SupportsIsEnabled) { builder.EmitGetIsEnabled(writer, LogSeverity.Trace); InstructionSequence branchSequence = block.AddInstructionSequence(null, NodePosition.After, sequence); writer.EmitBranchingInstruction(OpCodeNumber.Brfalse_S, branchSequence); } int parameterCount = Context.MethodMapping.MethodSignature.ParameterCount; bool hasThis = Context.MethodMapping.MethodSignature.CallingConvention == CallingConvention.HasThis; builder.EmitWrite(writer, block, messageFormatString, parameterCount, LogSeverity.Trace, null, (i, instructionWriter) => { instructionWriter.EmitInstructionInt16(OpCodeNumber.Ldarg, (short)(hasThis ? i + 1 : i)); instructionWriter.EmitConvertToObject( this.Context.MethodMapping.MethodSignature.GetParameterType(i)); }); writer.DetachInstructionSequence(); }
protected override void ImplementOnSuccess(InstructionBlock block, InstructionWriter writer) { MethodDefDeclaration targetMethod = Context.TargetElement as MethodDefDeclaration; if (targetMethod == null) { return; } string messageFormatString = this.CreateMessageFormatString(this.onSuccessOptions, targetMethod); this.EmitMessage(block, writer, targetMethod, "Leaving: " + messageFormatString); }
protected override void ImplementOnExit(InstructionBlock block, InstructionWriter writer) { }
protected override void ImplementOnException(InstructionBlock block, ITypeSignature exceptionType, InstructionWriter writer) { MethodDefDeclaration targetMethod = this.transformationInstance.AspectWeaverInstance.TargetElement as MethodDefDeclaration; if (targetMethod == null) { return; } // TODO: nested types string category = targetMethod.DeclaringType.Name; ILoggingCategoryBuilder builder = this.backendInstance.GetCategoryBuilder(category); InstructionSequence sequence = block.AddInstructionSequence(null, NodePosition.After, null); writer.AttachInstructionSequence(sequence); LocalVariableSymbol exceptionLocal = block.MethodBody.RootInstructionBlock.DefineLocalVariable( exceptionType, DebuggerSpecialNames.GetVariableSpecialName("ex")); LogSeverity logSeverity = LogSeverity.Warning; if (builder.SupportsIsEnabled) { builder.EmitGetIsEnabled(writer, logSeverity); InstructionSequence branchSequence = block.AddInstructionSequence(null, NodePosition.After, sequence); writer.EmitBranchingInstruction(OpCodeNumber.Brfalse_S, branchSequence); } builder.EmitWrite(writer, block, "An exception occurred:\n{0}", 1, logSeverity, w => w.EmitInstructionLocalVariable(OpCodeNumber.Stloc, exceptionLocal), (i, w) => w.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, exceptionLocal)); writer.EmitInstruction(OpCodeNumber.Rethrow); writer.DetachInstructionSequence(); }