public static LiveVariablesAnalysis analyze(ControlFlowGraph cfg, SymbolTable symbols) { LiveVariablesAnalysis instance = new LiveVariablesAnalysis(); instance.compute(cfg, symbols); return instance; }
/** * Builds a new LiveVariables instance for the given block and initializes the 'kill' and 'gen' symbol sets. */ static LiveVariables build(CfgBlock block, SymbolTable symbols) { LiveVariables instance = new LiveVariables(block); instance.init(block, symbols); return instance; }
private void init(CfgBlock block, SymbolTable symbols) { // 'writtenOnly' has variables that are WRITE-ONLY inside at least one element // (as opposed to 'kill' which can have a variable that inside an element is both READ and WRITTEN) Set<Symbol> writtenOnly = new HashSet<>(); for (Tree element : block.elements()) { Map<Symbol, VariableUsage> variableUsages = ReadWriteVisitor.getVariableUsages(element, symbols); variableUsagesPerElement.put(element, variableUsages); computeGenAndKill(writtenOnly, variableUsages); } }
private void verifyLiveVariableAnalysis(String body) { verifyLiveVariableAnalysis("", body); }
private boolean visitAssignedVariable(Tree tree) { if (!tree.is(Tree.Kind.VARIABLE_IDENTIFIER)) { return false; } Symbol varSym = symbols.getSymbol(tree); if (isLocalVariable(varSym)) { VariableUsage usage = variables.computeIfAbsent(varSym, s -> new VariableUsage()); usage.isWrite = true; return true; } return false; }
@Override public void visitLiteral(LiteralTree tree) { visitReadVariable(tree); super.visitLiteral(tree); }
static Map<Symbol, VariableUsage> getVariableUsages(Tree tree, SymbolTable symbols) { ReadWriteVisitor visitor = new ReadWriteVisitor(symbols); tree.accept(visitor); return visitor.variables; }
public static LiveVariablesAnalysis analyze(ControlFlowGraph cfg, SymbolTable symbols) { LiveVariablesAnalysis instance = new LiveVariablesAnalysis(); instance.compute(cfg, symbols); return instance; }
/** * Builds a new LiveVariables instance for the given block and initializes the 'kill' and 'gen' symbol sets. */ static LiveVariables build(CfgBlock block, SymbolTable symbols) { LiveVariables instance = new LiveVariables(block); instance.init(block, symbols); return instance; }
@Test public void test_simple_kill() { verifyLiveVariableAnalysis("" + "block( succ = [END], liveIn = [], liveOut = [], gen = [], kill = [foo, bar, qix]);" + "$foo = 1;" + "$bar = bar();" + "$qix = 1 + 2;"); }
@Override public void visitVariableIdentifier(VariableIdentifierTree tree) { visitReadVariable(tree); super.visitVariableIdentifier(tree); }
static Map<Symbol, VariableUsage> getVariableUsages(Tree tree, SymbolTable symbols) { ReadWriteVisitor visitor = new ReadWriteVisitor(symbols); tree.accept(visitor); return visitor.variables; }
@Test public void test_do_while() { verifyLiveVariableAnalysis("" + "beforeDo( succ = [body], liveIn = [x], liveOut = [a], gen = [x], kill = [a]);" + "$a = $x + 1;" + "do {" + " body( succ = [cond], liveIn = [a], liveOut = [a], gen = [a], kill = []);" + " foo ($a);" + "} while(cond( succ = [body, afterDo], liveIn = [a], liveOut = [a], gen = [], kill = []) );" + "afterDo( succ = [END], liveIn = [], liveOut = [], gen = [], kill = [a]);" + "$a = 0;"); }
@Override public void visitVariableIdentifier(VariableIdentifierTree tree) { visitReadVariable(tree); super.visitVariableIdentifier(tree); }
@Test public void unary_minus_plus_expression() { verifyLiveVariableAnalysis("" + "condition( succ = [insideIf], liveIn = [a], liveOut = [a], gen = [a], kill = []);" + "foo($a);" + "-$a;" + "+$a;" + "if (cond) {" + " insideIf (succ = [END], liveIn = [a], liveOut = [], gen = [a]);" + " foo($a);" + "}"); }
@Override public void visitLiteral(LiteralTree tree) { visitReadVariable(tree); super.visitLiteral(tree); }
@Test public void test_with_array_assignment() { verifyLiveVariableAnalysis("" + "condition( succ = [insideIf], liveIn = [], liveOut = [x], gen = [], kill = [x,y]);" + "list($x, $y) = array();" + "if ($y) {" + " insideIf (succ = [END], liveIn = [x], liveOut = [], gen = [x]);" + " foo($x);" + "}"); }
@Test public void test_simple_gen() { verifyLiveVariableAnalysis("" + "block( succ = [END], liveIn = [foo, bar], liveOut = [], gen = [foo, bar]);" + "foo($foo, $bar);"); }
@Test public void test_write_before_read() { verifyLiveVariableAnalysis("" + "condition( succ = [body, END], liveIn = [], liveOut = [], gen = [], kill = [a]);" + "$a = 1;" + "foo($a);" + "if (true) {" + " body( succ = [END], liveIn = [], liveOut = [], gen = [], kill = [a]);" + " $a = 1;" + " foo($a);" + "}"); }
@Test public void compound_assignments() { verifyLiveVariableAnalysis("" + "condition( succ = [insideIf], liveIn = [y], liveOut = [x,y], gen = [y], kill = [x,y]);" + "$x = 0;" + "$x += 20;" + "$y += 20;" + "if ($y) {" + " insideIf (succ = [END], liveIn = [x,y], liveOut = [], gen = [x,y]);" + " foo($x, $y);" + "}"); }