renaming and FlowGraph Update

This commit is contained in:
ChUrl
2021-01-29 21:53:27 +01:00
parent eac739d07c
commit 6ae06c9f63
7 changed files with 264 additions and 62 deletions

View File

@ -0,0 +1,171 @@
package codegen.flowgraph;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class FlowBasicBlock {
private final String id;
private final String label;
private final List<FlowInstruction> instructions;
private final Set<FlowBasicBlock> predecessors;
private final Set<FlowBasicBlock> successors;
private int instNr;
public FlowBasicBlock(String label) {
this.label = label;
this.id = String.valueOf(System.nanoTime());
this.instructions = new ArrayList<>();
this.predecessors = new HashSet<>();
this.successors = new HashSet<>();
}
public FlowBasicBlock() {
this("");
}
public boolean isEmpty() {
return this.label.isBlank() && this.instructions.isEmpty();
}
public String getId() {
return this.id;
}
public String getLabel() {
return this.label;
}
public void addInstruction(String instruction, String... args) {
this.instNr++;
this.instructions.add(new FlowInstruction(String.valueOf(Long.parseLong(this.id) + this.instNr), this.id,
instruction, args));
}
public List<FlowInstruction> getInstructions() {
return this.instructions;
}
public void addSuccessor(FlowBasicBlock block) {
this.successors.add(block);
}
public void addSuccessors(Set<FlowBasicBlock> successors) {
this.successors.addAll(successors);
}
public void addPredecessor(FlowBasicBlock block) {
this.predecessors.add(block);
}
public void addPredecessors(Set<FlowBasicBlock> predecessors) {
this.predecessors.addAll(predecessors);
}
public Set<FlowBasicBlock> getSuccessorSet() {
return this.successors;
}
public Set<FlowInstruction> getPredecessors(FlowInstruction inst) {
final int index = this.instructions.indexOf(inst);
if (index == -1) {
return null;
}
if (index > 0 && index <= this.instructions.size() - 1) {
// Instruction is in the middle or end
return Set.of(this.instructions.get(index - 1));
}
// Instruction is at the beginning
return this.predecessors.stream()
.map(FlowBasicBlock::getLastInst)
.filter(Objects::nonNull)
.collect(Collectors.toUnmodifiableSet());
}
public Set<FlowInstruction> getSuccessors(FlowInstruction inst) {
final int index = this.instructions.indexOf(inst);
if (index == -1) {
return null;
}
if (index >= 0 && index < this.instructions.size() - 1) {
// Instruction is in the beginning or middle
return Set.of(this.instructions.get(index + 1));
}
// Instruction is at the end
return this.successors.stream()
.map(FlowBasicBlock::getFirstInst)
.filter(Objects::nonNull)
.collect(Collectors.toUnmodifiableSet());
}
public Set<FlowBasicBlock> getPredecessorSet() {
return this.predecessors;
}
public FlowInstruction getFirstInst() {
if (!this.instructions.isEmpty()) {
return this.instructions.get(0);
}
return null;
}
public FlowInstruction getLastInst() {
if (!this.instructions.isEmpty()) {
return this.instructions.get(this.instructions.size() - 1);
}
return null;
}
// Print + Overrides
public String printInst() {
return this.instructions.stream()
.map(inst -> inst.toString().trim() + "\\n")
.map(inst -> inst.replace("\"", "\\\""))
.collect(Collectors.joining());
}
@Override
public int hashCode() {
return Objects.hash(this.id);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof FlowBasicBlock) {
return this.id.equals(((FlowBasicBlock) obj).id);
}
return false;
}
@Override
public String toString() {
final String linesString = this.instructions.stream()
.map(FlowInstruction::toString)
.map(line -> line + "\n")
.collect(Collectors.joining());
if (this.label.isBlank()) {
return linesString;
}
return this.label + ":\n"
+ linesString;
}
}

View File

@ -1,4 +1,4 @@
package codegen.sourcegraph;
package codegen.flowgraph;
import java.io.IOException;
import java.nio.file.Files;
@ -10,25 +10,25 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class SourceGraph {
public class FlowGraph {
private final SourceGraphHead head;
private final List<SourceBlock> blocks;
private final SourceGraphTail tail;
private final FlowGraphHead head;
private final List<FlowBasicBlock> blocks;
private final FlowGraphTail tail;
// If a new block has this label, the value in this map is a predecessor
private final Map<String, SourceBlock> predecessorMap;
private final Map<String, FlowBasicBlock> predecessorMap;
public SourceGraph(String bytecodeVersion, String source, String clazz, int stackSize, int localCount) {
this.head = new SourceGraphHead(bytecodeVersion, source, clazz, stackSize, localCount);
public FlowGraph(String bytecodeVersion, String source, String clazz, int stackSize, int localCount) {
this.head = new FlowGraphHead(bytecodeVersion, source, clazz, stackSize, localCount);
this.blocks = new ArrayList<>();
this.tail = new SourceGraphTail();
this.tail = new FlowGraphTail();
this.predecessorMap = new HashMap<>();
}
// Label marks beginning of block
public void addLabel(String label) {
final SourceBlock newBlock = new SourceBlock(label);
final FlowBasicBlock newBlock = new FlowBasicBlock(label);
// Resolve missing successors/predecessors from jumps
@ -39,34 +39,37 @@ public class SourceGraph {
// this.predecessorMap.remove(label); // Problematic if multiple gotos to same label
}
/*
TODO: Hier ist ein Bug, welcher im Datenflussgraph zu gotos mit 2 successors führt
if (this.getCurrentBlock().isEmpty()) {
// Replace empty blocks, we don't need them
if (this.blocks.size() >= 2) {
// This empty blocks successors become the previous blocks successors after replacment
this.blocks.get(this.blocks.size() - 2).addSuccessors(this.getCurrentBlock().getSuccessors());
this.blocks.get(this.blocks.size() - 2).addSuccessors(this.getCurrentBlock().getSuccessorSet());
}
// Previous blocks predecessors are also the new blocks predecessors
newBlock.addPredecessors(this.getCurrentBlock().getPredecessors());
newBlock.addPredecessors(this.getCurrentBlock().getPredecessorSet());
this.blocks.set(this.blocks.size() - 1, newBlock); // Replace
} else {
*/
// Append block if last one isn't empty
newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
this.getCurrentBlock().addSuccessor(newBlock); // Obvious successor of current block
this.blocks.add(newBlock);
}
// }
}
// Jump means end of block
public void addJump(String jumpInstruction, String label) {
this.addInst(jumpInstruction, label);
final SourceBlock newBlock = new SourceBlock();
final FlowBasicBlock newBlock = new FlowBasicBlock();
newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
if (!"goto".equals(jumpInstruction)) {
@ -76,7 +79,7 @@ public class SourceGraph {
}
// Jumped successor
final SourceBlock labelBlock = this.getBlockByLabel(label);
final FlowBasicBlock labelBlock = this.getBlockByLabel(label);
if (labelBlock != null) {
// Successor exists
@ -93,15 +96,15 @@ public class SourceGraph {
public void addInst(String instruction, String... args) {
if (this.blocks.isEmpty()) {
this.blocks.add(new SourceBlock()); // First block doesn't exist
this.blocks.add(new FlowBasicBlock()); // First block doesn't exist
}
this.getCurrentBlock().addLine(instruction, args); // Add to last block
this.getCurrentBlock().addInstruction(instruction, args); // Add to last block
}
public String print() {
final String blocksString = this.blocks.stream()
.map(SourceBlock::toString)
.map(FlowBasicBlock::toString)
.map(string -> string + "-".repeat(50) + "\n")
.collect(Collectors.joining());
@ -116,9 +119,11 @@ public class SourceGraph {
dot.append("digraph dfd {\n")
.append("node[shape=Mrecord]\n");
for (SourceBlock block : this.blocks) {
for (FlowBasicBlock block : this.blocks) {
dot.append(block.getId())
.append(" [label=\"{<f0> ")
.append(this.blocks.indexOf(block))
.append(": ")
.append(block.getLabel())
.append("|<f1> ")
.append(block.printInst())
@ -131,8 +136,8 @@ public class SourceGraph {
dot.append("START -> ").append(this.blocks.get(0).getId()).append(";\n");
dot.append(this.getCurrentBlock().getId()).append(" -> END;\n");
for (SourceBlock block : this.blocks) {
for (SourceBlock succ : block.getSuccessors()) {
for (FlowBasicBlock block : this.blocks) {
for (FlowBasicBlock succ : block.getSuccessorSet()) {
dot.append(block.getId()).append(" -> ").append(succ.getId()).append(";\n");
}
}
@ -141,14 +146,14 @@ public class SourceGraph {
final String dotOut = dot.toString();
final Path dotFile = Paths.get(System.getProperty("user.dir") + "/DotOut.dot");
final Path dotFile = Paths.get(System.getProperty("user.dir") + "/FlowGraph.dot");
try {
Files.writeString(dotFile, dotOut);
} catch (IOException e) {
e.printStackTrace();
}
final ProcessBuilder dotCompile = new ProcessBuilder("dot", "-Tsvg", "-O", "DotOut.dot");
final ProcessBuilder dotCompile = new ProcessBuilder("dot", "-Tsvg", "-oFlowGraph.svg", "FlowGraph.dot");
try {
dotCompile.start();
} catch (IOException e) {
@ -161,7 +166,7 @@ public class SourceGraph {
@Override
public String toString() {
final String blocksString = this.blocks.stream()
.map(SourceBlock::toString)
.map(FlowBasicBlock::toString)
.collect(Collectors.joining());
return this.head
@ -169,14 +174,25 @@ public class SourceGraph {
+ this.tail;
}
private SourceBlock getBlockByLabel(String label) {
private FlowBasicBlock getBlockByLabel(String label) {
return this.blocks.stream()
.filter(block -> block.getLabel().equals(label))
.findFirst()
.orElse(null);
}
private SourceBlock getCurrentBlock() {
private FlowBasicBlock getCurrentBlock() {
return this.blocks.get(this.blocks.size() - 1);
}
public List<FlowBasicBlock> getBlocks() {
return this.blocks;
}
public FlowBasicBlock getBlockById(String id) {
return this.blocks.stream()
.filter(block -> block.getId().equals(id))
.findFirst()
.orElse(null);
}
}

View File

@ -1,4 +1,4 @@
package codegen.sourcegraph;
package codegen.flowgraph;
import codegen.CodeGenerationException;
import codegen.analysis.StackSizeAnalyzer;
@ -17,14 +17,14 @@ import java.util.Map;
import static java.util.Map.entry;
import static util.Logger.log;
public final class SourceGraphGenerator {
public final class FlowGraphGenerator {
private static final Map<String, Method> methodMap;
static {
Map<String, Method> map;
try {
final Class<?> gen = SourceGraphGenerator.class;
final Class<?> gen = FlowGraphGenerator.class;
map = Map.ofEntries(
entry("cond", gen.getDeclaredMethod("condNode", ASTNode.class)),
entry("loop", gen.getDeclaredMethod("loopNode", ASTNode.class)),
@ -47,34 +47,33 @@ public final class SourceGraphGenerator {
private final AST tree;
private final Map<String, Integer> varMap;
private final Map<ASTNode, String> nodeTypeMap;
private final SourceGraph graph;
private final FlowGraph graph;
private int labelCounter;
private SourceGraphGenerator(Map<String, Integer> varMap, AST tree, Map<ASTNode, String> nodeTypeMap, SourceGraph graph) {
private FlowGraphGenerator(Map<String, Integer> varMap, AST tree, Map<ASTNode, String> nodeTypeMap, FlowGraph graph) {
this.varMap = varMap;
this.tree = tree;
this.nodeTypeMap = nodeTypeMap;
this.graph = graph;
}
public static SourceGraphGenerator fromAST(AST tree, Map<ASTNode, String> nodeTypeMap, String source) {
public static FlowGraphGenerator fromAST(AST tree, Map<ASTNode, String> nodeTypeMap, String source) {
if (!tree.getRoot().hasChildren()) {
throw new CodeGenerationException("Empty File can't be compiled");
}
final Map<String, Integer> varMap = varMapFromAST(tree);
final Map<String, Integer> varMap = initVarMap(tree);
final String bytecodeVersion = "49.0";
final String clazz = tree.getRoot().getChildren().get(1).getValue();
final int stackSize = StackSizeAnalyzer.runStackModel(tree);
final int localCount = varMap.size() + 1;
final SourceGraph graph = new SourceGraph(bytecodeVersion, source, clazz, stackSize, localCount);
final FlowGraph graph = new FlowGraph(bytecodeVersion, source, clazz, stackSize, localCount);
return new SourceGraphGenerator(varMap, tree, nodeTypeMap, graph);
return new FlowGraphGenerator(varMap, tree, nodeTypeMap, graph);
}
private static Map<String, Integer> varMapFromAST(AST tree) {
private static Map<String, Integer> initVarMap(AST tree) {
final Map<String, Integer> varMap = new HashMap<>();
// Assign variables to map
@ -98,7 +97,11 @@ public final class SourceGraphGenerator {
return Collections.unmodifiableMap(varMap);
}
public SourceGraph generateGraph() {
public Map<String, Integer> getVarMap() {
return this.varMap;
}
public FlowGraph generateGraph() {
System.out.println(" - Generating Source Graph...");
this.generateNode(this.tree.getRoot().getChildren().get(3).getChildren().get(11));

View File

@ -1,6 +1,6 @@
package codegen.sourcegraph;
package codegen.flowgraph;
public class SourceGraphHead {
public class FlowGraphHead {
private final String bytecodeVersion;
private final String source;
@ -8,7 +8,7 @@ public class SourceGraphHead {
private final int stackSize;
private final int localCount;
public SourceGraphHead(String bytecodeVersion, String source, String clazz, int stackSize, int localCount) {
public FlowGraphHead(String bytecodeVersion, String source, String clazz, int stackSize, int localCount) {
this.bytecodeVersion = bytecodeVersion;
this.source = source;
this.clazz = clazz;

View File

@ -1,6 +1,6 @@
package codegen.sourcegraph;
package codegen.flowgraph;
public class SourceGraphTail {
public class FlowGraphTail {
@Override
public String toString() {

View File

@ -1,11 +1,15 @@
package codegen.sourcegraph;
package codegen.flowgraph;
public class SourceInst {
public class FlowInstruction {
private final String id;
private final String blockId;
private final String instruction;
private final String[] args;
public SourceInst(String instruction, String... args) {
public FlowInstruction(String id, String blockId, String instruction, String... args) {
this.id = id;
this.blockId = blockId;
this.instruction = instruction;
this.args = args;
}
@ -24,4 +28,12 @@ public class SourceInst {
public String[] getArgs() {
return this.args;
}
public String getBlockId() {
return this.blockId;
}
public String getId() {
return this.id;
}
}

View File

@ -1,7 +1,7 @@
package codegen;
import codegen.sourcegraph.SourceGraph;
import codegen.sourcegraph.SourceGraphGenerator;
import codegen.flowgraph.FlowGraph;
import codegen.flowgraph.FlowGraphGenerator;
import lexer.StupsLexer;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.Lexer;
@ -29,14 +29,14 @@ import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class SourceGraphGeneratorTest {
class FlowGraphGeneratorTest {
private static StupsParser parser;
private static Grammar stupsGrammar;
@BeforeAll
static void init() throws IOException, URISyntaxException {
final Path path = Paths.get(SourceGraphGeneratorTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI());
final Path path = Paths.get(FlowGraphGeneratorTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI());
final Grammar grammar = Grammar.fromFile(path);
parser = StupsParser.fromGrammar(grammar);
stupsGrammar = grammar;
@ -44,7 +44,7 @@ class SourceGraphGeneratorTest {
private static String readProgram(String prog) {
try {
final Path progPath = Paths.get(SourceGraphGeneratorTest.class.getClassLoader().getResource("examplePrograms/" + prog).toURI());
final Path progPath = Paths.get(FlowGraphGeneratorTest.class.getClassLoader().getResource("examplePrograms/" + prog).toURI());
return Files.readString(progPath);
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
@ -242,8 +242,8 @@ class SourceGraphGeneratorTest {
final AST tree = lexParseProgram(program);
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
final SourceGraphGenerator gen = SourceGraphGenerator.fromAST(tree, nodeTable, "TestOutpu");
final SourceGraph srcProg = gen.generateGraph();
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutpu");
final FlowGraph srcProg = gen.generateGraph();
compileJasmin(srcProg.toString());
assertThat(Integer.parseInt(executeCompiledProgram())).isEqualTo(result);
@ -257,8 +257,8 @@ class SourceGraphGeneratorTest {
final AST tree = lexParseProgram(program);
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
final SourceGraphGenerator gen = SourceGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
final SourceGraph srcProg = gen.generateGraph();
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
final FlowGraph srcProg = gen.generateGraph();
compileJasmin(srcProg.toString());
assertThat(Integer.parseInt(executeCompiledProgram())).isEqualTo(result);
@ -272,8 +272,8 @@ class SourceGraphGeneratorTest {
final AST tree = lexParseProgram(program);
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
final SourceGraphGenerator gen = SourceGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
final SourceGraph srcProg = gen.generateGraph();
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
final FlowGraph srcProg = gen.generateGraph();
compileJasmin(srcProg.toString());
assertThat(Boolean.parseBoolean(executeCompiledProgram())).isEqualTo(result);
@ -287,8 +287,8 @@ class SourceGraphGeneratorTest {
final AST tree = lexParseProgram(program);
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
final SourceGraphGenerator gen = SourceGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
final SourceGraph srcProg = gen.generateGraph();
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
final FlowGraph srcProg = gen.generateGraph();
compileJasmin(srcProg.toString());
assertThat(executeCompiledProgram()).isEqualTo(result);
@ -302,8 +302,8 @@ class SourceGraphGeneratorTest {
final AST tree = lexParseProgram(program);
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
final SourceGraphGenerator gen = SourceGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
final SourceGraph srcProg = gen.generateGraph();
final FlowGraphGenerator gen = FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput");
final FlowGraph srcProg = gen.generateGraph();
compileJasmin(srcProg.toString());
assertThat(executeCompiledProgram()).isEqualTo(result);
@ -316,7 +316,7 @@ class SourceGraphGeneratorTest {
final AST tree = lexParseProgram(program);
final Map<ASTNode, String> nodeTable = TypeChecker.validate(tree);
assertThatThrownBy(() -> SourceGraphGenerator.fromAST(tree, nodeTable, "TestOutput"))
assertThatThrownBy(() -> FlowGraphGenerator.fromAST(tree, nodeTable, "TestOutput"))
.isInstanceOf(CodeGenerationException.class);
}
}