Commit c71aace8 authored by Eric Bruneton's avatar Eric Bruneton

Improve the code quality of Edge.

parent 3f8159e0
......@@ -28,39 +28,57 @@
package org.objectweb.asm;
/**
* An edge in the control flow graph of a method body. See {@link Label Label}.
* An edge in the control flow graph of a method. Each node of this graph is a basic block,
* represented with the Label corresponding to its first instruction. Each edge goes from one node
* to another, i.e. from one basic block to another (called the predecessor and successor blocks,
* respectively). An edge corresponds either to a jump instruction or to an exception handler.
*
* @see Label
* @author Eric Bruneton
*/
class Edge {
final class Edge {
/** Denotes a normal control flow graph edge. */
static final int NORMAL = 0;
/**
* Denotes a control flow graph edge corresponding to a jump instruction. Only used with {@link
* ClassWriter#COMPUTE_FRAMES}.
*/
static final int JUMP = 0;
/**
* Denotes a control flow graph edge corresponding to an exception handler. More precisely any
* {@link Edge} whose {@link #info} is strictly positive corresponds to an exception handler. The
* actual value of {@link #info} is the index, in the {@link ClassWriter} type table, of the
* exception that is catched.
* Denotes a control flow graph edge corresponding to an exception handler. Only used with {@link
* ClassWriter#COMPUTE_MAXS}.
*/
static final int EXCEPTION = 0x7FFFFFFF;
/**
* Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used
* this field is the (relative) stack size in the basic block from which this edge originates.
* This size is equal to the stack size at the "jump" instruction to which this edge corresponds,
* relatively to the stack size at the beginning of the originating basic block. If {@link
* ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control flow graph edge
* (i.e. NORMAL or EXCEPTION).
* Information about this control flow graph edge.
*
* <ul>
* <li>If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size
* delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an
* edge corresponding to an exception handler). The stack size delta is the stack size just
* after the jump instruction, minus the stack size at the beginning of the predecessor
* basic block, i.e. the one containing the jump instruction.
* <li>If {@link ClassWriter#COMPUTE_FRAMES} is used, this field contains either the value JUMP
* (for an edge corresponding to a jump instruction), or the index, in the {@link
* ClassWriter} type table, of the exception type that is handled (for an edge corresponding
* to an exception handler).
* </ul>
*/
int info;
final int info;
/** The successor block of the basic block from which this edge originates. */
Label successor;
/** The successor block of this control flow graph edge. */
final Label successor;
/**
* The next edge in the list of successors of the originating basic block. See {@link
* Label#successors successors}.
* The next edge in the list of outgoing edges of a basic block. See {@link Label#outgoingEdges}.
*/
Edge next;
Edge nextEdge;
/** Creates a new Edge. */
Edge(final int info, final Label successor, final Edge nextEdge) {
this.info = info;
this.successor = successor;
this.nextEdge = nextEdge;
}
}
......@@ -47,9 +47,6 @@ public class Label {
/** Indicates if the position of this label is known. */
static final int RESOLVED = 2;
/** Indicates if this label has been updated, after instruction resizing. */
static final int RESIZED = 4;
/**
* Indicates if this basic block has been pushed in the basic block stack. See {@link
* MethodWriter#visitMaxs visitMaxs}.
......@@ -100,7 +97,6 @@ public class Label {
*
* @see #DEBUG
* @see #RESOLVED
* @see #RESIZED
* @see #PUSHED
* @see #TARGET
* @see #STORE
......@@ -202,10 +198,10 @@ public class Label {
Label successor;
/**
* The successors of this node in the control flow graph. These successors are stored in a linked
* list of {@link Edge Edge} objects, linked to each other by their {@link Edge#next} field.
* The outgoing edges of this control flow graph node. These edges are stored in a linked list of
* {@link Edge} objects, linked to each other by their {@link Edge#nextEdge} field.
*/
Edge successors;
Edge outgoingEdges;
/**
* The next basic block in the basic block stack. This stack is used in the main loop of the fix
......@@ -446,11 +442,8 @@ public class Label {
// adds JSR to the successors of l, if it is a RET block
if ((l.status & RET) != 0) {
if (!l.inSameSubroutine(JSR)) {
Edge e = new Edge();
e.info = l.inputStackTop;
e.successor = JSR.successors.successor;
e.next = l.successors;
l.successors = e;
l.outgoingEdges =
new Edge(l.inputStackTop, JSR.outgoingEdges.successor, l.outgoingEdges);
}
}
} else {
......@@ -462,19 +455,19 @@ public class Label {
l.addToSubroutine(id, nbSubroutines);
}
// pushes each successor of l on the stack, except JSR targets
Edge e = l.successors;
Edge e = l.outgoingEdges;
while (e != null) {
// if the l block is a JSR block, then 'l.successors.next' leads
// if the l block is a JSR block, then 'l.outgoingEdges.nextEdge' leads
// to the JSR target (see {@link #visitJumpInsn}) and must
// therefore not be followed
if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
if ((l.status & Label.JSR) == 0 || e != l.outgoingEdges.nextEdge) {
// pushes e.successor on the stack if it not already added
if (e.successor.next == null) {
e.successor.next = stack;
stack = e.successor;
}
}
e = e.next;
e = e.nextEdge;
}
}
}
......
......@@ -886,7 +886,7 @@ class MethodWriter extends MethodVisitor {
// 'label' is the target of a jump instruction
label.getFirst().status |= Label.TARGET;
// adds 'label' as a successor of this basic block
addSuccessor(Edge.NORMAL, label);
addSuccessor(Edge.JUMP, label);
if (opcode != Opcodes.GOTO) {
// creates a Label for the next basic block
nextInsn = new Label();
......@@ -995,7 +995,7 @@ class MethodWriter extends MethodVisitor {
return;
}
// ends current block (with one new successor)
addSuccessor(Edge.NORMAL, label);
addSuccessor(Edge.JUMP, label);
}
// begins a new current block
currentBlock = label;
......@@ -1142,10 +1142,10 @@ class MethodWriter extends MethodVisitor {
if (compute == FRAMES) {
currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
// adds current block successors
addSuccessor(Edge.NORMAL, dflt);
addSuccessor(Edge.JUMP, dflt);
dflt.getFirst().status |= Label.TARGET;
for (int i = 0; i < labels.length; ++i) {
addSuccessor(Edge.NORMAL, labels[i]);
addSuccessor(Edge.JUMP, labels[i]);
labels[i].getFirst().status |= Label.TARGET;
}
} else {
......@@ -1339,13 +1339,8 @@ class MethodWriter extends MethodVisitor {
h.status |= Label.TARGET;
// adds 'h' as a successor of labels between 'start' and 'end'
while (l != e) {
// creates an edge to 'h'
Edge b = new Edge();
b.info = kind;
b.successor = h;
// adds it to the successors of 'l'
b.next = l.successors;
l.successors = b;
// create an edge to 'h' and add it to the outgoing edges of l.
l.outgoingEdges = new Edge(kind, h, l.outgoingEdges);
// goes to the next label
l = l.successor;
}
......@@ -1383,7 +1378,7 @@ class MethodWriter extends MethodVisitor {
max = blockMax;
}
// updates the successors of the current basic block
Edge e = l.successors;
Edge e = l.outgoingEdges;
while (e != null) {
Label n = e.successor.getFirst();
boolean change = f.merge(cw, n.frame, e.info);
......@@ -1393,7 +1388,7 @@ class MethodWriter extends MethodVisitor {
n.next = changed;
changed = n;
}
e = e.next;
e = e.nextEdge;
}
}
......@@ -1446,20 +1441,15 @@ class MethodWriter extends MethodVisitor {
Label e = handler.end;
// adds 'h' as a successor of labels between 'start' and 'end'
while (l != e) {
// creates an edge to 'h'
Edge b = new Edge();
b.info = Edge.EXCEPTION;
b.successor = h;
// adds it to the successors of 'l'
// create an edge to 'h' and add it to the successors of 'l'
if ((l.status & Label.JSR) == 0) {
b.next = l.successors;
l.successors = b;
l.outgoingEdges = new Edge(Edge.EXCEPTION, h, l.outgoingEdges);
} else {
// if l is a JSR block, adds b after the first two edges
// to preserve the hypothesis about JSR block successors
// order (see {@link #visitJumpInsn})
b.next = l.successors.next.next;
l.successors.next.next = b;
l.outgoingEdges.nextEdge.nextEdge =
new Edge(Edge.EXCEPTION, h, l.outgoingEdges.nextEdge.nextEdge);
}
// goes to the next label
l = l.successor;
......@@ -1481,7 +1471,7 @@ class MethodWriter extends MethodVisitor {
while (l != null) {
if ((l.status & Label.JSR) != 0) {
// the subroutine is defined by l's TARGET, not by l
Label subroutine = l.successors.next.successor;
Label subroutine = l.outgoingEdges.nextEdge.successor;
// if this subroutine has not been visited yet...
if ((subroutine.status & Label.VISITED) == 0) {
// ...assigns it a new id and finds its basic blocks
......@@ -1501,7 +1491,7 @@ class MethodWriter extends MethodVisitor {
L = L.successor;
}
// the subroutine is defined by l's TARGET, not by l
Label subroutine = l.successors.next.successor;
Label subroutine = l.outgoingEdges.nextEdge.successor;
subroutine.visitSubroutine(l, 0, subroutines);
}
l = l.successor;
......@@ -1532,10 +1522,10 @@ class MethodWriter extends MethodVisitor {
max = blockMax;
}
// analyzes the successors of the block
Edge b = l.successors;
Edge b = l.outgoingEdges;
if ((l.status & Label.JSR) != 0) {
// ignores the first edge of JSR blocks (virtual successor)
b = b.next;
b = b.nextEdge;
}
while (b != null) {
l = b.successor;
......@@ -1548,7 +1538,7 @@ class MethodWriter extends MethodVisitor {
l.next = stack;
stack = l;
}
b = b.next;
b = b.nextEdge;
}
}
this.maxStack = Math.max(maxStack, max);
......@@ -1572,13 +1562,8 @@ class MethodWriter extends MethodVisitor {
* @param successor the successor block to be added to the current block.
*/
private void addSuccessor(final int info, final Label successor) {
// creates and initializes an Edge object...
Edge b = new Edge();
b.info = info;
b.successor = successor;
// ...and adds it to the successor list of the currentBlock block
b.next = currentBlock.successors;
currentBlock.successors = b;
// add a new edge to the outgoing edges of currentBlock
currentBlock.outgoingEdges = new Edge(info, successor, currentBlock.outgoingEdges);
}
/**
......
......@@ -31,8 +31,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
......@@ -51,14 +49,6 @@ import org.junit.Test;
*/
public class ClassWriterComputeMaxsUnitTest {
private Field successors;
private Field successor;
private Field succ;
private Field next;
protected ClassWriter cw;
protected MethodVisitor mv;
......@@ -67,29 +57,6 @@ public class ClassWriterComputeMaxsUnitTest {
@Before
public void setUp() throws Exception {
Class<?> lClass = Label.class;
Class<?> eClass = Edge.class;
try {
successors = lClass.getDeclaredField("successors");
successor = lClass.getDeclaredField("successor");
succ = eClass.getDeclaredField("successor");
next = eClass.getDeclaredField("next");
} catch (RuntimeException exception) {
String f = "src/org/objectweb/asm/optimizer/shrink.properties";
Properties p = new Properties();
FileInputStream is = new FileInputStream(f);
try {
p.load(is);
} finally {
is.close();
}
String l = Type.getInternalName(lClass) + ".";
String e = Type.getInternalName(eClass) + ".";
successors = lClass.getDeclaredField(p.getProperty(l + "successors"));
successor = lClass.getDeclaredField(p.getProperty(l + "successor"));
succ = eClass.getDeclaredField(p.getProperty(e + "successor"));
next = eClass.getDeclaredField(p.getProperty(e + "next"));
}
cw = new ClassWriter(isComputeMaxs() ? ClassWriter.COMPUTE_MAXS : 0);
cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null);
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
......@@ -242,21 +209,17 @@ public class ClassWriterComputeMaxsUnitTest {
}
Map<String, Set<String>> actual = new HashMap<String, Set<String>>();
try {
Label l = start;
while (l != null) {
String key = "N" + l.getOffset();
Set<String> value = new HashSet<String>();
Edge e = (Edge) successors.get(l);
while (e != null) {
value.add("N" + ((Label) succ.get(e)).getOffset());
e = (Edge) next.get(e);
}
actual.put(key, value);
l = (Label) successor.get(l);
Label l = start;
while (l != null) {
String key = "N" + l.getOffset();
Set<String> value = new HashSet<String>();
Edge e = l.outgoingEdges;
while (e != null) {
value.add("N" + e.successor.getOffset());
e = e.nextEdge;
}
} catch (IllegalAccessException e) {
fail();
actual.put(key, value);
l = l.successor;
}
assertEquals(expected, actual);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment