bufixes with goto-successors, empty block removal

This commit is contained in:
ChUrl
2021-01-30 15:30:24 +01:00
parent 3a355d9224
commit 6e7208e6d3
3 changed files with 212 additions and 127 deletions

View File

@ -29,8 +29,12 @@ public class FlowBasicBlock {
this(""); this("");
} }
/**
* Ermittelt ob ein BasicBlock ohne weiteres entfernbar ist.
* Der Block darf kein Label haben, damit keine Sprünge ins Leere passieren.
*/
public boolean isEmpty() { public boolean isEmpty() {
return this.label.isBlank() && this.instructions.isEmpty(); return this.instructions.isEmpty() && this.label.isBlank();
} }
public String getId() { public String getId() {

View File

@ -1,19 +1,23 @@
package codegen.flowgraph; package codegen.flowgraph;
import util.Logger;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class FlowGraph { public class FlowGraph {
private final FlowGraphHead head; private final FlowGraphHead head;
private final List<FlowBasicBlock> blocks; private final List<FlowBasicBlock> basicBlocks;
private final FlowGraphTail tail; private final FlowGraphTail tail;
// If a new block has this label, the value in this map is a predecessor // If a new block has this label, the value in this map is a predecessor
@ -21,7 +25,7 @@ public class FlowGraph {
public FlowGraph(String bytecodeVersion, String source, String clazz, int stackSize, int localCount) { public FlowGraph(String bytecodeVersion, String source, String clazz, int stackSize, int localCount) {
this.head = new FlowGraphHead(bytecodeVersion, source, clazz, stackSize, localCount); this.head = new FlowGraphHead(bytecodeVersion, source, clazz, stackSize, localCount);
this.blocks = new ArrayList<>(); this.basicBlocks = new ArrayList<>();
this.tail = new FlowGraphTail(); this.tail = new FlowGraphTail();
this.predecessorMap = new HashMap<>(); this.predecessorMap = new HashMap<>();
} }
@ -35,46 +39,24 @@ public class FlowGraph {
if (this.predecessorMap.containsKey(label)) { if (this.predecessorMap.containsKey(label)) {
this.predecessorMap.get(label).addSuccessor(newBlock); this.predecessorMap.get(label).addSuccessor(newBlock);
newBlock.addPredecessor(this.predecessorMap.get(label)); newBlock.addPredecessor(this.predecessorMap.get(label));
// this.predecessorMap.remove(label); // Problematic if multiple gotos to same label
} }
/* newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
TODO: Hier ist ein Bug, welcher im Datenflussgraph zu gotos mit 2 successors führt this.getCurrentBlock().addSuccessor(newBlock); // Obvious successor of current block
if (this.getCurrentBlock().isEmpty()) {
// Replace empty blocks, we don't need them
if (this.blocks.size() >= 2) { this.basicBlocks.add(newBlock);
// This empty blocks successors become the previous blocks successors after replacment
this.blocks.get(this.blocks.size() - 2).addSuccessors(this.getCurrentBlock().getSuccessorSet());
}
// Previous blocks predecessors are also the new blocks predecessors
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 // Jump means end of block
public void addJump(String jumpInstruction, String label) { public void addJump(String jumpInstruction, String label) {
this.addInst(jumpInstruction, label); this.addInstruction(jumpInstruction, label);
final FlowBasicBlock newBlock = new FlowBasicBlock(); final FlowBasicBlock newBlock = new FlowBasicBlock();
newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
if (!"goto".equals(jumpInstruction)) { if (!"goto".equals(jumpInstruction)) {
// Goto always jumps // Goto always jumps
newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
this.getCurrentBlock().addSuccessor(newBlock); // Obvious successor of current block this.getCurrentBlock().addSuccessor(newBlock); // Obvious successor of current block
} }
@ -91,22 +73,80 @@ public class FlowGraph {
this.predecessorMap.put(label, this.getCurrentBlock()); // Current node is predecessor of label-block this.predecessorMap.put(label, this.getCurrentBlock()); // Current node is predecessor of label-block
} }
this.blocks.add(newBlock); this.basicBlocks.add(newBlock);
} }
public void addInst(String instruction, String... args) { public void addInstruction(String instruction, String... args) {
if (this.blocks.isEmpty()) { if (this.basicBlocks.isEmpty()) {
this.blocks.add(new FlowBasicBlock()); // First block doesn't exist this.basicBlocks.add(new FlowBasicBlock("START")); // First block doesn't exist
} }
this.getCurrentBlock().addInstruction(instruction, args); // Add to last block this.getCurrentBlock().addInstruction(instruction, args); // Add to last block
} }
/**
* Entfernt leere Blöcke.
*/
public void purgeEmptyBlocks() {
Logger.log("\nPurging empty blocks: ");
final Set<FlowBasicBlock> toRemove = new HashSet<>();
// Collect removable blocks
for (FlowBasicBlock block : this.basicBlocks) {
if (block.isEmpty()) {
Logger.log("Marking Block " + this.basicBlocks.indexOf(block) + " as removable.");
toRemove.add(block);
}
}
// Remove blocks + reroute predecessors/successors
for (FlowBasicBlock block : toRemove) {
for (FlowBasicBlock pred : block.getPredecessorSet()) {
for (FlowBasicBlock succ : block.getSuccessorSet()) {
Logger.log("Rerouting Block " + this.basicBlocks.indexOf(pred) + " to Block " + this.basicBlocks.indexOf(succ));
pred.addSuccessor(succ);
succ.addPredecessor(pred);
}
pred.getSuccessorSet().remove(block);
}
for (FlowBasicBlock succ : block.getSuccessorSet()) {
succ.getPredecessorSet().remove(block);
}
}
this.basicBlocks.removeAll(toRemove);
}
// Getters, Setters
private FlowBasicBlock getBlockByLabel(String label) {
return this.basicBlocks.stream()
.filter(block -> block.getLabel().equals(label))
.findFirst()
.orElse(null);
}
private FlowBasicBlock getCurrentBlock() {
return this.basicBlocks.get(this.basicBlocks.size() - 1);
}
public List<FlowBasicBlock> getBasicBlocks() {
return this.basicBlocks;
}
// Print + Overrides
public String print() { public String print() {
final String blocksString = this.blocks.stream() final String blocksString = this.basicBlocks.stream()
.map(FlowBasicBlock::toString) .map(FlowBasicBlock::toString)
.map(string -> string + "-".repeat(50) + "\n") .map(string -> string + "-".repeat(50) + "\n")
.collect(Collectors.joining()); .collect(Collectors.joining());
return this.head + "-".repeat(100) + "\n" return this.head + "-".repeat(100) + "\n"
+ "-".repeat(50) + "\n" + blocksString + "-".repeat(100) + "\n" + "-".repeat(50) + "\n" + blocksString + "-".repeat(100) + "\n"
@ -119,10 +159,10 @@ public class FlowGraph {
dot.append("digraph dfd {\n") dot.append("digraph dfd {\n")
.append("node[shape=Mrecord]\n"); .append("node[shape=Mrecord]\n");
for (FlowBasicBlock block : this.blocks) { for (FlowBasicBlock block : this.basicBlocks) {
dot.append(block.getId()) dot.append(block.getId())
.append(" [label=\"{<f0> ") .append(" [label=\"{<f0> ")
.append(this.blocks.indexOf(block)) .append(this.basicBlocks.indexOf(block))
.append(": ") .append(": ")
.append(block.getLabel()) .append(block.getLabel())
.append("|<f1> ") .append("|<f1> ")
@ -133,13 +173,23 @@ public class FlowGraph {
dot.append("START[label=\"START\"];\n") dot.append("START[label=\"START\"];\n")
.append("END[label=\"END\"];\n"); .append("END[label=\"END\"];\n");
dot.append("START -> ").append(this.blocks.get(0).getId()).append(";\n"); dot.append("START -> ").append(this.basicBlocks.get(0).getId()).append(";\n");
dot.append(this.getCurrentBlock().getId()).append(" -> END;\n"); dot.append(this.getCurrentBlock().getId()).append(" -> END;\n");
for (FlowBasicBlock block : this.blocks) { for (FlowBasicBlock block : this.basicBlocks) {
// Successors
for (FlowBasicBlock succ : block.getSuccessorSet()) { for (FlowBasicBlock succ : block.getSuccessorSet()) {
dot.append(block.getId()).append(" -> ").append(succ.getId()).append(";\n"); dot.append(block.getId()).append(" -> ").append(succ.getId()).append(";\n");
} }
// Predecessors
for (FlowBasicBlock pred : block.getPredecessorSet()) {
if (!dot.toString().contains(pred.getId() + " -> " + block.getId())) {
// No duplicate arrows
dot.append(pred.getId()).append(" -> ").append(block.getId()).append(";\n");
}
}
} }
dot.append("}"); dot.append("}");
@ -165,34 +215,13 @@ public class FlowGraph {
@Override @Override
public String toString() { public String toString() {
final String blocksString = this.blocks.stream() final String blocksString = this.basicBlocks.stream()
.map(FlowBasicBlock::toString) .map(FlowBasicBlock::toString)
.collect(Collectors.joining()); .collect(Collectors.joining());
return this.head return this.head
+ blocksString + blocksString
+ this.tail; + this.tail;
} }
private FlowBasicBlock getBlockByLabel(String label) {
return this.blocks.stream()
.filter(block -> block.getLabel().equals(label))
.findFirst()
.orElse(null);
}
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

@ -17,11 +17,15 @@ import java.util.Map;
import static java.util.Map.entry; import static java.util.Map.entry;
import static util.Logger.log; import static util.Logger.log;
/**
* Erzeugt den SourceCode in FlussGraph-Darstellung.
*/
public final class FlowGraphGenerator { public final class FlowGraphGenerator {
private static final Map<String, Method> methodMap; private static final Map<String, Method> methodMap;
static { static {
// Init the method mappings: ASTNode.getName() -> FlowGraphGenerator.method
Map<String, Method> map; Map<String, Method> map;
try { try {
final Class<?> gen = FlowGraphGenerator.class; final Class<?> gen = FlowGraphGenerator.class;
@ -76,7 +80,7 @@ public final class FlowGraphGenerator {
private static Map<String, Integer> initVarMap(AST tree) { private static Map<String, Integer> initVarMap(AST tree) {
final Map<String, Integer> varMap = new HashMap<>(); final Map<String, Integer> varMap = new HashMap<>();
// Assign variables to map // Assign variables to map: Symbol -> jasminLocalVarNr.
int varCount = 0; int varCount = 0;
final Deque<ASTNode> stack = new ArrayDeque<>(); final Deque<ASTNode> stack = new ArrayDeque<>();
stack.push(tree.getRoot()); stack.push(tree.getRoot());
@ -97,14 +101,17 @@ public final class FlowGraphGenerator {
return Collections.unmodifiableMap(varMap); return Collections.unmodifiableMap(varMap);
} }
public Map<String, Integer> getVarMap() { /**
return this.varMap; * Erzeugt den Flussgraphen für den gespeicherten AST.
} * Der Flussgraph ist dabei die Graphenform des generierten SourceCodes:
* Die Instruktionen sind unterteilt in BasicBlocks, welche über Kanten verbunden sind.
*/
public FlowGraph generateGraph() { public FlowGraph generateGraph() {
System.out.println(" - Generating Source Graph..."); System.out.println(" - Generating Source Graph...");
// Skip the first 2 identifiers: ClassName, MainArgs
this.generateNode(this.tree.getRoot().getChildren().get(3).getChildren().get(11)); this.generateNode(this.tree.getRoot().getChildren().get(3).getChildren().get(11));
this.graph.purgeEmptyBlocks();
Logger.call(this.graph::printToImage); Logger.call(this.graph::printToImage);
log("\n\nSourceGraph print:\n" + "-".repeat(100) + "\n" + this.graph.print() + "-".repeat(100)); log("\n\nSourceGraph print:\n" + "-".repeat(100) + "\n" + this.graph.print() + "-".repeat(100));
@ -113,137 +120,168 @@ public final class FlowGraphGenerator {
return this.graph; return this.graph;
} }
private void generateNode(ASTNode node) { /**
if (methodMap.containsKey(node.getName())) { * Erzeugt den FlussGraphen für die angegebene Wurzel.
* Der Wurzelname wird über die methodMap einer Methode zugewiesen.
* Diese wird aufgerufen und erzeugt den entsprechenden Teilbaum.
*/
private void generateNode(ASTNode root) {
if (methodMap.containsKey(root.getName())) {
try { try {
methodMap.get(node.getName()).invoke(this, node); methodMap.get(root.getName()).invoke(this, root);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
} }
} else { } else {
node.getChildren().forEach(this::generateNode); root.getChildren().forEach(this::generateNode);
} }
} }
// ifeq - if value is 0 // ifeq - if value is 0
// ifne - if value is not 0 // ifne - if value is not 0
private void condNode(ASTNode node) {
/**
* Erzeugt den Teilbaum für einen If-Knoten.
*/
private void condNode(ASTNode root) {
final int currentLabel = this.labelCounter; final int currentLabel = this.labelCounter;
this.labelCounter++; this.labelCounter++;
// Condition // Condition If ( ... ) {
this.generateNode(node.getChildren().get(0)); this.generateNode(root.getChildren().get(0));
// Jump // Jump if condition false
this.graph.addJump("ifeq", "IFfalse" + currentLabel); this.graph.addJump("ifeq", "IFfalse" + currentLabel);
// IFtrue branch // IFtrue branch (gets executed without jump)
this.generateNode(node.getChildren().get(1)); this.generateNode(root.getChildren().get(1));
this.graph.addJump("goto", "IFend" + currentLabel); this.graph.addJump("goto", "IFend" + currentLabel); // Skip IFfalse branch
// IFfalse branch // IFfalse branch (gets executed after jump)
this.graph.addLabel("IFfalse" + currentLabel); this.graph.addLabel("IFfalse" + currentLabel);
if (node.getChildren().size() == 3) { if (root.getChildren().size() == 3) {
// Else exists // Else exists
this.generateNode(node.getChildren().get(2)); this.generateNode(root.getChildren().get(2));
} }
// IFend branch // IFend branch
this.graph.addLabel("IFend" + currentLabel); this.graph.addLabel("IFend" + currentLabel);
} }
private void loopNode(ASTNode node) { /**
* Erzeugt den Teilbaum für einen While-Knoten.
*/
private void loopNode(ASTNode root) {
final int currentLabel = this.labelCounter; final int currentLabel = this.labelCounter;
this.labelCounter++; this.labelCounter++;
// LOOPstart label for loop repetition
this.graph.addLabel("LOOPstart" + currentLabel); this.graph.addLabel("LOOPstart" + currentLabel);
// Condition // Condition while ( ... ) {
this.generateNode(node.getChildren().get(0).getChildren().get(1)); this.generateNode(root.getChildren().get(0).getChildren().get(1));
// Jump // Jump out of loop if condition is false
this.graph.addJump("ifeq", "LOOPend" + currentLabel); this.graph.addJump("ifeq", "LOOPend" + currentLabel);
// Loop body // Loop body (gets executed without jump)
this.generateNode(node.getChildren().get(1)); this.generateNode(root.getChildren().get(1));
this.graph.addJump("goto", "LOOPstart" + currentLabel); this.graph.addJump("goto", "LOOPstart" + currentLabel); // Repeat loop
// Loop end // Loop end
this.graph.addLabel("LOOPend" + currentLabel); this.graph.addLabel("LOOPend" + currentLabel);
} }
private void assignNode(ASTNode node) { //! Stack - 1 /**
this.generateNode(node.getChildren().get(0)); * Erzeugt den Teilbaum für Assignment-Knoten.
* Die JVM-Stacksize wird dabei um 1 verringert, da istore/astore 1 Argument konsumieren.
*/
private void assignNode(ASTNode root) { //! Stack - 1
this.generateNode(root.getChildren().get(0));
final String type = this.nodeTypeMap.get(node.getChildren().get(0)); final String type = this.nodeTypeMap.get(root.getChildren().get(0));
final String inst = switch (type) { final String inst = switch (type) {
case "INTEGER_TYPE", "BOOLEAN_TYPE" -> "istore"; case "INTEGER_TYPE", "BOOLEAN_TYPE" -> "istore";
case "STRING_TYPE" -> "astore"; case "STRING_TYPE" -> "astore";
default -> throw new IllegalStateException("Unexpected value: " + type); default -> throw new IllegalStateException("Unexpected value: " + type);
}; };
log("assign(): " + node.getName() + ": " + node.getValue() + " => " + inst); log("assign(): " + root.getName() + ": " + root.getValue() + " => " + inst);
this.graph.addInst(inst, this.varMap.get(node.getValue()).toString()); this.graph.addInstruction(inst, this.varMap.get(root.getValue()).toString());
} }
private void exprNode(ASTNode node) { /**
if ("INTEGER_TYPE".equals(this.nodeTypeMap.get(node))) { * Wählt die entsprechende Methode für mathematische oder logische Ausdrücke.
this.intExpr(node); */
} else if ("BOOLEAN_TYPE".equals(this.nodeTypeMap.get(node))) { private void exprNode(ASTNode root) {
this.boolExpr(node); if ("INTEGER_TYPE".equals(this.nodeTypeMap.get(root))) {
this.intExpr(root);
} else if ("BOOLEAN_TYPE".equals(this.nodeTypeMap.get(root))) {
this.boolExpr(root);
} }
} }
private void intExpr(ASTNode node) { /**
* Erzeugt den Teilbaum für mathematische Ausdrücke.
* Bei unären Operatoren bleibt die Stackgröße konstant (1 konsumiert, 1 Ergebnis),
* bei binären Operatoren sinkt die Stackgröße um 1 (2 konsumiert, 1 Ergebnis).
*/
private void intExpr(ASTNode root) {
String inst = ""; String inst = "";
if (node.getChildren().size() == 1) { //! Stack + 0 if (root.getChildren().size() == 1) { //! Stack + 0
// Unary operator // Unary operator
this.generateNode(node.getChildren().get(0)); this.generateNode(root.getChildren().get(0));
inst = switch (node.getValue()) { inst = switch (root.getValue()) {
case "ADD" -> ""; case "ADD" -> "";
case "SUB" -> "ineg"; case "SUB" -> "ineg";
default -> throw new IllegalStateException("Unexpected value: " + node.getValue()); default -> throw new IllegalStateException("Unexpected value: " + root.getValue());
}; };
} else if (node.getChildren().size() == 2) { //! Stack - 1 } else if (root.getChildren().size() == 2) { //! Stack - 1
// Binary operator // Binary operator
this.generateNode(node.getChildren().get(0)); this.generateNode(root.getChildren().get(0));
this.generateNode(node.getChildren().get(1)); this.generateNode(root.getChildren().get(1));
inst = switch (node.getValue()) { inst = switch (root.getValue()) {
case "ADD" -> "iadd"; // Integer case "ADD" -> "iadd"; // Integer
case "SUB" -> "isub"; case "SUB" -> "isub";
case "MUL" -> "imul"; case "MUL" -> "imul";
case "DIV" -> "idiv"; case "DIV" -> "idiv";
case "MOD" -> "irem"; // Remainder operator case "MOD" -> "irem"; // Remainder operator
default -> throw new IllegalStateException("Unexpected value: " + node.getValue()); default -> throw new IllegalStateException("Unexpected value: " + root.getValue());
}; };
} }
log("intExpr(): " + node.getName() + ": " + node.getValue() + " => " + inst); log("intExpr(): " + root.getName() + ": " + root.getValue() + " => " + inst);
this.graph.addInst(inst); this.graph.addInstruction(inst);
} }
/**
* Erzeugt den Teilbaum für logische Ausdrücke.
* Bei unären Operatoren wächst der Stack temporär um 1 (NOT pusht eine 1 für xor),
* bei binären Operatoren sinkt die Stackgröße um 1 (2 konsumiert, 1 Ergebnis).
*/
private void boolExpr(ASTNode node) { private void boolExpr(ASTNode node) {
if (node.getChildren().size() == 1) { //! Stack + 1 if (node.getChildren().size() == 1) { //! Stack + 1
// Unary operator // Unary operator
if (!"NOT".equals(node.getValue())) { if (!"NOT".equals(node.getValue())) {
// Diese Möglichkeit gibts eigentlich nicht // Possibility doesn't exist, would be frontend-error
throw new IllegalStateException("Unexpected value: " + node.getValue()); throw new IllegalStateException("Unexpected value: " + node.getValue());
} }
this.generateNode(node.getChildren().get(0)); this.generateNode(node.getChildren().get(0));
// 0 ^1 = 1, 1 ^1 = 0 // 0 xor 1 = 1, 1 xor 1 = 0 => not
this.graph.addInst("ldc", "1"); this.graph.addInstruction("ldc", "1");
this.graph.addInst("ixor"); this.graph.addInstruction("ixor");
} else if (node.getChildren().size() == 2) { //! Stack - 1 } else if (node.getChildren().size() == 2) { //! Stack - 1
// Binary operator // Binary operator
@ -266,9 +304,10 @@ public final class FlowGraphGenerator {
default -> throw new IllegalStateException("Unexpected value: " + type); default -> throw new IllegalStateException("Unexpected value: " + type);
}; };
// The comparison operations need to jump
switch (node.getValue()) { switch (node.getValue()) {
case "AND" -> this.graph.addInst("iand"); // Boolean case "AND" -> this.graph.addInstruction("iand"); // Boolean
case "OR" -> this.graph.addInst("ior"); case "OR" -> this.graph.addInstruction("ior");
case "EQUAL" -> this.genComparisonInst(cmpeq, "EQ", currentLabel); case "EQUAL" -> this.genComparisonInst(cmpeq, "EQ", currentLabel);
case "NOT_EQUAL" -> this.genComparisonInst(cmpne, "NE", currentLabel); case "NOT_EQUAL" -> this.genComparisonInst(cmpne, "NE", currentLabel);
case "LESS" -> this.genComparisonInst("if_icmplt", "LT", currentLabel); case "LESS" -> this.genComparisonInst("if_icmplt", "LT", currentLabel);
@ -280,12 +319,19 @@ public final class FlowGraphGenerator {
} }
} }
/**
* Erzeugt die Instruktionen für eine Vergleichsoperation.
*
* @param cmpInst Die Vergleichsanweisung
* @param labelPre Das Labelpräfix, abhängig von der Art des Vergleichs
* @param currentLabel Der aktuelle Labelcounter
*/
private void genComparisonInst(String cmpInst, String labelPre, int currentLabel) { private void genComparisonInst(String cmpInst, String labelPre, int currentLabel) {
this.graph.addJump(cmpInst, labelPre + "true" + currentLabel); // If not equal jump to NEtrue this.graph.addJump(cmpInst, labelPre + "true" + currentLabel); // If not equal jump to NEtrue
this.graph.addInst("ldc", "0"); // If false load 0 this.graph.addInstruction("ldc", "0"); // If false load 0
this.graph.addJump("goto", labelPre + "end" + currentLabel); // If false skip to true this.graph.addJump("goto", labelPre + "end" + currentLabel); // If false skip to true
this.graph.addLabel(labelPre + "true" + currentLabel); this.graph.addLabel(labelPre + "true" + currentLabel);
this.graph.addInst("ldc", "1"); // If true load 1 this.graph.addInstruction("ldc", "1"); // If true load 1
this.graph.addLabel(labelPre + "end" + currentLabel); this.graph.addLabel(labelPre + "end" + currentLabel);
} }
@ -295,7 +341,7 @@ public final class FlowGraphGenerator {
log("intStringLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc"); log("intStringLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc");
// bipush only pushes 1 byte as int // bipush only pushes 1 byte as int
this.graph.addInst("ldc", node.getValue()); this.graph.addInstruction("ldc", node.getValue());
} }
private void boolLiteralNode(ASTNode node) { //! Stack + 1 private void boolLiteralNode(ASTNode node) { //! Stack + 1
@ -303,7 +349,7 @@ public final class FlowGraphGenerator {
final String val = "true".equals(node.getValue()) ? "1" : "0"; final String val = "true".equals(node.getValue()) ? "1" : "0";
this.graph.addInst("ldc", val); this.graph.addInstruction("ldc", val);
} }
private void identifierNode(ASTNode node) { //! Stack + 1 private void identifierNode(ASTNode node) { //! Stack + 1
@ -316,11 +362,11 @@ public final class FlowGraphGenerator {
log("identifier(): " + node.getName() + ": " + node.getValue() + " => " + inst); log("identifier(): " + node.getName() + ": " + node.getValue() + " => " + inst);
this.graph.addInst(inst, this.varMap.get(node.getValue()).toString()); this.graph.addInstruction(inst, this.varMap.get(node.getValue()).toString());
} }
private void printlnNode(ASTNode node) { //! Stack + 1 private void printlnNode(ASTNode node) { //! Stack + 1
this.graph.addInst("getstatic", "java/lang/System/out", "Ljava/io/PrintStream;"); this.graph.addInstruction("getstatic", "java/lang/System/out", "Ljava/io/PrintStream;");
final ASTNode expr = node.getChildren().get(1).getChildren().get(1); final ASTNode expr = node.getChildren().get(1).getChildren().get(1);
final String type = switch (this.nodeTypeMap.get(expr)) { final String type = switch (this.nodeTypeMap.get(expr)) {
@ -334,6 +380,12 @@ public final class FlowGraphGenerator {
log("println(): " + expr.getName() + ": " + expr.getValue() + " => " + type); log("println(): " + expr.getName() + ": " + expr.getValue() + " => " + type);
this.graph.addInst("invokevirtual", "java/io/PrintStream/println(" + type + ")V"); this.graph.addInstruction("invokevirtual", "java/io/PrintStream/println(" + type + ")V");
}
// Getters, Setters
public Map<String, Integer> getVarMap() {
return this.varMap;
} }
} }