diff --git a/.idea/jpa-buddy.xml b/.idea/jpa-buddy.xml new file mode 100644 index 0000000..966d5f5 --- /dev/null +++ b/.idea/jpa-buddy.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 49a9bf2..ad4a026 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,7 +4,10 @@ - + + + \ No newline at end of file diff --git a/README.md b/README.md index fe7621a..35a6e6d 100644 --- a/README.md +++ b/README.md @@ -6,26 +6,26 @@ Go to [this Lab on iCorsi](https://www.icorsi.ch/course/view.php?id=16963). ## Submission Info -Property | Value ------------- | ------------- -First Name | ... -Last Name | ... +| Property | Value | +|------------|----------| +| First Name | Claudio | +| Last Name | Maggioni | ## Submission Checklist Please complete this checklist (turn [ ] into [X]) before you submit: -- [ ] I completed the above Submission Info -- [ ] I built the project in IntelliJ (Build > Build Project) +- [x] I completed the above Submission Info +- [x] I built the project in IntelliJ (Build > Build Project) - [ ] I implemented the ControlFlowGraphBuilder - [ ] I implemented the ControlFlowGraphRenderer - [ ] I wrote the source code myself and did not look at the source code of my class mates - [ ] I ran all the JUnit tests and verified that they all pass - [ ] I manually checked that my implementation is correct by doing this: - - [ ] I studied the test-input/ExampleClass.java source code - - [ ] I ran App to produce the dot files (in test-output/) - - [ ] I ran dot to turn the dot files in test-output into a PDF - - [ ] I manually verified that the PDF contains one page per method of ExampleClass - - [ ] I manually verified that those CFGs correspond to the methods' source code + - [ ] I studied the test-input/ExampleClass.java source code + - [ ] I ran App to produce the dot files (in test-output/) + - [ ] I ran dot to turn the dot files in test-output into a PDF + - [ ] I manually verified that the PDF contains one page per method of ExampleClass + - [ ] I manually verified that those CFGs correspond to the methods' source code - [ ] I committed my changes (at least one commit, but possibly many) - [ ] I pushed my commits to GitHub diff --git a/lab-3-maggicl.iml b/lab-3-maggicl.iml new file mode 100644 index 0000000..2663f31 --- /dev/null +++ b/lab-3-maggicl.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ch/usi/inf/sp/cfg/ControlFlowGraphBuilder.java b/src/ch/usi/inf/sp/cfg/ControlFlowGraphBuilder.java index 9579528..4806b89 100644 --- a/src/ch/usi/inf/sp/cfg/ControlFlowGraphBuilder.java +++ b/src/ch/usi/inf/sp/cfg/ControlFlowGraphBuilder.java @@ -1,6 +1,6 @@ package ch.usi.inf.sp.cfg; -import java.util.List; +import java.util.*; import ch.usi.inf.sp.bytecode.Disassembler; import org.objectweb.asm.Opcodes; @@ -16,8 +16,99 @@ import org.objectweb.asm.tree.TableSwitchInsnNode; public class ControlFlowGraphBuilder { public static ControlFlowGraph createControlFlowGraph(final MethodNode method) { - //TODO - return null; + final Map labelToSource = new HashMap<>(); + + // get the list of all instructions in that method + final InsnList instructions = method.instructions; + for (int i = 0; i < instructions.size(); i++) { + final AbstractInsnNode instruction = instructions.get(i); + + switch (instruction.getType()) { + case AbstractInsnNode.JUMP_INSN: + final JumpInsnNode jumpInsn = (JumpInsnNode) instruction; + labelToSource.put(jumpInsn.label, new Edge(instruction, "T")); + + case AbstractInsnNode.LOOKUPSWITCH_INSN: + final LookupSwitchInsnNode lookupSwitchInsnNode = (LookupSwitchInsnNode) instruction; + for (int j = 0; j < lookupSwitchInsnNode.labels.size(); j++) { + final LabelNode label = lookupSwitchInsnNode.labels.get(i); + final String value = lookupSwitchInsnNode.keys.get(i).toString(); + labelToSource.put(label, new Edge(instruction, value)); + } + if (lookupSwitchInsnNode.dflt != null) + labelToSource.put(lookupSwitchInsnNode.dflt, new Edge(instruction, "default")); + + case AbstractInsnNode.TABLESWITCH_INSN: + final TableSwitchInsnNode tableSwitchInsnNode = (TableSwitchInsnNode) instruction; + for (int k = 0; k < tableSwitchInsnNode.labels.size(); k++) { + final LabelNode label = tableSwitchInsnNode.labels.get(i); + final String value = Integer.toString(tableSwitchInsnNode.min + k); + labelToSource.put(label, new Edge(instruction, value)); + } + if (tableSwitchInsnNode.dflt != null) + labelToSource.put(tableSwitchInsnNode.dflt, new Edge(instruction, "default")); + } + } + + final ControlFlowGraph graph = new ControlFlowGraph(); + final Map blocksById = new HashMap<>(); + + BasicBlock currentBasicBlock = new BasicBlock(0); + graph.addNode(currentBasicBlock); + blocksById.put(0, currentBasicBlock); + + graph.addEntryEdge(currentBasicBlock); + + for (int i = 0; i < instructions.size(); i++) { + final AbstractInsnNode instruction = instructions.get(i); + final int opcode = instruction.getOpcode(); + final int type = instruction.getType(); + + currentBasicBlock.appendInstruction(Disassembler.disassembleInstruction(instruction, i, instructions)); + + if (opcode == Opcodes.RETURN + || opcode == Opcodes.ARETURN + || opcode == Opcodes.LRETURN + || opcode == Opcodes.IRETURN + || opcode == Opcodes.FRETURN) { + graph.addExitEdge(currentBasicBlock); + } + + if (type == AbstractInsnNode.JUMP_INSN + || type == AbstractInsnNode.LOOKUPSWITCH_INSN + || type == AbstractInsnNode.TABLESWITCH_INSN + || labelToSource.containsKey(instruction)) { + final int nextI = i + 1; + + // if we're not at the end + if (nextI < instructions.size()) { + final BasicBlock previousBasicBlock = currentBasicBlock; + + currentBasicBlock = new BasicBlock(nextI); + graph.addNode(currentBasicBlock); + blocksById.put(nextI, currentBasicBlock); + + // Handle "implicit" edges from this basic block to the next one, or the exit node + if (instructions.get(nextI).getOpcode() != Opcodes.GOTO) { + graph.addFallthroughEdge(previousBasicBlock, currentBasicBlock); + } + } + } + } + + // TODO: add remaining branching edges and refactor code + + return graph; + } + + private static class Edge { + final AbstractInsnNode instruction; + final String condition; + + Edge(AbstractInsnNode instruction, String condition) { + this.instruction = instruction; + this.condition = condition; + } } } diff --git a/starter-lab-03-control-flow-graph.iml b/starter-lab-03-control-flow-graph.iml index 4f0d2e5..f4c6023 100644 --- a/starter-lab-03-control-flow-graph.iml +++ b/starter-lab-03-control-flow-graph.iml @@ -21,5 +21,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file