we are moving form post dominators.
This commit is contained in:
24
README.md
24
README.md
@@ -1,12 +1,14 @@
|
|||||||
# Final Project
|
### Things
|
||||||
---
|
1. Forward Slice => All statements that could be affected if you change a given statement.Think of it like ripple effects in water:
|
||||||
|
|
||||||
1. To run the program please run the script:
|
|
||||||
```bash
|
|
||||||
chmod +x build.sh
|
### Run
|
||||||
./build.sh
|
|
||||||
```
|
```bash
|
||||||
2. To run the program with bash run the command:
|
# Show all dependencies for a file
|
||||||
```bash
|
./run.sh examples/Example1.java
|
||||||
bash build.sh
|
|
||||||
```
|
# Analyze impact of line 3
|
||||||
|
./run.sh examples/Example1.java 3
|
||||||
|
```
|
||||||
|
|||||||
43
build.sh
43
build.sh
@@ -1,43 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
GREEN="\033[32m"
|
|
||||||
RESET="\033[0m"
|
|
||||||
echo ""
|
|
||||||
echo "==== CPSC 449 Project ===="
|
|
||||||
|
|
||||||
# Create lib directory
|
|
||||||
mkdir -p bin
|
|
||||||
|
|
||||||
echo "1. Checking dependencies"
|
|
||||||
|
|
||||||
if [ ! -f "lib/antlr-4.9.3-complete.jar" ]; then
|
|
||||||
echo " Please Download ANTLR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "lib/jgrapht-core-1.5.1.jar" ]; then
|
|
||||||
echo " Please Download JGraphT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "lib/jgrapht-io-1.5.1.jar" ]; then
|
|
||||||
echo " Please Download JGraphT IO"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo " [x] All dependencies acounted for"
|
|
||||||
|
|
||||||
CP="lib/antlr-4.9.3-complete.jar:lib/jgrapht-core-1.5.1.jar:lib/jgrapht-io-1.5.1.jar"
|
|
||||||
|
|
||||||
echo "2. Compiling CFG packages"
|
|
||||||
javac -d bin -cp "$CP" src/org/lsmr/cfg/*.java
|
|
||||||
echo " [x] CFG compiled"
|
|
||||||
|
|
||||||
echo "3. Compiling PDG packages"
|
|
||||||
javac -d bin -cp "$CP:bin" src/pdg/*.java
|
|
||||||
echo " [x] PDG compiled"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "${GREEN}==== Compilation Complete! ====${RESET}"
|
|
||||||
echo -e "${GREEN}Compiled classes are in: bin/${RESET}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${GREEN}>> To run this program:${RESET}"
|
|
||||||
echo -e "${GREEN} java -cp bin:$CP YourMainClass${RESET}"
|
|
||||||
echo ""
|
|
||||||
BIN
lib/.DS_Store
vendored
Normal file
BIN
lib/.DS_Store
vendored
Normal file
Binary file not shown.
27
run.sh
Executable file
27
run.sh
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ "$#" -lt 1 ]; then
|
||||||
|
echo "Usage: ./run.sh <file> [line]"
|
||||||
|
echo "Example: ./run.sh examples/Example1.java 3"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for antlr jar
|
||||||
|
if [ ! -f "lib/antlr-4.13.2-complete.jar" ]; then
|
||||||
|
echo "ERROR: Put antlr-4.13.2-complete.jar in lib/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build if needed be
|
||||||
|
if [ ! -d "bin/pdg" ]; then
|
||||||
|
echo "Building..."
|
||||||
|
mkdir -p bin
|
||||||
|
CP="lib/antlr-4.13.2-complete.jar"
|
||||||
|
javac -d bin -cp "$CP" src/org/lsmr/cfg/*.java || exit 1
|
||||||
|
javac -d bin -cp "$CP:bin" src/pdg/PDG.java || exit 1
|
||||||
|
javac -d bin -cp "$CP:bin" src/CFGBuilder.java src/PDGTool.java || exit 1
|
||||||
|
echo "Build complete!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run
|
||||||
|
java -cp "bin:lib/antlr-4.13.2-complete.jar" PDGTool "$@"
|
||||||
BIN
src/.DS_Store
vendored
BIN
src/.DS_Store
vendored
Binary file not shown.
130
src/CFGBuilder.java
Normal file
130
src/CFGBuilder.java
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import org.lsmr.cfg.*;
|
||||||
|
import org.antlr.v4.runtime.*;
|
||||||
|
import org.antlr.v4.runtime.tree.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class CFGBuilder {
|
||||||
|
|
||||||
|
private Map<Node, Integer> nodeToLine = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build CFG from a Java file
|
||||||
|
*/
|
||||||
|
public ControlFlowGraph buildFromFile(String filename) throws IOException {
|
||||||
|
System.out.println("\n\tBuilding CFG from " + filename);
|
||||||
|
|
||||||
|
// Parse the file
|
||||||
|
CharStream input = CharStreams.fromFileName(filename);
|
||||||
|
Java1_4Lexer lexer = new Java1_4Lexer(input);
|
||||||
|
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||||
|
Java1_4Parser parser = new Java1_4Parser(tokens);
|
||||||
|
|
||||||
|
parser.removeErrorListeners();
|
||||||
|
|
||||||
|
ParseTree tree = parser.compilationUnit();
|
||||||
|
|
||||||
|
// build CFG using professor's NodeBuilder
|
||||||
|
NodeBuilder builder = new NodeBuilder();
|
||||||
|
builder.visit(tree);
|
||||||
|
|
||||||
|
List<ControlFlowGraph> cfgs = builder.getCFGs();
|
||||||
|
|
||||||
|
if (cfgs.isEmpty()) {
|
||||||
|
throw new RuntimeException("No methods found in file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfgs.size() > 1) {
|
||||||
|
System.out.println("Note: File has " + cfgs.size() + " methods, using first method");
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlFlowGraph cfg = cfgs.get(0);
|
||||||
|
|
||||||
|
extractLineNumbers(cfg, tree);
|
||||||
|
|
||||||
|
System.out.println("CFG built: " + cfg.nodes().size() + " nodes, " + cfg.edges().size() + " edges");
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
private void extractLineNumbers(ControlFlowGraph cfg, ParseTree tree) {
|
||||||
|
Map<String, Integer> labelToLine = new HashMap<>();
|
||||||
|
collectLineNumbers(tree, labelToLine);
|
||||||
|
|
||||||
|
for (Node node : cfg.nodes()) {
|
||||||
|
String label = node.label();
|
||||||
|
Integer line = labelToLine.get(label);
|
||||||
|
|
||||||
|
if (line == null) {
|
||||||
|
for (Map.Entry<String, Integer> entry : labelToLine.entrySet()) {
|
||||||
|
if (label.contains(entry.getKey()) || entry.getKey().contains(label)) {
|
||||||
|
line = entry.getValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeToLine.put(node, line != null ? line : -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void collectLineNumbers(ParseTree tree, Map<String, Integer> map) {
|
||||||
|
if (tree instanceof ParserRuleContext) {
|
||||||
|
ParserRuleContext ctx = (ParserRuleContext) tree;
|
||||||
|
if (ctx.start != null) {
|
||||||
|
String text = ctx.getText();
|
||||||
|
if (text != null && text.length() < 200 && text.length() > 0) {
|
||||||
|
map.put(text, ctx.start.getLine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < tree.getChildCount(); i++) {
|
||||||
|
collectLineNumbers(tree.getChild(i), map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getLineNumber(Node node) {
|
||||||
|
return nodeToLine.getOrDefault(node, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getAllLineNumbers() {
|
||||||
|
Set<Integer> lines = new TreeSet<>();
|
||||||
|
for (Integer line : nodeToLine.values()) {
|
||||||
|
if (line > 0) lines.add(line);
|
||||||
|
}
|
||||||
|
return new ArrayList<>(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Node> findNodesAtLine(ControlFlowGraph cfg, int lineNumber) {
|
||||||
|
List<Node> result = new ArrayList<>();
|
||||||
|
for (Node node : cfg.nodes()) {
|
||||||
|
if (getLineNumber(node) == lineNumber) {
|
||||||
|
result.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printLineMapping(ControlFlowGraph cfg) {
|
||||||
|
System.out.println("\n Line Number Mapping");
|
||||||
|
Map<Integer, List<String>> lineToNodes = new TreeMap<>();
|
||||||
|
|
||||||
|
for (Node node : cfg.nodes()) {
|
||||||
|
int line = getLineNumber(node);
|
||||||
|
if (line > 0) {
|
||||||
|
lineToNodes.putIfAbsent(line, new ArrayList<>());
|
||||||
|
lineToNodes.get(line).add(node.label());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, List<String>> entry : lineToNodes.entrySet()) {
|
||||||
|
System.out.println("Line " + entry.getKey() + ":");
|
||||||
|
for (String label : entry.getValue()) {
|
||||||
|
System.out.println(" " + label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
106
src/PDGTool.java
Normal file
106
src/PDGTool.java
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import org.lsmr.cfg.*;
|
||||||
|
import pdg.PDG;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDG Tool: Change Impact Analysis
|
||||||
|
* Usage: java PDGTool <java-file> [line-number]
|
||||||
|
*/
|
||||||
|
public class PDGTool {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
if (args.length < 1) {
|
||||||
|
System.err.println("Usage: java PDGTool <java-file> [line-number]");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String filename = args[0];
|
||||||
|
Integer targetLine = args.length > 1 ? Integer.parseInt(args[1]) : null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
analyzePDG(filename, targetLine);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void analyzePDG(String filename, Integer targetLine) throws IOException {
|
||||||
|
System.out.println("PDG Analysis Tool");
|
||||||
|
System.out.println("File: " + filename);
|
||||||
|
if (targetLine != null) {
|
||||||
|
System.out.println("Target line: " + targetLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Build CFG
|
||||||
|
CFGBuilder cfgBuilder = new CFGBuilder();
|
||||||
|
ControlFlowGraph cfg = cfgBuilder.buildFromFile(filename);
|
||||||
|
|
||||||
|
// Step 2: Build PDG
|
||||||
|
PDG pdg = new PDG(cfg);
|
||||||
|
|
||||||
|
// Step 3: Show results
|
||||||
|
System.out.println("\n=== Available Lines ===");
|
||||||
|
List<Integer> lines = cfgBuilder.getAllLineNumbers();
|
||||||
|
System.out.println("Lines with statements: " + lines);
|
||||||
|
|
||||||
|
// If specific line requested, compute impact
|
||||||
|
if (targetLine != null) {
|
||||||
|
computeImpact(cfg, pdg, cfgBuilder, targetLine);
|
||||||
|
} else {
|
||||||
|
// Show all dependencies
|
||||||
|
System.out.println("\n=== All Dependencies ===");
|
||||||
|
pdg.printPDG();
|
||||||
|
cfgBuilder.printLineMapping(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void computeImpact(ControlFlowGraph cfg, PDG pdg,
|
||||||
|
CFGBuilder cfgBuilder, int targetLine) {
|
||||||
|
System.out.println("\n=== Impact Analysis for Line " + targetLine + " ===");
|
||||||
|
|
||||||
|
// Find nodes at target line
|
||||||
|
List<Node> nodesAtLine = cfgBuilder.findNodesAtLine(cfg, targetLine);
|
||||||
|
|
||||||
|
if (nodesAtLine.isEmpty()) {
|
||||||
|
System.out.println("WARNING: No executable statement at line " + targetLine);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\nStatement(s) at line " + targetLine + ":");
|
||||||
|
for (Node node : nodesAtLine) {
|
||||||
|
System.out.println(" " + node.label());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute forward slice
|
||||||
|
Set<String> allImpacted = new HashSet<>();
|
||||||
|
for (Node node : nodesAtLine) {
|
||||||
|
Set<String> impacted = pdg.computeForwardSlice(node.label());
|
||||||
|
allImpacted.addAll(impacted);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to line numbers
|
||||||
|
Set<Integer> impactedLines = new TreeSet<>();
|
||||||
|
for (Node node : cfg.nodes()) {
|
||||||
|
if (allImpacted.contains(node.label())) {
|
||||||
|
int line = cfgBuilder.getLineNumber(node);
|
||||||
|
if (line > 0) {
|
||||||
|
impactedLines.add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\n=== IMPACTED LINES ===");
|
||||||
|
if (impactedLines.isEmpty()) {
|
||||||
|
System.out.println(" (none)");
|
||||||
|
} else {
|
||||||
|
for (int line : impactedLines) {
|
||||||
|
System.out.println(" Line " + line);
|
||||||
|
}
|
||||||
|
System.out.println("\nTotal: " + impactedLines.size() + " lines impacted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
import org.lsmr.cfg.ControlFlowGraph;
|
|
||||||
import org.lsmr.cfg.Node;
|
|
||||||
import org.lsmr.cfg.Edge;
|
|
||||||
import pdg.PDG;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class Test {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println("=== PDG Test ===\n");
|
|
||||||
|
|
||||||
// Create a simple CFG manually
|
|
||||||
ControlFlowGraph cfg = new ControlFlowGraph("testMethod");
|
|
||||||
|
|
||||||
// Create nodes
|
|
||||||
Node n1 = cfg.buildNode("int x = 5");
|
|
||||||
Node n2 = cfg.buildNode("int y = x + 10");
|
|
||||||
Node n3 = cfg.buildNode("int z = y * 2");
|
|
||||||
Node n4 = cfg.buildNode("System.out.println(z)");
|
|
||||||
|
|
||||||
// Connect nodes: entry -> n1 -> n2 -> n3 -> n4 -> exit
|
|
||||||
cfg.buildEdge(cfg.entry, n1, Edge.EdgeLabel.BLANK);
|
|
||||||
cfg.buildEdge(n1, n2, Edge.EdgeLabel.BLANK);
|
|
||||||
cfg.buildEdge(n2, n3, Edge.EdgeLabel.BLANK);
|
|
||||||
cfg.buildEdge(n3, n4, Edge.EdgeLabel.BLANK);
|
|
||||||
cfg.buildEdge(n4, cfg.normalExit, Edge.EdgeLabel.BLANK);
|
|
||||||
|
|
||||||
System.out.println("CFG created with " + cfg.nodes().size() + " nodes");
|
|
||||||
|
|
||||||
// Create PDG from CFG
|
|
||||||
PDG pdg = new PDG(cfg);
|
|
||||||
|
|
||||||
// Print CFG structure
|
|
||||||
pdg.printCFG();
|
|
||||||
|
|
||||||
// Print PDG structure
|
|
||||||
pdg.printPDG();
|
|
||||||
|
|
||||||
// Test impact analysis
|
|
||||||
System.out.println("\n=== Impact Analysis ===");
|
|
||||||
|
|
||||||
String[] testNodes = {"int x = 5", "int y = x + 10", "int z = y * 2"};
|
|
||||||
|
|
||||||
for (String nodeLabel : testNodes) {
|
|
||||||
Set<String> impacted = pdg.computeForwardSlice(nodeLabel);
|
|
||||||
System.out.println("\nChanging '" + nodeLabel + "' impacts:");
|
|
||||||
for (String label : impacted) {
|
|
||||||
if (!label.startsWith("*")) { // Skip special nodes
|
|
||||||
System.out.println(" - " + label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("\n=== Test Complete ===");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BIN
src/org/.DS_Store
vendored
BIN
src/org/.DS_Store
vendored
Binary file not shown.
BIN
src/org/lsmr/.DS_Store
vendored
BIN
src/org/lsmr/.DS_Store
vendored
Binary file not shown.
BIN
src/org/lsmr/cfg/.DS_Store
vendored
Normal file
BIN
src/org/lsmr/cfg/.DS_Store
vendored
Normal file
Binary file not shown.
587
src/pdg/PDG.java
587
src/pdg/PDG.java
@@ -1,454 +1,309 @@
|
|||||||
// program Dependence Graph implementation using the Profs CFG.
|
|
||||||
// combines control dependence and data dependence.
|
|
||||||
package pdg;
|
package pdg;
|
||||||
|
|
||||||
import org.lsmr.cfg.ControlFlowGraph;
|
import org.lsmr.cfg.*;
|
||||||
import org.lsmr.cfg.Node;
|
|
||||||
import org.lsmr.cfg.Edge;
|
|
||||||
import org.jgrapht.Graph;
|
|
||||||
import org.jgrapht.graph.DefaultDirectedGraph;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple Program Dependence Graph (PDG)
|
||||||
|
* Computes control and data dependencies for a CFG
|
||||||
|
*/
|
||||||
public class PDG {
|
public class PDG {
|
||||||
private ControlFlowGraph cfg;
|
|
||||||
private Graph<PDGNode, PDGEdge> pdg;
|
|
||||||
private Map<Node, PDGNode> cfgToPdgMap;
|
|
||||||
|
|
||||||
// Analysis results
|
private ControlFlowGraph cfg;
|
||||||
private Map<Node, Set<Node>> postDominators;
|
private Map<String, Set<String>> controlDeps;
|
||||||
private Map<Node, Set<Node>> controlDependence;
|
private Map<String, Set<String>> dataDeps;
|
||||||
private Map<Node, Set<Node>> dataDependence;
|
|
||||||
|
|
||||||
public PDG(ControlFlowGraph cfg) {
|
public PDG(ControlFlowGraph cfg) {
|
||||||
this.cfg = cfg;
|
this.cfg = cfg;
|
||||||
this.pdg = new DefaultDirectedGraph<>(PDGEdge.class);
|
this.controlDeps = new HashMap<>();
|
||||||
this.cfgToPdgMap = new HashMap<>();
|
this.dataDeps = new HashMap<>();
|
||||||
this.postDominators = new HashMap<>();
|
|
||||||
this.controlDependence = new HashMap<>();
|
|
||||||
this.dataDependence = new HashMap<>();
|
|
||||||
|
|
||||||
buildPDG();
|
System.out.println("Building PDG...");
|
||||||
|
computeControlDependencies();
|
||||||
|
computeDataDependencies();
|
||||||
|
System.out.println("PDG complete!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// build the complete PDG.
|
/**
|
||||||
private void buildPDG() {
|
* Compute control dependencies using simple reachability
|
||||||
// Step 1: create PDG nodes from CFG nodes
|
*/
|
||||||
createPDGNodes();
|
private void computeControlDependencies() {
|
||||||
// Step 2: compute control dependence
|
System.out.println("\tComputing control dependencies...");
|
||||||
computeControlDependence();
|
|
||||||
// Step 3: compute data dependence
|
|
||||||
computeDataDependence();
|
|
||||||
// Step 4: add edges to PDG
|
|
||||||
addPDGEdges();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a PDG node for each CFG node.
|
|
||||||
private void createPDGNodes() {
|
|
||||||
for (Node cfgNode : cfg.nodes()) {
|
|
||||||
PDGNode pdgNode = new PDGNode(cfgNode);
|
|
||||||
pdg.addVertex(pdgNode);
|
|
||||||
cfgToPdgMap.put(cfgNode, pdgNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute control dependence using post-dominator analysis.
|
|
||||||
// Source: https://pages.cs.wisc.edu/~fischer/cs701.f14/lectures/L6.4up.pdf
|
|
||||||
private void computeControlDependence() {
|
|
||||||
// If, compute post-dominators
|
|
||||||
computePostDominators();
|
|
||||||
// Then, compute control dependence
|
|
||||||
for (Node node : cfg.nodes()) {
|
for (Node node : cfg.nodes()) {
|
||||||
controlDependence.put(node, new HashSet<>());
|
Set<String> deps = new HashSet<>();
|
||||||
}
|
|
||||||
|
|
||||||
// for each edge X -> Y in the CFG
|
for (Edge inEdge : node.inEdges()) {
|
||||||
for (Node x : cfg.nodes()) {
|
Node pred = inEdge.source();
|
||||||
for (Edge edge : x.outEdges()) {
|
|
||||||
Node y = edge.target();
|
if (pred.outEdges().size() > 1) {
|
||||||
if (y == null) continue;
|
deps.add(pred.label());
|
||||||
// find all nodes that are control-dependent on X via this edge
|
|
||||||
for (Node node : cfg.nodes()) {
|
if (controlDeps.containsKey(pred.label())) {
|
||||||
// Node is control-dependent on X if:
|
deps.addAll(controlDeps.get(pred.label()));
|
||||||
// 1. Node post-dominates Y (the successor)
|
|
||||||
// 2. Node does NOT post-dominate X
|
|
||||||
if (postDominates(node, y) && !postDominates(node, x)) {
|
|
||||||
controlDependence.get(x).add(node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controlDeps.put(node.label(), deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.println("\t\tFound " + countDependencies(controlDeps) + " control dependencies");
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute post-dominators using fixed-point algorithm.
|
/**
|
||||||
// node Y post-dominates X if all paths from X to exit go through Y.
|
* Compute data dependencies using reaching definitions
|
||||||
private void computePostDominators() {
|
*/
|
||||||
List<Node> allNodes = cfg.nodes();
|
private void computeDataDependencies() {
|
||||||
Node exitNode = cfg.normalExit;
|
System.out.println(" Computing data dependencies...");
|
||||||
for (Node node : allNodes) {
|
|
||||||
postDominators.put(node, new HashSet<>(allNodes));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exitNode != null) {
|
// 1. Find definitions and uses for each node
|
||||||
postDominators.put(exitNode, new HashSet<>(Arrays.asList(exitNode)));
|
Map<String, Set<String>> defs = new HashMap<>();
|
||||||
}
|
Map<String, Set<String>> uses = new HashMap<>();
|
||||||
|
|
||||||
boolean changed = true;
|
|
||||||
while (changed) {
|
|
||||||
changed = false;
|
|
||||||
|
|
||||||
for (Node node : allNodes) {
|
|
||||||
if (node.equals(exitNode)) continue;
|
|
||||||
|
|
||||||
Set<Node> newPostDom = new HashSet<>();
|
|
||||||
newPostDom.add(node); // Node post-dominates itself
|
|
||||||
|
|
||||||
Set<Edge> successorEdges = node.outEdges();
|
|
||||||
if (!successorEdges.isEmpty()) {
|
|
||||||
boolean first = true;
|
|
||||||
for (Edge edge : successorEdges) {
|
|
||||||
Node successor = edge.target();
|
|
||||||
if (successor == null) continue;
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
newPostDom.addAll(postDominators.get(successor));
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
newPostDom.retainAll(postDominators.get(successor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newPostDom.equals(postDominators.get(node))) {
|
|
||||||
postDominators.put(node, newPostDom);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean postDominates(Node dominator, Node node) {
|
|
||||||
Set<Node> postDoms = postDominators.get(node);
|
|
||||||
return postDoms != null && postDoms.contains(dominator);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void computeDataDependence() {
|
|
||||||
Map<Node, Set<String>> defs = new HashMap<>();
|
|
||||||
Map<Node, Set<String>> uses = new HashMap<>();
|
|
||||||
|
|
||||||
for (Node node : cfg.nodes()) {
|
for (Node node : cfg.nodes()) {
|
||||||
defs.put(node, extractDefs(node));
|
String label = node.label();
|
||||||
uses.put(node, extractUses(node));
|
defs.put(label, extractDefs(label));
|
||||||
PDGNode pdgNode = cfgToPdgMap.get(node);
|
uses.put(label, extractUses(label));
|
||||||
pdgNode.setDefs(defs.get(node));
|
|
||||||
pdgNode.setUses(uses.get(node));
|
|
||||||
}
|
}
|
||||||
Map<Node, Set<Definition>> reachingDefs = computeReachingDefinitions(defs);
|
|
||||||
|
// 2. Compute reaching definitions
|
||||||
|
Map<String, Map<String, Set<String>>> reaching = computeReachingDefinitions(defs);
|
||||||
|
|
||||||
|
// 3. Build data dependencies
|
||||||
for (Node node : cfg.nodes()) {
|
for (Node node : cfg.nodes()) {
|
||||||
dataDependence.put(node, new HashSet<>());
|
String label = node.label();
|
||||||
}
|
Set<String> deps = new HashSet<>();
|
||||||
for (Node use : cfg.nodes()) {
|
|
||||||
Set<String> usedVars = uses.get(use);
|
|
||||||
Set<Definition> reaching = reachingDefs.get(use);
|
|
||||||
|
|
||||||
for (Definition def : reaching) {
|
for (String var : uses.get(label)) {
|
||||||
if (usedVars.contains(def.variable)) {
|
if (reaching.containsKey(label) && reaching.get(label).containsKey(var)) {
|
||||||
dataDependence.get(def.node).add(use);
|
deps.addAll(reaching.get(label).get(var));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dataDeps.put(label, deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.println(" Found " + countDependencies(dataDeps) + " data dependencies");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract variable definitions from a CFG node.
|
/**
|
||||||
private Set<String> extractDefs(Node node) {
|
* Extract variable definitions from a statement simple pattern matching for Java 1.4
|
||||||
Set<String> defs = new HashSet<>();
|
*/
|
||||||
String label = node.label();
|
private Set<String> extractDefs(String statement) {
|
||||||
|
|
||||||
if (label.startsWith("*")) { // Skip special nodes
|
|
||||||
return defs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (label.contains("=") && !label.contains("==")) { // Look for assignments: variable = ...
|
|
||||||
try {
|
|
||||||
String[] parts = label.split("=");
|
|
||||||
if (parts.length >= 2) {
|
|
||||||
String varPart = parts[0].trim();
|
|
||||||
|
|
||||||
// handle "int v" or just "v"
|
|
||||||
String[] tokens = varPart.split("\\s+");
|
|
||||||
String varName = tokens[tokens.length - 1].replaceAll("[^a-zA-Z0-9_]", "");
|
|
||||||
|
|
||||||
if (varName.length() > 0 && Character.isJavaIdentifierStart(varName.charAt(0))) {
|
|
||||||
defs.add(varName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// parsing failed, ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return defs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract variable uses from a CFG node.
|
|
||||||
private Set<String> extractUses(Node node) {
|
|
||||||
Set<String> uses = new HashSet<>();
|
|
||||||
String label = node.label();
|
|
||||||
|
|
||||||
// Skip special nodes
|
|
||||||
if (label.startsWith("*")) {
|
|
||||||
return uses;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For assignments, extract from right-hand side
|
|
||||||
if (label.contains("=") && !label.contains("==")) {
|
|
||||||
String[] parts = label.split("=", 2);
|
|
||||||
if (parts.length >= 2) {
|
|
||||||
String rhs = parts[1].trim().replace(";", "");
|
|
||||||
uses.addAll(extractVariablesFromExpression(rhs));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// For other statements, extract all variables
|
|
||||||
uses.addAll(extractVariablesFromExpression(label));
|
|
||||||
}
|
|
||||||
|
|
||||||
return uses;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract variable names from an expression.
|
|
||||||
private Set<String> extractVariablesFromExpression(String expr) {
|
|
||||||
Set<String> vars = new HashSet<>();
|
Set<String> vars = new HashSet<>();
|
||||||
|
|
||||||
// Remove common operators and split
|
// Skip special nodes
|
||||||
String cleaned = expr.replaceAll("[+\\-*/()\\[\\]{}<>=!&|;,.]", " ");
|
if (statement.startsWith("*")) return vars;
|
||||||
String[] tokens = cleaned.split("\\s+");
|
|
||||||
|
|
||||||
for (String token : tokens) {
|
if (statement.contains("=") && !statement.contains("==")) {
|
||||||
token = token.trim();
|
String[] parts = statement.split("=");
|
||||||
if (token.isEmpty()) continue;
|
if (parts.length > 0) {
|
||||||
|
String lhs = parts[0].trim();
|
||||||
|
String[] tokens = lhs.split("\\s+");
|
||||||
|
if (tokens.length > 0) {
|
||||||
|
String varName = tokens[tokens.length - 1];
|
||||||
|
varName = varName.replaceAll("[\\[\\].();,]", "");
|
||||||
|
if (!varName.isEmpty() && Character.isJavaIdentifierStart(varName.charAt(0))) {
|
||||||
|
vars.add(varName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if it's a valid identifier (not a number, not a keyword)
|
if (statement.contains("for") && statement.contains("(")) {
|
||||||
if (isValidIdentifier(token) && !isKeyword(token)) {
|
String forPart = statement.substring(statement.indexOf("("));
|
||||||
vars.add(token);
|
String[] forParts = forPart.split(";");
|
||||||
|
if (forParts.length >= 3) {
|
||||||
|
if (forParts[0].contains("=")) {
|
||||||
|
String[] initParts = forParts[0].split("=");
|
||||||
|
if (initParts.length > 0) {
|
||||||
|
String var = initParts[0].trim().replaceAll("[^a-zA-Z0-9_]", "");
|
||||||
|
if (!var.isEmpty()) vars.add(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String update = forParts[forParts.length - 1];
|
||||||
|
if (update.contains("++") || update.contains("--")) {
|
||||||
|
String var = update.replaceAll("[^a-zA-Z0-9_]", "");
|
||||||
|
if (!var.isEmpty()) vars.add(var);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vars;
|
return vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidIdentifier(String s) {
|
/**
|
||||||
if (s == null || s.isEmpty()) return false;
|
* Extract variable uses from a statement
|
||||||
|
*/
|
||||||
|
private Set<String> extractUses(String statement) {
|
||||||
|
Set<String> vars = new HashSet<>();
|
||||||
|
|
||||||
// Check if it's a number
|
if (statement.startsWith("*")) return vars;
|
||||||
try {
|
String[] tokens = statement.split("[\\s+\\-*/=<>!&|(){}\\[\\];,.]");
|
||||||
Integer.parseInt(s);
|
for (String token : tokens) {
|
||||||
return false;
|
token = token.trim();
|
||||||
} catch (NumberFormatException e) {
|
if (!token.isEmpty() &&
|
||||||
// Not a number, continue
|
Character.isJavaIdentifierStart(token.charAt(0)) &&
|
||||||
|
!isKeyword(token) &&
|
||||||
|
!token.matches("\\d+")) { r
|
||||||
|
vars.add(token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
vars.removeAll(extractDefs(statement));
|
||||||
|
|
||||||
if (!Character.isJavaIdentifierStart(s.charAt(0))) return false;
|
return vars;
|
||||||
for (int i = 1; i < s.length(); i++) {
|
|
||||||
if (!Character.isJavaIdentifierPart(s.charAt(i))) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isKeyword(String s) {
|
/**
|
||||||
|
* Check if a word is a Java keyword
|
||||||
|
*/
|
||||||
|
private boolean isKeyword(String word) {
|
||||||
Set<String> keywords = new HashSet<>(Arrays.asList(
|
Set<String> keywords = new HashSet<>(Arrays.asList(
|
||||||
"if", "else", "while", "for", "return", "int", "boolean", "void", "class",
|
"if", "else", "while", "for", "do", "return", "break", "continue",
|
||||||
"public", "private", "static", "new", "this", "true", "false", "null",
|
"int", "double", "float", "char", "boolean", "void", "String",
|
||||||
"break", "continue", "switch", "case", "default", "try", "catch", "finally",
|
"new", "null", "true", "false", "class", "public", "private",
|
||||||
"throw", "throws", "extends", "implements", "abstract", "final", "native",
|
"static", "final", "this", "super", "try", "catch", "throw", "throws"
|
||||||
"synchronized", "transient", "volatile", "strictfp", "package", "import"
|
|
||||||
));
|
));
|
||||||
return keywords.contains(s);
|
return keywords.contains(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute reaching definitions using fixed-point analysis.
|
/**
|
||||||
private Map<Node, Set<Definition>> computeReachingDefinitions(Map<Node, Set<String>> defs) {
|
* Compute reaching definitions using iterative data flow analysis
|
||||||
Map<Node, Set<Definition>> reachingDefs = new HashMap<>();
|
*/
|
||||||
|
private Map<String, Map<String, Set<String>>> computeReachingDefinitions(
|
||||||
|
Map<String, Set<String>> defs) {
|
||||||
|
|
||||||
// Initialize
|
Map<String, Map<String, Set<String>>> reaching = new HashMap<>();
|
||||||
for (Node node : cfg.nodes()) {
|
for (Node node : cfg.nodes()) {
|
||||||
reachingDefs.put(node, new HashSet<>());
|
reaching.put(node.label(), new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fixed-point iteration
|
|
||||||
boolean changed = true;
|
boolean changed = true;
|
||||||
while (changed) {
|
int iterations = 0;
|
||||||
|
while (changed && iterations < 100) {
|
||||||
changed = false;
|
changed = false;
|
||||||
|
iterations++;
|
||||||
|
|
||||||
for (Node node : cfg.nodes()) {
|
for (Node node : cfg.nodes()) {
|
||||||
Set<Definition> newReaching = new HashSet<>();
|
String label = node.label();
|
||||||
|
Map<String, Set<String>> oldReaching = new HashMap<>(reaching.get(label));
|
||||||
// Union of reaching definitions from all predecessors
|
Map<String, Set<String>> newReaching = new HashMap<>();
|
||||||
Set<Edge> inEdges = node.inEdges();
|
for (Edge inEdge : node.inEdges()) {
|
||||||
for (Edge edge : inEdges) {
|
Node pred = inEdge.source();
|
||||||
Node pred = edge.source();
|
String predLabel = pred.label();
|
||||||
Set<Definition> predReaching = new HashSet<>(reachingDefs.get(pred));
|
if (reaching.containsKey(predLabel)) {
|
||||||
|
for (Map.Entry<String, Set<String>> entry : reaching.get(predLabel).entrySet()) {
|
||||||
// Kill definitions of variables defined in pred
|
String var = entry.getKey();
|
||||||
Set<String> predDefs = defs.get(pred);
|
newReaching.putIfAbsent(var, new HashSet<>());
|
||||||
predReaching.removeIf(def -> predDefs.contains(def.variable));
|
newReaching.get(var).addAll(entry.getValue());
|
||||||
|
}
|
||||||
// Gen: Add new definitions from pred
|
|
||||||
for (String var : predDefs) {
|
|
||||||
predReaching.add(new Definition(pred, var));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newReaching.addAll(predReaching);
|
// Add predecessor's definitions
|
||||||
|
for (String var : defs.get(predLabel)) {
|
||||||
|
newReaching.putIfAbsent(var, new HashSet<>());
|
||||||
|
newReaching.get(var).clear();
|
||||||
|
newReaching.get(var).add(predLabel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newReaching.equals(reachingDefs.get(node))) {
|
reaching.put(label, newReaching);
|
||||||
reachingDefs.put(node, newReaching);
|
|
||||||
|
if (!mapsEqual(oldReaching, newReaching)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return reachingDefs;
|
return reaching;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add control and data dependence edges to PDG.
|
private boolean mapsEqual(Map<String, Set<String>> m1, Map<String, Set<String>> m2) {
|
||||||
private void addPDGEdges() {
|
if (m1.size() != m2.size()) return false;
|
||||||
// Add control dependence edges
|
for (String key : m1.keySet()) {
|
||||||
for (Node from : controlDependence.keySet()) {
|
if (!m2.containsKey(key)) return false;
|
||||||
PDGNode fromPDG = cfgToPdgMap.get(from);
|
if (!m1.get(key).equals(m2.get(key))) return false;
|
||||||
for (Node to : controlDependence.get(from)) {
|
|
||||||
PDGNode toPDG = cfgToPdgMap.get(to);
|
|
||||||
PDGEdge edge = new PDGEdge(PDGEdge.EdgeType.CONTROL);
|
|
||||||
try {
|
|
||||||
pdg.addEdge(fromPDG, toPDG, edge);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// Edge might already exist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add data dependence edges
|
|
||||||
for (Node from : dataDependence.keySet()) {
|
|
||||||
PDGNode fromPDG = cfgToPdgMap.get(from);
|
|
||||||
for (Node to : dataDependence.get(from)) {
|
|
||||||
PDGNode toPDG = cfgToPdgMap.get(to);
|
|
||||||
PDGEdge edge = new PDGEdge(PDGEdge.EdgeType.DATA);
|
|
||||||
try {
|
|
||||||
pdg.addEdge(fromPDG, toPDG, edge);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// Edge might already exist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int countDependencies(Map<String, Set<String>> deps) {
|
||||||
|
int count = 0;
|
||||||
|
for (Set<String> set : deps.values()) {
|
||||||
|
count += set.size();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Set<String> getDependencies(String nodeLabel) {
|
||||||
|
Set<String> all = new HashSet<>();
|
||||||
|
if (controlDeps.containsKey(nodeLabel)) {
|
||||||
|
all.addAll(controlDeps.get(nodeLabel));
|
||||||
|
}
|
||||||
|
if (dataDeps.containsKey(nodeLabel)) {
|
||||||
|
all.addAll(dataDeps.get(nodeLabel));
|
||||||
|
}
|
||||||
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute forward slice from a given node label.
|
|
||||||
* Returns all nodes that could be impacted by a change to the given node.
|
|
||||||
**/
|
|
||||||
public Set<String> computeForwardSlice(String nodeLabel) {
|
public Set<String> computeForwardSlice(String nodeLabel) {
|
||||||
Node startCFGNode = cfg.findNode(nodeLabel); // Find the CFG node with this label
|
Set<String> slice = new HashSet<>();
|
||||||
if (startCFGNode == null) {
|
Queue<String> worklist = new LinkedList<>();
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
return computeForwardSliceFromNode(startCFGNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute forward slice from a given node.
|
slice.add(nodeLabel);
|
||||||
private Set<String> computeForwardSliceFromNode(Node startNode) {
|
worklist.add(nodeLabel);
|
||||||
PDGNode startPDGNode = cfgToPdgMap.get(startNode);
|
while (!worklist.isEmpty()) {
|
||||||
Set<String> impactedLabels = new HashSet<>();
|
String current = worklist.poll();
|
||||||
Set<PDGNode> visited = new HashSet<>();
|
for (String node : getAllNodes()) {
|
||||||
Queue<PDGNode> queue = new LinkedList<>();
|
if (!slice.contains(node)) {
|
||||||
|
Set<String> deps = getDependencies(node);
|
||||||
queue.add(startPDGNode);
|
if (deps.contains(current)) {
|
||||||
visited.add(startPDGNode);
|
slice.add(node);
|
||||||
|
worklist.add(node);
|
||||||
while (!queue.isEmpty()) {
|
}
|
||||||
PDGNode current = queue.poll();
|
|
||||||
impactedLabels.add(current.getCfgNode().label());
|
|
||||||
|
|
||||||
// Follow all outgoing edges (both control and data)
|
|
||||||
Set<PDGEdge> outEdges = pdg.outgoingEdgesOf(current);
|
|
||||||
for (PDGEdge edge : outEdges) {
|
|
||||||
PDGNode target = pdg.getEdgeTarget(edge);
|
|
||||||
if (!visited.contains(target)) {
|
|
||||||
visited.add(target);
|
|
||||||
queue.add(target);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return impactedLabels;
|
return slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the PDG structure.
|
private Set<String> getAllNodes() {
|
||||||
public void printPDG() {
|
Set<String> nodes = new HashSet<>();
|
||||||
System.out.println("\n=== PDG Structure ===");
|
|
||||||
|
|
||||||
List<PDGNode> nodes = new ArrayList<>(pdg.vertexSet());
|
|
||||||
nodes.sort(Comparator.comparing(n -> n.getCfgNode().label()));
|
|
||||||
|
|
||||||
for (PDGNode node : nodes) {
|
|
||||||
System.out.print("Node: " + node.getCfgNode().label());
|
|
||||||
System.out.print(" [Defs: " + node.getDefs() + ", Uses: " + node.getUses() + "]");
|
|
||||||
System.out.println();
|
|
||||||
|
|
||||||
Set<PDGEdge> outEdges = pdg.outgoingEdgesOf(node);
|
|
||||||
for (PDGEdge edge : outEdges) {
|
|
||||||
PDGNode target = pdg.getEdgeTarget(edge);
|
|
||||||
System.out.println(" -> " + edge.getType() + " dep on: " + target.getCfgNode().label());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print CFG structure for debugging.
|
|
||||||
public void printCFG() {
|
|
||||||
System.out.println("\n=== CFG Structure ===");
|
|
||||||
System.out.println("Entry: " + cfg.entry.label());
|
|
||||||
System.out.println("Normal Exit: " + cfg.normalExit.label());
|
|
||||||
System.out.println("Abrupt Exit: " + cfg.abruptExit.label());
|
|
||||||
System.out.println("\nNodes:");
|
|
||||||
|
|
||||||
for (Node node : cfg.nodes()) {
|
for (Node node : cfg.nodes()) {
|
||||||
System.out.println(" " + node.label());
|
nodes.add(node.label());
|
||||||
for (Edge edge : node.outEdges()) {
|
|
||||||
String target = edge.target() != null ? edge.target().label() : "null";
|
|
||||||
System.out.println(" -> " + edge.label() + " to " + target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the PDG graph.
|
public void printPDG() {
|
||||||
public Graph<PDGNode, PDGEdge> getGraph() {
|
System.out.println("CONTROL DEPENDENCIES:");
|
||||||
return pdg;
|
for (Map.Entry<String, Set<String>> entry : controlDeps.entrySet()) {
|
||||||
|
if (!entry.getValue().isEmpty()) {
|
||||||
|
System.out.println(" " + entry.getKey());
|
||||||
|
for (String dep : entry.getValue()) {
|
||||||
|
System.out.println(" <- " + dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\nDATA DEPENDENCIES:");
|
||||||
|
for (Map.Entry<String, Set<String>> entry : dataDeps.entrySet()) {
|
||||||
|
if (!entry.getValue().isEmpty()) {
|
||||||
|
System.out.println(" " + entry.getKey());
|
||||||
|
for (String dep : entry.getValue()) {
|
||||||
|
System.out.println(" <- " + dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Set<String>> getControlDependencies() {
|
||||||
|
return new HashMap<>(controlDeps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the underlying CFG.
|
public Map<String, Set<String>> getDataDependencies() {
|
||||||
public ControlFlowGraph getCFG() {
|
return new HashMap<>(dataDeps);
|
||||||
return cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Helper class for tracking definitions
|
|
||||||
private static class Definition {
|
|
||||||
Node node;
|
|
||||||
String variable;
|
|
||||||
|
|
||||||
Definition(Node node, String variable) {
|
|
||||||
this.node = node;
|
|
||||||
this.variable = variable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (!(o instanceof Definition)) return false;
|
|
||||||
Definition that = (Definition) o;
|
|
||||||
return node.equals(that.node) && variable.equals(that.variable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(node, variable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
/**
|
|
||||||
* Edge in the PDG representing either control or data dependence.
|
|
||||||
*/
|
|
||||||
package pdg;
|
|
||||||
|
|
||||||
import org.jgrapht.graph.DefaultEdge;
|
|
||||||
|
|
||||||
public class PDGEdge extends DefaultEdge {
|
|
||||||
|
|
||||||
public enum EdgeType {
|
|
||||||
CONTROL, // Control dependence
|
|
||||||
DATA // Data dependence
|
|
||||||
}
|
|
||||||
|
|
||||||
private EdgeType type;
|
|
||||||
|
|
||||||
public PDGEdge(EdgeType type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EdgeType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return type.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
|
|
||||||
/**
|
|
||||||
* PDG Node that wraps a CFG node (org.lsmr.cfg.Node) and adds def-use information.
|
|
||||||
*/
|
|
||||||
package pdg;
|
|
||||||
|
|
||||||
import org.lsmr.cfg.Node;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
|
|
||||||
public class PDGNode {
|
|
||||||
private Node cfgNode;
|
|
||||||
private Set<String> defs;
|
|
||||||
private Set<String> uses;
|
|
||||||
|
|
||||||
public PDGNode(Node cfgNode) {
|
|
||||||
this.cfgNode = cfgNode;
|
|
||||||
this.defs = new HashSet<>();
|
|
||||||
this.uses = new HashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node getCfgNode() {
|
|
||||||
return cfgNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getDefs() {
|
|
||||||
return defs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefs(Set<String> defs) {
|
|
||||||
this.defs = defs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getUses() {
|
|
||||||
return uses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUses(Set<String> uses) {
|
|
||||||
this.uses = uses;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "PDGNode{" + cfgNode.label() +
|
|
||||||
", defs=" + defs + ", uses=" + uses + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (!(o instanceof PDGNode)) return false;
|
|
||||||
PDGNode pdgNode = (PDGNode) o;
|
|
||||||
return cfgNode.equals(pdgNode.cfgNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(cfgNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
tests/Example1.java
Normal file
29
tests/Example1.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
public class Example1 {
|
||||||
|
public void test() {
|
||||||
|
int x = 5;
|
||||||
|
int y = x + 10;
|
||||||
|
int z = y * 2;
|
||||||
|
int result = z + x;
|
||||||
|
}
|
||||||
|
public void test1(int a) {
|
||||||
|
int x = 5;
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
|
if (a > 10) {
|
||||||
|
y = x + a;
|
||||||
|
} else {
|
||||||
|
y = x - a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = y * 2;
|
||||||
|
}
|
||||||
|
public void test2() {
|
||||||
|
int sum = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < 10) {
|
||||||
|
sum = sum + i;
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user