/// <summary> /// Rewrites the blocks in the given cdfg so that every assignment to a local or parameter is to a new local (and thus each local is just /// assigned to in exactly one place in the graph). The new names introduced by the writes are connected to the reads in successor blocks /// by means of join points (a.k.a. Phi nodes) that are found in the Reads property of an SSABasicBlock. /// </summary> /// <param name="cdfg"> /// A set of basic blocks, each of which has a list of successor blocks and some other information. /// Each block consists of a list of instructions, each of which can point to previous instructions that compute the operands it consumes. /// </param> /// <param name="cfgQueries"> /// Presents information derived from a simple control flow graph. For example, traversal orders, predecessors, dominators and dominance frontiers. /// </param> /// <param name="nameTable"> /// An extensible collection of IName instances that represent names that are commonly used during compilation. /// </param> /// <param name="sourceLocationProvider"></param> public static void GetInSingleAssignmentForm(INameTable nameTable, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg, ControlGraphQueries <BasicBlock, Instruction> cfgQueries, ISourceLocationProvider sourceLocationProvider) { Contract.Requires(nameTable != null); Contract.Requires(cdfg != null); Contract.Requires(cfgQueries != null); var singleAssigner = new SingleAssigner <BasicBlock, Instruction>(nameTable, cdfg, cfgQueries, sourceLocationProvider); singleAssigner.GetInSingleAssignmentForm(); }
/// <summary> /// Initializes an instance of SingleAssigner. /// </summary> /// <param name="cdfg"> /// A set of basic blocks, each of which has a list of successor blocks and some other information. /// Each block consists of a list of instructions, each of which can point to previous instructions that compute the operands it consumes. /// </param> /// <param name="nameTable"> /// An extensible collection of IName instances that represent names that are commonly used during compilation. /// </param> /// <param name="cfgQueries"></param> /// <param name="sourceLocationProvider">An object that can map some kinds of ILocation objects to IPrimarySourceLocation objects. May be null.</param> private SingleAssigner(INameTable nameTable, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg, ControlGraphQueries <BasicBlock, Instruction> cfgQueries, ISourceLocationProvider sourceLocationProvider) { Contract.Requires(nameTable != null); Contract.Requires(cdfg != null); Contract.Requires(cfgQueries != null); this.nameTable = nameTable; this.cdfg = cdfg; this.cfgQueries = cfgQueries; this.sourceLocationProvider = sourceLocationProvider; }
private TypeInferencer(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cfg, Stack <Instruction> stack, Queue <BasicBlock> blocksToVisit, SetOfObjects blocksAlreadyVisited) { Contract.Requires(host != null); Contract.Requires(cfg != null); Contract.Requires(stack != null); Contract.Requires(blocksToVisit != null); Contract.Requires(blocksAlreadyVisited != null); this.platformType = host.PlatformType; this.cfg = cfg; this.stack = stack; this.blocksToVisit = blocksToVisit; this.blocksAlreadyVisited = blocksAlreadyVisited; this.internFactory = host.InternFactory; }
private DataFlowInferencer(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg) { Contract.Requires(host != null); Contract.Requires(cdfg != null); var numberOfBlocks = cdfg.BlockFor.Count; this.platformType = host.PlatformType; this.cdfg = cdfg; this.operandStackSetupInstructions = new List <Instruction>(cdfg.MethodBody.MaxStack); this.stack = new Stack <Instruction>(cdfg.MethodBody.MaxStack); this.blocksToVisit = new Queue <BasicBlock>((int)numberOfBlocks); this.blocksAlreadyVisited = new SetOfObjects(numberOfBlocks);; this.internFactory = host.InternFactory; }
/// <summary> /// /// </summary> internal static void FillInTypes(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cfg) { Contract.Requires(host != null); Contract.Requires(cfg != null); //If this is a dummy body, do nothing. if (cfg.AllBlocks.Count == 1 && cfg.AllBlocks[0] != null && cfg.AllBlocks[0].Instructions.Count <= 1) { return; } var stack = new Stack <Instruction>(cfg.MethodBody.MaxStack, new List <Instruction>(0)); var numberOfBlocks = cfg.BlockFor.Count; var blocksToVisit = new Queue <BasicBlock>((int)numberOfBlocks); var blocksAlreadyVisited = new SetOfObjects(numberOfBlocks); var inferencer = new TypeInferencer <BasicBlock, Instruction>(host, cfg, stack, blocksToVisit, blocksAlreadyVisited); foreach (var root in cfg.RootBlocks) { blocksToVisit.Enqueue(root); while (blocksToVisit.Count != 0) { inferencer.DequeueBlockAndFillInItsTypes(); } } //At this point, all reachable code blocks have had their types inferred. Now look for unreachable blocks. foreach (var block in cfg.AllBlocks) { if (blocksAlreadyVisited.Contains(block)) { continue; } blocksToVisit.Enqueue(block); while (blocksToVisit.Count != 0) { inferencer.DequeueBlockAndFillInItsTypes(); } } }
internal static void FillInHandlers(IMetadataHost host, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg) { var method = cdfg.MethodBody; var handlers = new List <IOperationExceptionInformation>(method.OperationExceptionInformation).ToArray(); #region Compute enclosing handlers for each block FList <IOperationExceptionInformation> currentHandlers = null; FList <IOperationExceptionInformation> containingHandlers = null; foreach (var current in cdfg.AllBlocks) { //traceFile.WriteLine("Block at: {0:x3}", current.Offset); currentHandlers = PopPushHandlers(current, currentHandlers, handlers, ref containingHandlers); } #endregion // now compute extra block information: // - local def maps // - parameter def maps ComputeDataFlowThroughLocals(cdfg); }
/// <summary> /// Presents information derived from a simple control flow graph. For example, traversal orders, predecessors, dominators and dominance frontiers. /// </summary> /// <param name="controlFlowGraph">The simple control flow graph from which to derive the information.</param> public ControlGraphQueries(ControlAndDataFlowGraph <BasicBlock, Instruction> controlFlowGraph) { Contract.Requires(controlFlowGraph != null); this.cfg = controlFlowGraph; }
private static void ComputeDataFlowThroughLocals(ControlAndDataFlowGraph <BasicBlock, Instruction> cdg) { FMap <ILocalDefinition, Microsoft.Cci.Analysis.Instruction> currentLocals; var todo = new Queue <BlockPC>(); var seen = new HashSet <BlockPC>(); var startBlock = cdg.RootBlocks[0]; FMap <IParameterDefinition, Microsoft.Cci.Analysis.Instruction> currentParameters = new FMap <IParameterDefinition, Microsoft.Cci.Analysis.Instruction>(k => k.Index); var initialLocation = GetStartLocation(startBlock); // push parameters onto start block foreach (var arg in cdg.MethodBody.MethodDefinition.Parameters) { var initialOp = new InitialParameterAssignment(arg, initialLocation); var initialDef = new Instruction() { Operation = initialOp }; currentParameters = currentParameters.Insert(arg, initialDef); } startBlock.ParamDefs = currentParameters; todo.Enqueue(new BlockPC(startBlock.Offset.Singleton())); while (todo.Count > 0) { var currentPC = todo.Dequeue(); if (seen.Contains(currentPC)) { continue; } seen.Add(currentPC); var block = cdg.CurrentBlock(currentPC); Contract.Assume(block != null); currentLocals = block.LocalDefs; currentParameters = block.ParamDefs; foreach (var instr in block.Instructions) { if (instr.IsMergeNode) { continue; } switch (instr.Operation.OperationCode) { case OperationCode.Starg: case OperationCode.Starg_S: // without pdb we seem to have no parameter info. var pdef = (IParameterDefinition)instr.Operation.Value; if (pdef != null) { currentParameters = currentParameters.Insert(pdef, instr.Operand1); } break; case OperationCode.Stloc: case OperationCode.Stloc_0: case OperationCode.Stloc_1: case OperationCode.Stloc_2: case OperationCode.Stloc_3: case OperationCode.Stloc_S: var ldef = (ILocalDefinition)instr.Operation.Value; currentLocals = currentLocals.Insert(ldef, instr.Operand1); break; case OperationCode.Ldloc: case OperationCode.Ldloc_0: case OperationCode.Ldloc_1: case OperationCode.Ldloc_2: case OperationCode.Ldloc_3: case OperationCode.Ldloc_S: // save the source in Aux { currentLocals.TryGetValue((ILocalDefinition)instr.Operation.Value, out instr.Aux); break; } case OperationCode.Ldarg: case OperationCode.Ldarg_0: case OperationCode.Ldarg_1: case OperationCode.Ldarg_2: case OperationCode.Ldarg_3: case OperationCode.Ldarg_S: // save the source in Aux var pdef2 = (IParameterDefinition)instr.Operation.Value; if (pdef2 == null) { // this parameter. Assume it's never overwritten } else { currentParameters.TryGetValue(pdef2, out instr.Aux); } break; case OperationCode.Stind_I: case OperationCode.Stind_I1: case OperationCode.Stind_I2: case OperationCode.Stind_I4: case OperationCode.Stind_I8: case OperationCode.Stind_R4: case OperationCode.Stind_R8: case OperationCode.Stind_Ref: { var location = cdg.LocalOrParameter(instr.Operand1); UpdateLocation(ref currentLocals, ref currentParameters, location, (Analysis.Instruction)instr.Operand2); break; } case OperationCode.Ldind_I: case OperationCode.Ldind_I1: case OperationCode.Ldind_I2: case OperationCode.Ldind_I4: case OperationCode.Ldind_I8: case OperationCode.Ldind_R4: case OperationCode.Ldind_R8: case OperationCode.Ldind_Ref: case OperationCode.Ldind_U1: case OperationCode.Ldind_U2: case OperationCode.Ldind_U4: { // save the read value in Aux var location = cdg.LocalOrParameter(instr.Operand1); instr.Aux = ReadLocation(currentLocals, currentParameters, location); break; } case OperationCode.Call: case OperationCode.Callvirt: { // update byref / out parameters var methodRef = instr.Operation.Value as IMethodReference; var args = instr.Operand2 as Instruction[]; if (args != null && methodRef != null) { foreach (var p in methodRef.Parameters) { if (p.IsByReference && p.Index < args.Length) { var arg = args[p.Index]; if (arg != null) { var loc = cdg.LocalOrParameter(arg); var syntheticOp = new CallByRefAssignment(instr, p); UpdateLocation(ref currentLocals, ref currentParameters, loc, new Instruction() { Operation = syntheticOp, Type = p.Type }); } } } } break; } } instr.PostLocalDefs = currentLocals; instr.PostParamDefs = currentParameters; } foreach (var succ in cdg.Successors(currentPC)) { MergeLocalsAndParameters(cdg.CurrentBlock(succ), currentLocals, currentParameters); todo.Enqueue(succ); } } }
/// <summary> /// /// </summary> internal static void SetupDataFlow(IMetadataHost host, IMethodBody methodBody, ControlAndDataFlowGraph <BasicBlock, Instruction> cdfg) { Contract.Requires(host != null); Contract.Requires(methodBody != null); Contract.Requires(cdfg != null); var dataFlowInferencer = new DataFlowInferencer <BasicBlock, Instruction>(host, cdfg); dataFlowInferencer.SetupDataFlowFor(methodBody); }