Initial commit

This commit is contained in:
github-classroom[bot] 2023-10-18 19:57:49 +00:00 committed by GitHub
commit 74a433f602
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
73 changed files with 2719 additions and 0 deletions

2
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml

View file

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View file

@ -0,0 +1,19 @@
<component name="libraryTable">
<library name="asm-util-7.1">
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/asm-util-7.1.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-tree-7.1.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-7.1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$PROJECT_DIR$/lib/asm-util-7.1-javadoc.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-tree-7.1-javadoc.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-7.1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$PROJECT_DIR$/lib/asm-util-7.1-sources.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-tree-7.1-sources.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/asm-7.1-sources.jar!/" />
</SOURCES>
</library>
</component>

10
.idea/misc.xml Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ASMPluginConfiguration">
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
<groovy codeStyle="LEGACY" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="10" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/starter-lab-04-dominator-analysis.iml" filepath="$PROJECT_DIR$/starter-lab-04-dominator-analysis.iml" />
</modules>
</component>
</project>

View file

@ -0,0 +1,16 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="App" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="ch.usi.inf.sp.cfg.App" />
<module name="starter-lab-04-dominator-analysis" />
<option name="PROGRAM_PARAMETERS" value="test-input/java10/ExampleClass.class test-output" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="ch.usi.inf.sp.graph.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,16 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Disassembler" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="ch.usi.inf.sp.bytecode.Disassembler" />
<module name="starter-lab-03-control-flow-graph" />
<option name="PROGRAM_PARAMETERS" value="test-input/java10/ExampleClass.class" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="ch.usi.inf.sp.bytecode.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,3 @@
9
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d

124
.idea/uiDesigner.xml Normal file
View file

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

34
README.md Normal file
View file

@ -0,0 +1,34 @@
# Lab 4 - Software Peformance 2023
This is Lab 4 of the **Software Performance** course at USI.
Go to [this Lab on iCorsi](https://www.icorsi.ch/course/view.php?id=16963).
## Submission Info
Property | Value
------------ | -------------
First Name | ...
Last Name | ...
## 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)
- [ ] I (re)implemented the ControlFlowGraphBuilder (copy from Lab 3)
- [ ] I (re)implemented the ControlFlowGraphRenderer (copy from Lab 3)
- [ ] I implemented the Traversal
- [ ] I implemented the DominatorAnalyzer
- [ ] 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 a set of pages per method of ExampleClass
- [ ] I manually verified that the CFGs in the PDFs correspond to the methods' source code
- [ ] I manually verified that the dominator trees in the PDFs correspond to the method's source code
- [ ] I committed my changes (at least one commit, but possibly many)
- [ ] I pushed my commits to GitHub

BIN
lib/asm-7.1-javadoc.jar Normal file

Binary file not shown.

BIN
lib/asm-7.1-sources.jar Normal file

Binary file not shown.

BIN
lib/asm-7.1.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/asm-tree-7.1.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/asm-util-7.1.jar Normal file

Binary file not shown.

View file

@ -0,0 +1,265 @@
package ch.usi.inf.sp.bytecode;
import java.io.FileInputStream;
import java.util.List;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.util.Printer;
/**
* A Disassembler can disassemble Java class files.
* It presents an output similar to javap -c.
* Given the name of the class file as a command line argument,
* it prints the name of the class, a list of all methods,
* and for each method, the list of all Java bytecode instructions.
* <p>
* The format of the disassembled bytecode includes the opcodes
* (in the form of mnemonics such as "ILOAD") and all the operands.
* Some operands can be printed as simple integers, while others have to be printed in a more understandable form
* (e.g. method or field names and descriptors).
* Operands of branch instructions are shown as an "id" of the targeted instruction.
* For this, all instructions of a method, including ASM's pseudo-instructions (LABEL, LINE, FRAME),
* are numbered, starting at 0.
* The instruction id allows you to look up the corresponding instruction object in the instruction list:
* AbstractInsnNode target = instructionList.get(targetId);
* <p>
* An example output:
*
* <pre>
* Class: ExampleClass
* ...
* Method: switchMethod2(I)I
* 0: // label
* 1: // line number information
* 2: ICONST_0
* 3: ISTORE 2
* 4: // label
* 5: // line number information
* 6: ILOAD 1
* 7: LOOKUPSWITCH 0: 8, 1000: 13, 2000: 18, default: 23
* 8: // label
* 9: // line number information
* 10: ICONST_0
* 11: ISTORE 2
* 12: GOTO 27
* 13: // label
* 14: // line number information
* 15: ICONST_1
* 16: ISTORE 2
* 17: GOTO 27
* 18: // label
* 19: // line number information
* 20: ICONST_2
* 21: ISTORE 2
* 22: GOTO 27
* 23: // label
* 24: // line number information
* 25: ICONST_M1
* 26: ISTORE 2
* 27: // label
* 28: // line number information
* 29: ILOAD 2
* 30: IRETURN
* 31: // label
* </pre>
*
* @author Matthias.Hauswirth@usi.ch
*/
public class Disassembler {
public static void main(final String[] args) throws Exception {
// create a ClassReader that loads the Java .class file specified as the command line argument
final String classFileName = args[0];
final ClassReader cr = new ClassReader(new FileInputStream(classFileName));
// create an empty ClassNode (in-memory representation of a class)
final ClassNode clazz = new ClassNode();
// have the ClassReader read the class file and populate the ClassNode with the corresponding information
cr.accept(clazz, 0);
// create a dumper and have it dump the given ClassNode
System.out.println(disassembleClass(clazz));
}
public static String disassembleClass(final ClassNode clazz) {
final StringBuffer sb = new StringBuffer("Class: ");
sb.append(clazz.name);
sb.append('\n');
// get the list of all methods in that class
final List<MethodNode> methods = clazz.methods;
for (int m = 0; m < methods.size(); m++) {
final MethodNode method = methods.get(m);
sb.append(disassembleMethod(method));
}
return sb.toString();
}
public static String disassembleMethod(final MethodNode method) {
final StringBuffer sb = new StringBuffer(" Method: ");
sb.append(method.name);
sb.append(method.desc);
sb.append('\n');
// 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);
sb.append(" ");
sb.append(Disassembler.disassembleInstruction(instruction, i, instructions));
sb.append('\n');
}
return sb.toString();
}
/**
* Hint: Check out org.objectweb.asm.MethodVisitor to determine which instructions (opcodes)
* have which instruction types (subclasses of AbstractInsnNode).
*
* @see org.objectweb.asm.MethodVisitor
* <p>
* E.g. the comment in org.objectweb.asm.MethodVisitor.visitIntInsn(int opcode, int operand)
* shows the list of all opcodes that are represented as instructions of type IntInsnNode.
* That list e.g. includes the BIPUSH opcode.
*/
public static String disassembleInstruction(final AbstractInsnNode instruction, final int i, final InsnList instructions) {
StringBuffer sb = new StringBuffer();
final int opcode = instruction.getOpcode();
final String mnemonic = opcode == -1 ? "" : Printer.OPCODES[instruction.getOpcode()];
sb.append(i + ":\t" + mnemonic + " ");
// There are different subclasses of AbstractInsnNode.
// AbstractInsnNode.getType() represents the subclass as an int.
// Note:
// to check the subclass of an instruction node, we can either use:
// if (instruction.getType()==AbstractInsnNode.LABEL)
// or we can use:
// if (instruction instanceof LabelNode)
// They give the same result, but the first one can be used in a switch statement.
switch (instruction.getType()) {
case AbstractInsnNode.LABEL:
// pseudo-instruction (branch or exception target)
sb.append("// label");
break;
case AbstractInsnNode.FRAME:
// pseudo-instruction (stack frame map)
sb.append("// stack frame map");
break;
case AbstractInsnNode.LINE:
// pseudo-instruction (line number information)
sb.append("// line number information");
case AbstractInsnNode.INSN:
// Opcodes: NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2,
// ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0,
// FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD,
// DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE,
// DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP,
// DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD,
// DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV,
// FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL,
// LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR,
// I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B,
// I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN,
// FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW,
// MONITORENTER, or MONITOREXIT.
// zero operands, nothing to print
break;
case AbstractInsnNode.INT_INSN:
// Opcodes: NEWARRAY, BIPUSH, SIPUSH.
if (instruction.getOpcode() == Opcodes.NEWARRAY) {
// NEWARRAY
sb.append(Printer.TYPES[((IntInsnNode) instruction).operand]);
} else {
// BIPUSH or SIPUSH
sb.append(((IntInsnNode) instruction).operand);
}
break;
case AbstractInsnNode.JUMP_INSN:
// Opcodes: IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
// IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ,
// IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
{
final LabelNode targetInstruction = ((JumpInsnNode) instruction).label;
final int targetId = instructions.indexOf(targetInstruction);
sb.append(targetId);
break;
}
case AbstractInsnNode.LDC_INSN:
// Opcodes: LDC.
sb.append(((LdcInsnNode) instruction).cst);
break;
case AbstractInsnNode.IINC_INSN:
// Opcodes: IINC.
sb.append(((IincInsnNode) instruction).var);
sb.append(" ");
sb.append(((IincInsnNode) instruction).incr);
break;
case AbstractInsnNode.TYPE_INSN:
// Opcodes: NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
sb.append(((TypeInsnNode) instruction).desc);
break;
case AbstractInsnNode.VAR_INSN:
// Opcodes: ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE,
// LSTORE, FSTORE, DSTORE, ASTORE or RET.
sb.append(((VarInsnNode) instruction).var);
break;
case AbstractInsnNode.FIELD_INSN:
// Opcodes: GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
sb.append(((FieldInsnNode) instruction).owner);
sb.append(".");
sb.append(((FieldInsnNode) instruction).name);
sb.append(" ");
sb.append(((FieldInsnNode) instruction).desc);
break;
case AbstractInsnNode.METHOD_INSN:
// Opcodes: INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC,
// INVOKEINTERFACE or INVOKEDYNAMIC.
sb.append(((MethodInsnNode) instruction).owner);
sb.append(".");
sb.append(((MethodInsnNode) instruction).name);
sb.append(" ");
sb.append(((MethodInsnNode) instruction).desc);
break;
case AbstractInsnNode.MULTIANEWARRAY_INSN:
// Opcodes: MULTIANEWARRAY.
sb.append(((MultiANewArrayInsnNode) instruction).desc);
sb.append(" ");
sb.append(((MultiANewArrayInsnNode) instruction).dims);
break;
case AbstractInsnNode.LOOKUPSWITCH_INSN:
// Opcodes: LOOKUPSWITCH.
{
final List keys = ((LookupSwitchInsnNode) instruction).keys;
final List labels = ((LookupSwitchInsnNode) instruction).labels;
for (int t = 0; t < keys.size(); t++) {
final int key = (Integer) keys.get(t);
final LabelNode targetInstruction = (LabelNode) labels.get(t);
final int targetId = instructions.indexOf(targetInstruction);
sb.append(key + ": " + targetId + ", ");
}
final LabelNode defaultTargetInstruction = ((LookupSwitchInsnNode) instruction).dflt;
final int defaultTargetId = instructions.indexOf(defaultTargetInstruction);
sb.append("default: " + defaultTargetId);
break;
}
case AbstractInsnNode.TABLESWITCH_INSN:
// Opcodes: TABLESWITCH.
{
final int minKey = ((TableSwitchInsnNode) instruction).min;
final List labels = ((TableSwitchInsnNode) instruction).labels;
for (int t = 0; t < labels.size(); t++) {
final int key = minKey + t;
final LabelNode targetInstruction = (LabelNode) labels.get(t);
final int targetId = instructions.indexOf(targetInstruction);
sb.append(key + ": " + targetId + ", ");
}
final LabelNode defaultTargetInstruction = ((TableSwitchInsnNode) instruction).dflt;
final int defaultTargetId = instructions.indexOf(defaultTargetInstruction);
sb.append("default: " + defaultTargetId);
break;
}
}
return sb.toString();
}
}

View file

@ -0,0 +1,99 @@
package ch.usi.inf.sp.cfg;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import ch.usi.inf.sp.bytecode.Disassembler;
import ch.usi.inf.sp.dom.DominatorAnalyzer;
import ch.usi.inf.sp.dom.DominatorTree;
import ch.usi.inf.sp.dom.DominatorTreeRenderer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
public final class App {
/**
* Invoke like this...
* <p>
* java App test-input/java10/ExampleClass.class test-output
* <p>
* to produce one disassembly, one CFG, one dominator tree,
* and one combined graph (CFG with additional dotted dominance edges)
* for each method in ExampleClass.
* Afterwards, go to the test-output folder, and call...
* <p>
* dot -Tpdf -oall.pdf *.dot
* <p>
* ...to produce a file all.pdf containing one page for each graph, or...
* <p>
* dot -Tpdf -oall.combined.pdf *.combined.pdf
* </p>
* ...to produce a file all.combined.pdf with just the combined graphs.
*
* MAKE SURE YOU MANUALLY VERIFY FOR EACH METHOD THAT THE DOMINATORS ARE CORRECT.
*/
public static void main(final String[] args) throws IOException {
final File classFile = new File(args[0]);
final File outputDirectory = new File(args[1]);
final App app = new App(classFile, outputDirectory);
app.execute();
}
private final File classFile;
private final File outputDirectory;
public App(final File classFile, final File outputDirectory) {
this.classFile = classFile;
this.outputDirectory = outputDirectory;
}
/**
* Save the given contents into a file with the given fileName in the outputDirectory.
*/
private void save(final String fileName, final String contents) throws IOException {
if (!outputDirectory.exists()) {
outputDirectory.mkdirs();
}
final File file = new File(outputDirectory, fileName);
final FileWriter writer = new FileWriter(file);
writer.write(contents);
writer.close();
}
public void execute() throws IOException {
final ClassReader cr = new ClassReader(new FileInputStream(classFile));
// create an empty ClassNode (in-memory representation of a class)
final ClassNode cn = new ClassNode();
// have the ClassReader read the class file and populate the ClassNode with the corresponding information
cr.accept(cn, 0);
// disassemble and perform control-flow analysis
processClass(cn);
}
private void processClass(final ClassNode cn) throws IOException {
System.out.println("Class: " + cn.name);
// get the list of all methods in that class
final List<MethodNode> methods = cn.methods;
for (int m = 0; m < methods.size(); m++) {
final MethodNode method = methods.get(m);
processMethod(method);
}
}
private void processMethod(final MethodNode method) throws IOException {
System.out.println(" Method: " + method.name + method.desc);
save(method.name + ".asm.txt", Disassembler.disassembleMethod(method));
final ControlFlowGraph cfg = ControlFlowGraphBuilder.createControlFlowGraph(method);
save(method.name + ".cfg.dot", ControlFlowGraphRenderer.renderControlFlowGraph(method.name, cfg));
final DominatorTree dt = DominatorAnalyzer.analyze(cfg);
save(method.name + ".dt.dot", DominatorTreeRenderer.renderDominatorTree(method.name, dt));
save(method.name + ".combined.dot", DominatorTreeRenderer.renderCombined(method.name, cfg, dt));
}
}

View file

@ -0,0 +1,44 @@
package ch.usi.inf.sp.cfg;
import ch.usi.inf.sp.graph.Node;
import java.util.ArrayList;
public final class BasicBlock extends Node<ControlFlowEdge> {
private final int id;
private final ArrayList<String> instructions;
public BasicBlock(final int id) {
this.id = id;
instructions = new ArrayList<String>();
}
public void appendInstruction(final String s) {
instructions.add(s);
}
public int getId() {
return id;
}
public int getInstructionCount() {
return instructions.size();
}
public String getInstruction(int i) {
return instructions.get(i);
}
public Iterable<String> getInstructions() {
return instructions;
}
@Override
public String toString() {
return "\""+id+"\"";
}
}

View file

@ -0,0 +1,19 @@
package ch.usi.inf.sp.cfg;
import ch.usi.inf.sp.graph.Edge;
public final class ControlFlowEdge extends Edge<BasicBlock> {
private final String label;
public ControlFlowEdge(final String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}

View file

@ -0,0 +1,110 @@
package ch.usi.inf.sp.cfg;
import ch.usi.inf.sp.graph.DiGraph;
public final class ControlFlowGraph extends DiGraph<BasicBlock, ControlFlowEdge> {
private BasicBlock entry;
private BasicBlock exit;
public ControlFlowGraph() {
entry = new BasicBlock(-1);
addNode(entry);
exit = new BasicBlock(-2);
addNode(exit);
}
private final void checkContains(BasicBlock block, String name) {
if (!getNodes().contains(block)) {
throw new IllegalStateException("Control flow graph does not contain the given " + name + " block.");
}
}
public ControlFlowEdge addEntryEdge(BasicBlock firstBlock) {
if (entry.getOutEdges().size() > 0) {
throw new IllegalStateException("Control flow graph already has an entry edge. It can only have one.");
}
checkContains(firstBlock, "firstBlock");
ControlFlowEdge edge = new ControlFlowEdge("");
addEdge(edge);
connect(entry, edge, firstBlock);
return edge;
}
public ControlFlowEdge addExitEdge(BasicBlock returnBlock) {
checkContains(returnBlock, "returnBlock");
ControlFlowEdge edge = new ControlFlowEdge("");
addEdge(edge);
connect(returnBlock, edge, exit);
return edge;
}
public ControlFlowEdge addFallthroughEdge(BasicBlock fromBlock, BasicBlock toBlock) {
checkContains(fromBlock, "fromBlock");
checkContains(toBlock, "toBlock");
ControlFlowEdge edge = new ControlFlowEdge("");
addEdge(edge);
connect(fromBlock, edge, toBlock);
return edge;
}
public ControlFlowEdge addBranchTakenEdge(BasicBlock fromBlock, BasicBlock toBlock) {
checkContains(fromBlock, "fromBlock");
checkContains(toBlock, "toBlock");
ControlFlowEdge edge = new ControlFlowEdge("T");
addEdge(edge);
connect(fromBlock, edge, toBlock);
return edge;
}
public ControlFlowEdge addCaseEdge(BasicBlock fromBlock, BasicBlock toBlock, int key) {
checkContains(fromBlock, "fromBlock");
checkContains(toBlock, "toBlock");
ControlFlowEdge edge = new ControlFlowEdge("" + key);
addEdge(edge);
connect(fromBlock, edge, toBlock);
return edge;
}
public ControlFlowEdge addDefaultEdge(BasicBlock fromBlock, BasicBlock toBlock) {
checkContains(fromBlock, "fromBlock");
checkContains(toBlock, "toBlock");
ControlFlowEdge edge = new ControlFlowEdge("default");
addEdge(edge);
connect(fromBlock, edge, toBlock);
return edge;
}
public BasicBlock getEntry() {
return entry;
}
public BasicBlock getExit() {
return exit;
}
public String toString() {
final StringBuffer sb = new StringBuffer("digraph CFG {\n");
for (final BasicBlock node : getNodes()) {
if (node==entry) {
sb.append(" " + node + " [shape=circle,style=filled,label=e]\n");
} else if (node==exit) {
sb.append(" " + node + " [shape=circle,style=filled,label=x]\n");
} else {
sb.append(" " + node + " [shape=rectangle]\n");
}
}
for (final ControlFlowEdge edge : getEdges()) {
if (edge.getLabel().length()>0) {
sb.append(" " + edge + " [label=" + edge.getLabel() + "]\n");
} else {
sb.append(" " + edge + "\n");
}
}
sb.append("}\n");
return sb.toString();
}
}

View file

@ -0,0 +1,23 @@
package ch.usi.inf.sp.cfg;
import java.util.List;
import ch.usi.inf.sp.bytecode.Disassembler;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LookupSwitchInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TableSwitchInsnNode;
public class ControlFlowGraphBuilder {
public static ControlFlowGraph createControlFlowGraph(final MethodNode method) {
//TODO
return null;
}
}

View file

@ -0,0 +1,11 @@
package ch.usi.inf.sp.cfg;
public class ControlFlowGraphRenderer {
public static String renderControlFlowGraph(final String label, final ControlFlowGraph cfg) {
//TODO
return null;
}
}

View file

@ -0,0 +1,8 @@
package ch.usi.inf.sp.dom;
import ch.usi.inf.sp.graph.Edge;
public class DominanceEdge extends Edge<DominatorTreeNode> {
}

View file

@ -0,0 +1,52 @@
package ch.usi.inf.sp.dom;
import ch.usi.inf.sp.cfg.BasicBlock;
import ch.usi.inf.sp.cfg.ControlFlowGraph;
import ch.usi.inf.sp.graph.Traversal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DominatorAnalyzer {
/**
* Cooper et al.'s "Engineered Algorithm".
* ================================================================
* for all nodes, b // initialize the dominators array
* doms[b] Undefined
* doms[entryNode] entryNode
* Changed true
* while (Changed)
* Changed false
* for all nodes, b, in reverse postorder (except entryNode)
* newidom first (processed) predecessor of b // (pick one)
* for all other predecessors, p, of b
* if doms[p] != Undefined // i.e., if doms[p] already calculated
* newidom intersect(p, newidom)
* if doms[b] != newidom
* doms[b] newidom
* Changed true
*
* function intersect(b1, b2) returns node
* finger1 b1
* finger2 b2
* while (finger1 != finger2)
* while (finger1 < finger2)
* finger1 = doms[finger1]
* while (finger2 < finger1)
* finger2 = doms[finger2]
* return finger1
* ================================================================
* Figure 3 of Cooper, Harvey, Kennedy
*/
public static DominatorTree analyze(final ControlFlowGraph cfg) {
//TODO
return null;
}
// probably add a method intersect(...)
}

View file

@ -0,0 +1,80 @@
package ch.usi.inf.sp.dom;
import ch.usi.inf.sp.cfg.BasicBlock;
import ch.usi.inf.sp.graph.DiGraph;
import java.util.HashMap;
import java.util.Map;
public final class DominatorTree extends DiGraph<DominatorTreeNode,DominanceEdge> {
private Map<BasicBlock,DominatorTreeNode> nodeForBlock;
private DominatorTreeNode rootNode;
public DominatorTree() {
nodeForBlock = new HashMap<>();
}
public DominatorTreeNode getNodeForBlock(final BasicBlock block) {
return nodeForBlock.get(block);
}
public DominatorTreeNode setRootBlock(BasicBlock rootBlock) {
DominatorTreeNode newRootNode = nodeForBlock.get(rootBlock);
if (newRootNode==null) {
newRootNode = new DominatorTreeNode(rootBlock);
nodeForBlock.put(rootBlock, newRootNode);
}
if (!getNodes().contains(newRootNode)) {
addNode(newRootNode);
}
rootNode = newRootNode;
return rootNode;
}
public DominatorTreeNode getRoot() {
return rootNode;
}
public DominanceEdge addDominanceEdge(BasicBlock idom, BasicBlock child) {
DominatorTreeNode idomNode = nodeForBlock.get(idom);
if (idomNode==null) {
idomNode = new DominatorTreeNode(idom);
nodeForBlock.put(idom, idomNode);
}
if (!getNodes().contains(idomNode)) {
addNode(idomNode);
}
DominatorTreeNode childNode = nodeForBlock.get(child);
if (childNode==null) {
childNode = new DominatorTreeNode(child);
nodeForBlock.put(child, childNode);
}
if (!getNodes().contains(childNode)) {
addNode(childNode);
}
final DominanceEdge edge = new DominanceEdge();
addEdge(edge);
connect(idomNode, edge, childNode);
return edge;
}
public String toString() {
final StringBuffer sb = new StringBuffer("digraph DOM {\n");
for (final DominatorTreeNode node : getNodes()) {
if (node==rootNode) {
sb.append(" " + node + " [style=filled]\n");
} else {
sb.append(" " + node + "\n");
}
}
for (final DominanceEdge edge : getEdges()) {
sb.append(" "+edge+"\n");
}
sb.append("}\n");
return sb.toString();
}
}

View file

@ -0,0 +1,30 @@
package ch.usi.inf.sp.dom;
import ch.usi.inf.sp.cfg.BasicBlock;
import ch.usi.inf.sp.graph.Node;
public class DominatorTreeNode extends Node<DominanceEdge> {
private final BasicBlock block;
public DominatorTreeNode(final BasicBlock block) {
this.block = block;
}
public BasicBlock getBlock() {
return block;
}
@Override
public boolean equals(Object other) {
return other instanceof DominatorTreeNode && block==((DominatorTreeNode)other).block;
}
@Override
public String toString() {
return "\"D("+block.getId()+")\"";
}
}

View file

@ -0,0 +1,59 @@
package ch.usi.inf.sp.dom;
import ch.usi.inf.sp.cfg.BasicBlock;
import ch.usi.inf.sp.cfg.ControlFlowEdge;
import ch.usi.inf.sp.cfg.ControlFlowGraph;
public class DominatorTreeRenderer {
public static String renderDominatorTree(final String label, final DominatorTree tree) {
final StringBuffer sb = new StringBuffer();
sb.append("digraph dominatorTree {\n");
sb.append(" label=\"" + label + "\"\n");
for (final DominatorTreeNode node : tree.getNodes()) {
if (node == tree.getRoot()) {
sb.append(" " + node.toString() + " [style=filled]\n");
} else {
sb.append(" " + node.toString() + "\n");
}
}
for (final DominanceEdge edge : tree.getEdges()) {
sb.append(" " + edge.getFrom().toString() + " -> " + edge.getTo().toString()+"\n");
}
sb.append("}\n");
return sb.toString();
}
public static String renderCombined(final String label, final ControlFlowGraph cfg, final DominatorTree dt) {
final StringBuffer sb = new StringBuffer();
sb.append("digraph combined {\n");
sb.append(" label=\"" + label + "\"\n");
// render basic blocks
for (final BasicBlock block : cfg.getNodes()) {
if (block == cfg.getEntry()) {
sb.append(" " + block.getId() + " [shape=record,style=filled,label=\""+block.getId()+"|entry\"]\n");
} else if (block == cfg.getExit()) {
sb.append(" " + block.getId() + " [shape=record,label=\""+block.getId()+"|exit\"]\n");
} else {
sb.append(" " + block.getId() + " [shape=record,label=\""+block.getId()+"|{");
// use \l to tell dot to left-align each line
sb.append(String.join("\\l|", block.getInstructions()));
sb.append("\\l}\"]\n");
}
}
// render control flow edges (solid)
for (final ControlFlowEdge edge : cfg.getEdges()) {
sb.append(" " + edge.getFrom().getId() + " -> " + edge.getTo().getId());
sb.append(" [label=\"" + edge.getLabel() + "\"]\n");
}
// render dominance edges (dotted)
for (final DominanceEdge edge : dt.getEdges()) {
sb.append(" " + edge.getFrom().getBlock().getId() + " -> " + edge.getTo().getBlock().getId()+" [style=dotted]\n");
}
sb.append("}\n");
return sb.toString();
}
}

View file

@ -0,0 +1,69 @@
package ch.usi.inf.sp.graph;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class DiGraph<N extends Node<E>, E extends Edge<N>> {
private final ArrayList<N> nodes;
private final ArrayList<E> edges;
public DiGraph() {
nodes = new ArrayList<N>();
edges = new ArrayList<E>();
}
public void addNode(N node) {
nodes.add(node);
}
public void addEdge(E edge) {
edges.add(edge);
}
public void connect(N from, E edge, N to) {
if (!nodes.contains(from)) {
throw new IllegalStateException("Graph does not contain from node.");
}
if (!nodes.contains(to)) {
throw new IllegalStateException("Graph does not contain to node.");
}
if (!edges.contains(edge)) {
throw new IllegalStateException("Graph does not contain edge.");
}
if (from.getOutEdges().contains(edge)) {
throw new IllegalStateException("From node already has this edge as out edge");
}
if (to.getInEdges().contains(edge)) {
throw new IllegalStateException("To node already has this edge as in edge");
}
edge.setFrom(from);
edge.setTo(to);
from.addOutEdge(edge);
to.addInEdge(edge);
}
public List<E> getEdges() {
return Collections.unmodifiableList(edges);
}
public List<N> getNodes() {
return Collections.unmodifiableList(nodes);
}
public String toString() {
final StringBuffer sb = new StringBuffer("digraph G {\n");
for (final Node node : nodes) {
sb.append(" "+node+"\n");
}
for (final Edge edge : edges) {
sb.append(" "+edge+"\n");
}
sb.append("}\n");
return sb.toString();
}
}

View file

@ -0,0 +1,32 @@
package ch.usi.inf.sp.graph;
public class Edge<N extends Node> {
private N from;
private N to;
public Edge() {
}
public void setFrom(N node) {
from = node;
}
public N getFrom() {
return from;
}
public void setTo(N node) {
to = node;
}
public N getTo() {
return to;
}
public String toString() {
return from.toString()+" -> "+to.toString();
}
}

View file

@ -0,0 +1,38 @@
package ch.usi.inf.sp.graph;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Node<E extends Edge> {
private final ArrayList<E> inEdges;
private final ArrayList<E> outEdges;
public Node() {
inEdges = new ArrayList<E>();
outEdges = new ArrayList<E>();
}
public void addInEdge(E edge) {
inEdges.add(edge);
}
public void addOutEdge(E edge) {
outEdges.add(edge);
}
public List<E> getInEdges() {
return Collections.unmodifiableList(inEdges);