/// <summary> /// Creates and adds a new node to the collection of data flow nodes. /// </summary> /// <param name="id">The unique identifier of the node.</param> /// <param name="contents">The contents of the node.</param> /// <returns>The created node.</returns> public DataFlowNode <TContents> Add(long id, TContents contents) { var node = new DataFlowNode <TContents>(id, contents); Add(node); return(node); }
private void CollectStackDependencies( BasicBlock <Statement <TInstruction> > block, DataFlowNode <TInstruction> dataFlowNode, Span <IVariable> buffer, ref int phiStatementCount) { var stackDependencies = dataFlowNode.StackDependencies; for (int i = 0; i < stackDependencies.Count; i++) { var sources = stackDependencies[i]; if (sources.Count == 1) { // If the dependency only has 1 possible data source, we can simply // create a stack slot and an assignment to that slot. buffer[i] = GetStackSlot(sources.First()); } else { // If we have more than 1 possible data source, we // will add a "phi" node. This basically means // that the result of the "phi function" will return // the value based on prior control flow. var phi = CreatePhiSlot(); var slots = sources .Select(source => new VariableExpression <TInstruction>(GetStackSlot(source))) .ToArray(); block.Instructions.Insert(phiStatementCount++, new PhiStatement <TInstruction>(phi, slots)); buffer[i] = phi; } } }
/// <summary> /// Constructor. /// </summary> /// <param name="symbol">ISymbol</param> /// <param name="dfgNode">DataFlowNode</param> internal SymbolDefinition(ISymbol symbol, DataFlowNode dfgNode) { this.DataFlowNode = dfgNode; this.Symbol = symbol; this.CandidateTypes = new HashSet<ITypeSymbol>(); this.Kind = symbol.Kind; this.Name = $"[{this.DataFlowNode.Id},{this.Kind}]::{this.Symbol.Name}"; }
public void AddNodeToGraphShouldSetParentGraph() { var dfg = new DataFlowGraph <int>(IntArchitecture.Instance); var node = new DataFlowNode <int>(1, 2); dfg.Nodes.Add(node); Assert.Same(dfg, node.ParentGraph); }
/// <inheritdoc /> public bool Contains(DataFlowNode <TContents> item) { if (item == null) { return(false); } return(_nodes.TryGetValue(item.Id, out var node) && node == item); }
public void RemoveNodeFromGraphShouldUnsetParentGraph() { var dfg = new DataFlowGraph <int>(IntArchitecture.Instance); var node = new DataFlowNode <int>(1, 2); dfg.Nodes.Add(node); dfg.Nodes.Remove(node); Assert.Null(node.ParentGraph); }
/// <summary> /// Constructor. /// </summary> /// <param name="dfgNode">DataFlowNode</param> /// <param name="context">AnalysisContext</param> internal DataFlowInfo(DataFlowNode dfgNode, AnalysisContext context) { this.AnalysisContext = context; this.DataFlowNode = dfgNode; this.GeneratedDefinitions = new HashSet<SymbolDefinition>(); this.KilledDefinitions = new HashSet<SymbolDefinition>(); this.InputDefinitions = new HashSet<SymbolDefinition>(); this.OutputDefinitions = new HashSet<SymbolDefinition>(); this.TaintedDefinitions = new Dictionary<SymbolDefinition, ISet<SymbolDefinition>>(); }
public void DisconnectNodeShouldRemoveEdge(DataDependencyType edgeType, bool removeSourceNode) { var variable = new DummyVariable("var"); var graph = new DataFlowGraph <int>(IntArchitecture.Instance); var n1 = new DataFlowNode <int>(0, 0); n1.StackDependencies.Add(new DataDependency <int>()); n1.VariableDependencies.Add(variable, new DataDependency <int>()); var n2 = new DataFlowNode <int>(1, 1); graph.Nodes.AddRange(new[] { n1, n2 }); switch (edgeType) { case DataDependencyType.Stack: n1.StackDependencies[0].Add(new DataSource <int>(n2)); break; case DataDependencyType.Variable: n1.VariableDependencies[variable].Add(new DataSource <int>(n2)); break; default: throw new ArgumentOutOfRangeException(nameof(edgeType), edgeType, null); } if (removeSourceNode) { n1.Disconnect(); } else { n2.Disconnect(); } Assert.Empty(n1.StackDependencies[0]); Assert.Empty(n1.VariableDependencies[variable]); Assert.Empty(n2.GetDependants()); }
/// <inheritdoc /> public void Add(DataFlowNode <TContents> item) { if (item.ParentGraph == _owner) { return; } if (item.ParentGraph != null) { throw new ArgumentException("Cannot add a node from another graph."); } if (_nodes.ContainsKey(item.Id)) { throw new ArgumentException($"A node with identifier 0x{item.Id:X8} was already added to the graph."); } _nodes.Add(item.Id, item); item.ParentGraph = _owner; }
/// <summary> /// Collects all dependency nodes recursively, and sorts them in a topological order such that the final collection /// of nodes can be executed sequentially. /// </summary> /// <param name="node">The node to find all dependencies for.</param> /// <param name="flags">Flags that influence the behaviour of the algorithm.</param> /// <typeparam name="T">The type of contents that each node contains.</typeparam> /// <returns>The topological ordering of all dependencies of the node.</returns> /// <exception cref="CyclicDependencyException">Occurs when there is a cyclic dependency in the graph.</exception> public static IEnumerable <DataFlowNode <T> > GetOrderedDependencies <T>(this DataFlowNode <T> node, DependencyCollectionFlags flags) { try { var topologicalSorting = new TopologicalSorter <DataFlowNode <T> >(GetSortedOutgoingEdges); return(topologicalSorting.GetTopologicalSorting(node)); } catch (CycleDetectedException ex) { throw new CyclicDependencyException("Cyclic dependency was detected.", ex); } IReadOnlyList <DataFlowNode <T> > GetSortedOutgoingEdges(DataFlowNode <T> n) { var result = new List <DataFlowNode <T> >(); // Prioritize stack dependencies over variable dependencies. if ((flags & DependencyCollectionFlags.IncludeStackDependencies) != 0) { foreach (var dependency in n.StackDependencies) { if (dependency.HasKnownDataSources) { result.Add(dependency.First().Node); } } } if ((flags & DependencyCollectionFlags.IncludeVariableDependencies) != 0) { foreach (var entry in n.VariableDependencies) { if (entry.Value.HasKnownDataSources) { result.Add(entry.Value.First().Node); } } } return(result); } }
/// <summary> /// Creates a new stack data source, referencing a stack value produced by the provided node. /// </summary> /// <param name="node">The node producing the value.</param> /// <param name="slotIndex">The index of the stack value that was produced by the node.</param> public StackDataSource(DataFlowNode <TContents> node, int slotIndex) : base(node) { SlotIndex = slotIndex; }
/// <summary> /// Creates a new stack data source, referencing the first stack value produced by the provided node. /// </summary> /// <param name="node">The node producing the value.</param> public StackDataSource(DataFlowNode <TContents> node) : base(node) { }
/// <summary> /// Collects all dependency nodes recursively, and sorts them in a topological order such that the final collection /// of nodes can be executed sequentially. /// </summary> /// <param name="node">The node to find all dependencies for.</param> /// <typeparam name="T">The type of contents that each node contains.</typeparam> /// <returns>The topological ordering of all dependencies of the node.</returns> /// <exception cref="CyclicDependencyException">Occurs when there is a cyclic dependency in the graph.</exception> public static IEnumerable <DataFlowNode <T> > GetOrderedDependencies <T>(this DataFlowNode <T> node) => GetOrderedDependencies(node, DependencyCollectionFlags.IncludeAllDependencies);
internal VariableDependencyCollection(DataFlowNode <TContents> owner) { _owner = owner ?? throw new ArgumentNullException(nameof(owner)); }
/// <inheritdoc /> public bool Remove(DataFlowNode <TContents> item) => item != null && Remove(item.Id);
private void CollectVariableDependencies( BasicBlock <Statement <TInstruction> > block, DataFlowNode <TInstruction> dataFlowNode, Span <IVariable> buffer, ref int phiStatementCount) { int index = 0; var variableDependencies = dataFlowNode.VariableDependencies; foreach (var pair in variableDependencies) { var variable = pair.Key; var dependency = pair.Value; if (dependency.Count <= 1) { // If the dependency has only 1 possible source we just simply // get the variable. But since the AST utilizes SSA, all of the // variables are versioned. This is good because everything is // "immutable". One "real" variable will have a new versioned // variable created every time it is assigned to. int version = _context.GetVariableVersion(variable); var snapshot = new VariableSnapshot(variable, version); buffer[index++] = _context.GetVersionedVariable(snapshot); continue; } // Otherwise (>0), we will get the list of versioned(!) variables // that could reach the instruction and create a "phi" statement // like in the stack dependencies. var sources = CollectVariables(); if (_context.VariableSourcesToPhiVariable.TryGetValue(sources, out var phi)) { // If a phi slot already exists for the list of variables, // reuse the same phi slot. buffer[index++] = phi; } else { // Otherwise, create a new phi slot for the list of variables // and save it if we encounter the same variables again. phi = CreatePhiSlot(); var slots = sources .Select(source => new VariableExpression <TInstruction>(source)) .ToArray(); _context.VariableSourcesToPhiVariable.Add(sources, phi); block.Instructions.Insert(phiStatementCount++, new PhiStatement <TInstruction>(phi, slots)); buffer[index++] = phi; } List <AstVariable> CollectVariables() { var result = new List <AstVariable>(); foreach (var instruction in dependency.Select(dep => dep.Node.Contents)) { if (_context.VariableStates.TryGetValue(instruction, out var versions)) { // If we already have a dictionary for the instruction, we will // just get the versioned variable from the existing dictionary. var snapshot = new VariableSnapshot(variable, versions[variable]); result.Add(_context.VersionedVariables[snapshot]); } else { // Otherwise, we will create a new dictionary for the instruction. var snapshot = new VariableSnapshot(variable, 0); var slot = _context.GetVersionedVariable(snapshot); _context.VariableStates.Add(instruction, new Dictionary <IVariable, int> { [variable] = 0 }); result.Add(slot); } } return(result); } } }
/// <summary> /// Creates a new symbolic value with a single data source. /// </summary> /// <param name="dataSource">The data source of the symbolic value.</param> public SymbolicValue(DataFlowNode <T> dataSource) : this(new DataSource <T>(dataSource, 0)) { }
public void ConstructorShouldSetContents() { var node = new DataFlowNode <int>(1, 2); Assert.Equal(2, node.Contents); }