Initial commit
This commit is contained in:
commit
74a433f602
73 changed files with 2719 additions and 0 deletions
2
.idea/.gitignore
vendored
Normal file
2
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Default ignored files
|
||||
/workspace.xml
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
19
.idea/libraries/asm_util_7_1.xml
Normal file
19
.idea/libraries/asm_util_7_1.xml
Normal 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
10
.idea/misc.xml
Normal 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
8
.idea/modules.xml
Normal 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>
|
16
.idea/runConfigurations/App.xml
Normal file
16
.idea/runConfigurations/App.xml
Normal 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>
|
16
.idea/runConfigurations/Disassembler.xml
Normal file
16
.idea/runConfigurations/Disassembler.xml
Normal 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>
|
3
.idea/sonarlint/issuestore/index.pb
Normal file
3
.idea/sonarlint/issuestore/index.pb
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
9
|
||||
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d
|
124
.idea/uiDesigner.xml
Normal file
124
.idea/uiDesigner.xml
Normal 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
6
.idea/vcs.xml
Normal 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
34
README.md
Normal 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
BIN
lib/asm-7.1-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/asm-7.1-sources.jar
Normal file
BIN
lib/asm-7.1-sources.jar
Normal file
Binary file not shown.
BIN
lib/asm-7.1.jar
Normal file
BIN
lib/asm-7.1.jar
Normal file
Binary file not shown.
BIN
lib/asm-tree-7.1-javadoc.jar
Normal file
BIN
lib/asm-tree-7.1-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/asm-tree-7.1-sources.jar
Normal file
BIN
lib/asm-tree-7.1-sources.jar
Normal file
Binary file not shown.
BIN
lib/asm-tree-7.1.jar
Normal file
BIN
lib/asm-tree-7.1.jar
Normal file
Binary file not shown.
BIN
lib/asm-util-7.1-javadoc.jar
Normal file
BIN
lib/asm-util-7.1-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/asm-util-7.1-sources.jar
Normal file
BIN
lib/asm-util-7.1-sources.jar
Normal file
Binary file not shown.
BIN
lib/asm-util-7.1.jar
Normal file
BIN
lib/asm-util-7.1.jar
Normal file
Binary file not shown.
265
src/ch/usi/inf/sp/bytecode/Disassembler.java
Normal file
265
src/ch/usi/inf/sp/bytecode/Disassembler.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
99
src/ch/usi/inf/sp/cfg/App.java
Normal file
99
src/ch/usi/inf/sp/cfg/App.java
Normal 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));
|
||||
}
|
||||
|
||||
}
|
44
src/ch/usi/inf/sp/cfg/BasicBlock.java
Normal file
44
src/ch/usi/inf/sp/cfg/BasicBlock.java
Normal 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+"\"";
|
||||
}
|
||||
|
||||
}
|
19
src/ch/usi/inf/sp/cfg/ControlFlowEdge.java
Normal file
19
src/ch/usi/inf/sp/cfg/ControlFlowEdge.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
110
src/ch/usi/inf/sp/cfg/ControlFlowGraph.java
Normal file
110
src/ch/usi/inf/sp/cfg/ControlFlowGraph.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
23
src/ch/usi/inf/sp/cfg/ControlFlowGraphBuilder.java
Normal file
23
src/ch/usi/inf/sp/cfg/ControlFlowGraphBuilder.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
11
src/ch/usi/inf/sp/cfg/ControlFlowGraphRenderer.java
Normal file
11
src/ch/usi/inf/sp/cfg/ControlFlowGraphRenderer.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
8
src/ch/usi/inf/sp/dom/DominanceEdge.java
Normal file
8
src/ch/usi/inf/sp/dom/DominanceEdge.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package ch.usi.inf.sp.dom;
|
||||
|
||||
import ch.usi.inf.sp.graph.Edge;
|
||||
|
||||
|
||||
public class DominanceEdge extends Edge<DominatorTreeNode> {
|
||||
|
||||
}
|
52
src/ch/usi/inf/sp/dom/DominatorAnalyzer.java
Normal file
52
src/ch/usi/inf/sp/dom/DominatorAnalyzer.java
Normal 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(...)
|
||||
|
||||
}
|
80
src/ch/usi/inf/sp/dom/DominatorTree.java
Normal file
80
src/ch/usi/inf/sp/dom/DominatorTree.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
30
src/ch/usi/inf/sp/dom/DominatorTreeNode.java
Normal file
30
src/ch/usi/inf/sp/dom/DominatorTreeNode.java
Normal 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()+")\"";
|
||||
}
|
||||
|
||||
}
|
59
src/ch/usi/inf/sp/dom/DominatorTreeRenderer.java
Normal file
59
src/ch/usi/inf/sp/dom/DominatorTreeRenderer.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
69
src/ch/usi/inf/sp/graph/DiGraph.java
Normal file
69
src/ch/usi/inf/sp/graph/DiGraph.java
Normal 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();
|
||||
}
|
||||
}
|
32
src/ch/usi/inf/sp/graph/Edge.java
Normal file
32
src/ch/usi/inf/sp/graph/Edge.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
38
src/ch/usi/inf/sp/graph/Node.java
Normal file
38
src/ch/usi/inf/sp/graph/Node.java
Normal 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); |