/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package EDU.purdue.cs.bloat.tree;
import java.util.*;
import EDU.purdue.cs.bloat.cfg.*;
import EDU.purdue.cs.bloat.editor.*;
import EDU.purdue.cs.bloat.reflect.*;
import EDU.purdue.cs.bloat.util.*;
/**
* Tree represents the expression tree of a basic Block. It consists of an
* operand (expression) stack comprised of expressions and a list of statements
* contained in the block.
*
* @see Block
* @see Expr
* @see OperandStack
* @see Stmt see StmtList
*/
public class Tree extends Node implements InstructionVisitor, Opcode {
public static boolean DEBUG = false;
public static boolean FLATTEN = false;
public static boolean USE_STACK = true; // Do we use stack vars?
public static boolean AUPDATE_FIX_HACK = false;
public static boolean AUPDATE_FIX_HACK_CHANGED = false;
public static boolean USE_PERSISTENT = false; // Insert UCExpr by default
Block block; // Block that is represented by this Tree
Subroutine sub; // The Subroutine that we're currently in
Block next; // The Block after this one
OperandStack stack; // The program stack for this block
StmtList stmts; // The statements in the basic block
Stack savedStack;
static int stackpos = 0;
boolean saveValue; // Do we push a StoreExpr on operand stack?
// Some dup instruction combinations cause saveStack to generate
// temporaries that clobber other temporaries. So, we use nextindex
// to ensure that a uniquely-name temporary is created by
// saveStack. Yes, this will introduce a lot of new temporaries,
// but expression propagation should eliminate a lot of them.
private int nextIndex = 0;
private void db(final String s) {
if (Tree.DEBUG) {
System.out.println(s);
}
}
/**
* Constructor.
*
* @param block
* The basic Block of code represented in this Tree.
* @param predStack
* The contents of the operand stack from the previous basic
* Block.
*/
public Tree(final Block block, final OperandStack predStack) {
this.block = block;
if (Tree.DEBUG) {
System.out.println(" new tree for " + block);
}
stack = new OperandStack();
stmts = new StmtList();
// The first statement in the Tree is the label indicating the start
// of the basic Block.
appendStmt(new LabelStmt(block.label()));
// Make a copy of predStack
for (int i = 0; i < predStack.size(); i++) {
final Expr expr = predStack.get(i);
final Expr copy = (Expr) expr.clone();
copy.setDef(null);
stack.push(copy);
}
}
/**
* Cleans up this node. Does nothing in this case.
*/
public void cleanupOnly() {
}
/**
* Add a Collection of local variables to the block. Add an InitStmt to the
* statement list.
*
* @see LocalExpr
* @see InitStmt
*/
public void initLocals(final Collection locals) {
final LocalExpr[] t = new LocalExpr[locals.size()];
if (t.length == 0) {
return;
}
final Iterator iter = locals.iterator();
for (int i = 0; iter.hasNext(); i++) {
t[i] = (LocalExpr) iter.next();
}
addStmt(new InitStmt(t));
}
/**
* Removes a statement from the statement list.
*
* @param stmt
* The statement to remove
*/
public void removeStmt(final Stmt stmt) {
stmts.remove(stmt);
}
/**
* Removes the last non-Label statement from the statement list.
*/
public void removeLastStmt() {
final ListIterator iter = stmts.listIterator(stmts.size());
while (iter.hasPrevious()) {
final Stmt s = (Stmt) iter.previous();
if (s instanceof LabelStmt) {
continue;
}
iter.remove();
return;
}
}
/**
* @return The statement list
*/
public List stmts() {
return stmts;
}
/**
* StmtList is a linked list of statements. A number of methods are
* overridden because some adjustments may need to be made to the Nodes in
* the tree when certain operations are performed.
*/
class StmtList extends LinkedList {
/**
* Clear the contents of this statement list.
*/
public void clear() {
final Iterator iter = iterator();
while (iter.hasNext()) {
((Stmt) iter.next()).cleanup();
}
super.clear();
}
/**
* Remove a statement from the list and clean up afterwards.
*/
public boolean remove(final Object o) {
if (super.remove(o)) {
((Stmt) o).cleanup();
return true;
}
return false;
}
/**
* Remove all of the statements in a Collection from this statement
* list.
*
* @param c
* A Collection containing the statements to remove.
* @return True, if the contents of this statement list changed.
*/
public boolean removeAll(final Collection c) {
boolean changed = false;
if (c == this) {
changed = size() > 0;
clear();
} else {
final Iterator iter = c.iterator();
while (iter.hasNext()) {
changed = remove(iter.next()) || changed;
}
}
return changed;
}
/**
* Remove all statements in this list except those that are in a
* specified Collection.
*
* @param c
* The statements to keep.
* @return True, if the contents of this statement list changed.
*/
public boolean retainAll(final Collection c) {
boolean changed = false;
if (c == this) {
return false;
}
final Iterator iter = iterator();
while (iter.hasNext()) {
if (!c.contains(iter.next())) {
changed = true;
iter.remove();
}
}
return changed;
}
/**
* Set the value of a given statement.
*
* @param index
* Index of the statement to change.
* @param element
* New value of statement at index.
*
* @return Statement previously at position index.
*/
public Object set(final int index, final Object element) {
if (index < size()) {
final Stmt s = (Stmt) get(index);
if (s != element) {
s.cleanup();
}
}
return super.set(index, element);
}
/**
* Removes the statement at index
*
* @return Statement previously at position index.
*/
public Object remove(final int index) {
final Object o = super.remove(index);
if (o != null) {
((Stmt) o).cleanup();
}
return o;
}
/**
* Removes statements in a given index range.
*/
/*
* public void removeRange(int fromIndex, int toIndex) { int remaining =
* toIndex - fromIndex;
*
* ListIterator iter = listIterator(fromIndex);
*
* while (iter.hasNext() && remaining-- > 0) { ((Stmt)
* iter.next()).cleanup(); }
*
* super.removeRange(fromIndex, toIndex); }
*/
/**
* @return A ListIterator starting with the first statement in the
* statement list.
*/
public ListIterator listIterator() {
return listIterator(0);
}
/**
* @return A ListIterator starting a given index.
*/
public ListIterator listIterator(final int index) {
final ListIterator iter = super.listIterator(index);
return new ListIterator() {
Object last = null;
public boolean hasNext() {
return iter.hasNext();
}
public Object next() {
last = iter.next();
return last;
}
public boolean hasPrevious() {
return iter.hasPrevious();
}
public Object previous() {
last = iter.previous();
return last;
}
public int nextIndex() {
return iter.nextIndex();
}
public int previousIndex() {
return iter.previousIndex();
}
public void add(final Object obj) {
Assert.isTrue(obj instanceof Stmt);
((Stmt) obj).setParent(Tree.this);
last = null;
iter.add(obj);
}
public void set(final Object obj) {
if (last == null) {
throw new NoSuchElementException();
}
Assert.isTrue(obj instanceof Stmt);
((Stmt) obj).setParent(Tree.this);
((Stmt) last).cleanup();
last = null;
iter.set(obj);
}
public void remove() {
if (last == null) {
throw new NoSuchElementException();
}
((Stmt) last).cleanup();
last = null;
iter.remove();
}
};
}
/**
* @return An Iterator over this statement list.
*/
public Iterator iterator() {
final Iterator iter = super.iterator();
return new Iterator() {
Object last = null;
public boolean hasNext() {
return iter.hasNext();
}
public Object next() {
last = iter.next();
return last;
}
public void remove() {
if (last == null) {
throw new NoSuchElementException();
}
((Stmt) last).cleanup();
last = null;
iter.remove();
}
};
}
}
/**
* Returns the last non-Label statement in the statement list.
*/
public Stmt lastStmt() {
final ListIterator iter = stmts.listIterator(stmts.size());
while (iter.hasPrevious()) {
final Stmt s = (Stmt) iter.previous();
if (s instanceof LabelStmt) {
continue;
}
return s;
}
return null;
}
/**
* Returns the operand stack.
*/
public OperandStack stack() {
return stack;
}
/**
* Inserts a statement into the statement list after another given
* statement.
*
* @param stmt
* The statement to add.
* @param after
* The statement after which to add stmt.
*/
public void addStmtAfter(final Stmt stmt, final Stmt after) {
if (Tree.DEBUG) {
System.out.println("insert: " + stmt + " after " + after);
}
final ListIterator iter = stmts.listIterator();
while (iter.hasNext()) {
final Stmt s = (Stmt) iter.next();
if (s == after) {
iter.add(stmt);
stmt.setParent(this);
return;
}
}
throw new RuntimeException(after + " not found");
}
/**
* Inserts a statement into the statement list before a specified statement.
*
* @param stmt
* The statement to insert
* @param before
* The statement before which to add stmt.
*/
public void addStmtBefore(final Stmt stmt, final Stmt before) {
if (Tree.DEBUG) {
System.out.println("insert: " + stmt + " before " + before);
}
final ListIterator iter = stmts.listIterator();
while (iter.hasNext()) {
final Stmt s = (Stmt) iter.next();
if (s == before) {
iter.previous();
iter.add(stmt);
stmt.setParent(this);
return;
}
}
throw new RuntimeException(before + " not found");
}
/**
* Add an statement to the statement list before the first non-Label
* statement.
*
* @param stmt
* The statement to add.
*/
public void prependStmt(final Stmt stmt) {
if (Tree.DEBUG) {
System.out.println("prepend: " + stmt + " in " + block);
}
final ListIterator iter = stmts.listIterator();
while (iter.hasNext()) {
final Stmt s = (Stmt) iter.next();
if (!(s instanceof LabelStmt)) {
iter.previous();
iter.add(stmt);
stmt.setParent(this);
return;
}
}
appendStmt(stmt);
}
/**
* When we build the expression tree, there may be items left over on the
* operand stack. We want to save these items. If USE_STACK is true, then we
* place these items into stack variables. If USE_STACK is false, then we
* place the items into local variables.
*/
private void saveStack() {
int height = 0;
for (int i = 0; i < stack.size(); i++) {
final Expr expr = stack.get(i);
if (Tree.USE_STACK) {
// Save to a stack variable only if we'll create a new
// variable there.
if (!(expr instanceof StackExpr)
|| (((StackExpr) expr).index() != height)) {
final StackExpr target = new StackExpr(height, expr.type());
// Make a new statement to store the expression that was
// part of the stack into memory.
final Stmt store = new ExprStmt(new StoreExpr(target, expr,
expr.type()));
appendStmt(store);
final StackExpr copy = (StackExpr) target.clone();
copy.setDef(null);
stack.set(i, copy);
}
} else {
if (!(expr instanceof LocalExpr)
|| !((LocalExpr) expr).fromStack()
|| (((LocalExpr) expr).index() != height)) {
final LocalExpr target = newStackLocal(nextIndex++, expr
.type());
final Stmt store = new ExprStmt(new StoreExpr(target, expr,
expr.type()));
appendStmt(store);
final LocalExpr copy = (LocalExpr) target.clone();
copy.setDef(null);
stack.set(i, copy);
}
}
height += expr.type().stackHeight();
}
}
/**
* Add a statement to this Tree statement list and specify that this is the
* statement's parent.
*/
private void appendStmt(final Stmt stmt) {
if (Tree.DEBUG) {
System.out.println(" append: " + stmt);
}
stmt.setParent(this);
stmts.add(stmt);
}
/**
* Save the contents of the stack and add stmt to the statement list.
*
* @param stmt
* A statement to add to the statement list.
*/
public void addStmt(final Stmt stmt) {
saveStack();
appendStmt(stmt);
}
/**
* Adds a statement to the statement list before the last jump statement. It
* is assumed that the last statement in the statement list is a jump
* statement.
*
* @see JumpStmt
*/
public void addStmtBeforeJump(final Stmt stmt) {
final Stmt last = lastStmt();
Assert.isTrue(last instanceof JumpStmt, "Last statement of " + block
+ " is " + last + ", not a jump");
addStmtBefore(stmt, last);
}
/**
* Throw a new ClassFormatException with information about method and class
* that this basic block is in.
*
* @param msg
* String description of the exception.
*
* @see ClassFormatException
*/
private void throwClassFormatException(final String msg) {
final MethodEditor method = block.graph().method();
throw new ClassFormatException("Method "
+ method.declaringClass().type().className() + "."
+ method.name() + " " + method.type() + ": " + msg);
}
/**
* The last instruction we saw. addInst(Instruction) needs this information.
*/
Instruction last = null;
/**
* Adds an instruction that jumps to another basic block.
*
* @param inst
* The instruction to add.
* @param next
* The basic block after the jump. Remember that a jump ends a
* basic block.
*
* @see Instruction#isJsr
* @see Instruction#isConditionalJump
*/
public void addInstruction(final Instruction inst, final Block next) {
Assert.isTrue(inst.isJsr() || inst.isConditionalJump(),
"Wrong addInstruction called with " + inst);
Assert.isTrue(next != null, "Null next block for " + inst);
this.next = next;
addInst(inst);
}
/**
* Adds an instruction that does not change the control flow (a normal
* instruction).
*
* @param inst
* Instruction to add.
*/
public void addInstruction(final Instruction inst) {
Assert.isTrue(!inst.isJsr() && !inst.isConditionalJump(),
"Wrong addInstruction called with " + inst);
this.next = null;
addInst(inst);
}
/**
* Add an instruction such as <i>ret</i> or <i>astore</i> that may involve
* a subroutine.
*
* @param inst
* Instruction to add.
* @param sub
* Subroutine in which inst resides. The <i>ret</i> instruction
* always resides in a Subroutine. An <i>astore</i> may store
* the return address of a subroutine in a local variable.
*
* @see Instruction#isRet
*/
public void addInstruction(final Instruction inst, final Subroutine sub) {
Assert.isTrue(inst.isRet()
|| (inst.opcodeClass() == Opcode.opcx_astore),
"Wrong addInstruction called with " + inst);
this.sub = sub;
this.next = null;
addInst(inst);
}
/**
* Add a label to the statement list. A label is inserted before a dup
* statement, but after any other statement.
*
* @param label
* Label to add.
*/
public void addLabel(final Label label) {
// Add before a dup, but after any other instruction.
if (last != null) {
switch (last.opcodeClass()) {
case opcx_dup:
case opcx_dup2:
case opcx_dup_x1:
case opcx_dup2_x1:
case opcx_dup_x2:
case opcx_dup2_x2:
break;
default:
addInst(last, false);
last = null;
break;
}
}
addStmt(new LabelStmt(label));
}
/**
* Private method that adds an instruction to the Tree. The visit method of
* the instruction is called with this tree as the visitor. The instruction,
* in turn, calls the appropriate method of this for adding the instruction
* to the statement list.
*
* @param inst
* The <tt>Instruction</tt> to add to the <tt>Tree</tt>
* @param saveValue
* Do we save expressions on the operand stack to stack variables
* or local variables.
*/
private void addInst(final Instruction inst, final boolean saveValue) {
if (Tree.DEBUG) {
// Print the contents of the stack
for (int i = 0; i < stack.size(); i++) {
final Expr exp = stack.peek(i);
System.out.println((i > 0 ? "-" + i : " " + i) + ": " + exp);
}
}
if (Tree.DEBUG) {
System.out.println(" add " + inst + " save=" + saveValue);
}
try {
this.saveValue = saveValue;
if (Tree.FLATTEN) {
saveStack();
}
inst.visit(this);
} catch (final EmptyStackException e) {
throwClassFormatException("Empty operand stack at " + inst);
return;
}
}
/**
* Private method that adds an instruction to the tree. Before dispatching
* the addition off to addInst(Instruction, boolean), it optimizes(?) dup
* instructions as outlined below:
*/
// (S0, S1) := dup(X)
// L := S1 --> use (L := X)
// use S0
//
// (S0, S1, S2) := dup_x1(X, Y)
// S1.f := S2 --> use (X.f := Y)
// use S0
//
// (S0, S1, S2, S3) := dup_x2(X, Y, Z)
// S1[S2] := S3 --> use (X[Y] := Z)
// use S0
//
private void addInst(final Instruction inst) {
// Build the tree, trying to convert dup-stores
if (last == null) {
last = inst;
} else {
switch (last.opcodeClass()) {
case opcx_dup:
switch (inst.opcodeClass()) {
case opcx_astore:
case opcx_fstore:
case opcx_istore:
case opcx_putstatic:
addInst(inst, true);
last = null;
break;
}
break;
case opcx_dup2:
switch (inst.opcodeClass()) {
case opcx_dstore:
case opcx_lstore:
case opcx_putstatic:
addInst(inst, true);
last = null;
break;
}
break;
case opcx_dup_x1:
switch (inst.opcodeClass()) {
case opcx_putfield:
case opcx_putfield_nowb:
addInst(inst, true);
last = null;
break;
}
break;
case opcx_dup2_x1:
switch (inst.opcodeClass()) {
case opcx_putfield:
case opcx_putfield_nowb:
addInst(inst, true);
last = null;
break;
}
break;
case opcx_dup_x2:
switch (inst.opcodeClass()) {
case opcx_aastore:
case opcx_bastore:
case opcx_castore:
case opcx_fastore:
case opcx_iastore:
case opcx_sastore:
addInst(inst, true);
last = null;
break;
}
break;
case opcx_dup2_x2:
switch (inst.opcodeClass()) {
case opcx_dastore:
case opcx_lastore:
addInst(inst, true);
last = null;
break;
}
break;
}
if (last != null) {
addInst(last, false);
last = inst;
}
}
// We should have dealt with the old last instruction
Assert.isTrue((last == null) || (last == inst));
if (inst.isJump() || inst.isSwitch() || inst.isThrow()
|| inst.isReturn() || inst.isJsr() || inst.isRet()) {
addInst(inst, false);
last = null;
}
}
/**
* Returns a new StackExpr for the top of the operand stack.
*/
public StackExpr newStack(final Type type) {
return new StackExpr(Tree.stackpos++, type);
}
/**
* Returns a new LocalExpr that represents an element of the stack. They are
* created when the USE_STACK flag is not set.
*
* @param index
* Stack index of variable.
* @param type
* The type of the LocalExpr
*/
public LocalExpr newStackLocal(final int index, final Type type) {
if (index >= nextIndex) {
nextIndex = index + 1;
}
return new LocalExpr(index, true, type);
}
/**
* Returns a new LocalExpr that is not allocated on the stack.
*
* @param index
* Stack index of variable.
* @param type
* The type of the LocalExpr
*/
public LocalExpr newLocal(final int index, final Type type) {
return new LocalExpr(index, false, type);
}
/**
* Returns a local variable (<tt>LocalExpr</tt>) located in this method.
*
* @param type
* The type of the new LocalExpr.
*/
public LocalExpr newLocal(final Type type) {
final LocalVariable var = block.graph().method().newLocal(type);
return new LocalExpr(var.index(), type);
}
/**
* Returns a String representation of this Tree.
*/
public String toString() {
String x = "(TREE " + block + " stack=";
for (int i = 0; i < stack.size(); i++) {
final Expr expr = stack.get(i);
x += expr.type().shortName();
}
return x + ")";
}
/**
* Adds no statements to the statement list.
*/
public void visit_nop(final Instruction inst) {
}
/**
* Pushes a ConstantExpr onto the operand stack.
*
* @see ConstantExpr
*/
public void visit_ldc(final Instruction inst) {
final Object value = inst.operand();
Type type;
if (value == null) {
type = Type.NULL;
} else if (value instanceof Integer) {
type = Type.INTEGER;
} else if (value instanceof Long) {
type = Type.LONG;
} else if (value instanceof Float) {
type = Type.FLOAT;
} else if (value instanceof Double) {
type = Type.DOUBLE;
} else if (value instanceof String) {
type = Type.STRING;
}
// FIXME this won't work - check usages
else if (value instanceof Type) {
type = Type.CLASS;
} else {
throwClassFormatException("Illegal constant type: "
+ value.getClass().getName() + ": " + value);
return;
}
final Expr top = new ConstantExpr(value, type);
stack.push(top);
}
/**
* All <tt>visit_<i>x</i>load</tt> push a LocalExpr onto the operand
* stack.
*
* @see LocalExpr
*/
public void visit_iload(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr top = new LocalExpr(operand.index(), Type.INTEGER);
stack.push(top);
}
public void visit_lload(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr top = new LocalExpr(operand.index(), Type.LONG);
stack.push(top);
}
public void visit_fload(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr top = new LocalExpr(operand.index(), Type.FLOAT);
stack.push(top);
}
public void visit_dload(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr top = new LocalExpr(operand.index(), Type.DOUBLE);
stack.push(top);
}
public void visit_aload(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr top = new LocalExpr(operand.index(), Type.OBJECT);
stack.push(top);
db(" aload: " + top);
}
/**
* All <tt>visit_<i>x</i>aload</tt> push an ArrayRefExpr onto the
* operand stack.
*/
public void visit_iaload(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.INTEGER.arrayType());
final Expr top = new ArrayRefExpr(array, index, Type.INTEGER,
Type.INTEGER);
stack.push(top);
}
public void visit_laload(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.LONG.arrayType());
final Expr top = new ArrayRefExpr(array, index, Type.LONG, Type.LONG);
stack.push(top);
}
public void visit_faload(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.FLOAT.arrayType());
final Expr top = new ArrayRefExpr(array, index, Type.FLOAT, Type.FLOAT);
stack.push(top);
}
public void visit_daload(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.DOUBLE.arrayType());
final Expr top = new ArrayRefExpr(array, index, Type.DOUBLE,
Type.DOUBLE);
stack.push(top);
}
public void visit_aaload(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.OBJECT.arrayType());
final Expr top = new ArrayRefExpr(array, index, Type.OBJECT,
Type.OBJECT);
stack.push(top);
}
public void visit_baload(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.BYTE.arrayType());
final Expr top = new ArrayRefExpr(array, index, Type.BYTE, Type.BYTE);
stack.push(top);
}
public void visit_caload(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.CHARACTER.arrayType());
final Expr top = new ArrayRefExpr(array, index, Type.CHARACTER,
Type.CHARACTER);
stack.push(top);
}
public void visit_saload(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.SHORT.arrayType());
final Expr top = new ArrayRefExpr(array, index, Type.SHORT, Type.SHORT);
stack.push(top);
}
/**
* Deals with an expression that stores a value. It either pushes it on the
* operand stack or adds a statement depending on the value of saveValue.
*
* @param target
* The location to where we are storing the value.
* @param expr
* The expression whose value we are storing.
*/
private void addStore(final MemExpr target, final Expr expr) {
if (saveValue) {
stack.push(new StoreExpr(target, expr, expr.type()));
} else {
addStmt(new ExprStmt(new StoreExpr(target, expr, expr.type())));
}
}
/**
* All <tt>visit_<i>x</i>store</tt> add a LocalExpr statement to the
* statement list.
*/
public void visit_istore(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr expr = stack.pop(Type.INTEGER);
final LocalExpr target = new LocalExpr(operand.index(), expr.type());
addStore(target, expr);
}
public void visit_lstore(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr expr = stack.pop(Type.LONG);
final LocalExpr target = new LocalExpr(operand.index(), expr.type());
addStore(target, expr);
}
public void visit_fstore(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr expr = stack.pop(Type.FLOAT);
final LocalExpr target = new LocalExpr(operand.index(), expr.type());
addStore(target, expr);
}
public void visit_dstore(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
final Expr expr = stack.pop(Type.DOUBLE);
final LocalExpr target = new LocalExpr(operand.index(), expr.type());
addStore(target, expr);
}
/**
* Visit an <i>astore</i> instruction. If the type of the operand to the
* instruction is an address add an AddressStoreStmt to the tree, else add a
* StoreStmt to the tree consisting of a LocalExpr and the top Expr on the
* operand stack.
*
* @see AddressStoreStmt
* @see LocalExpr
* @see StoreExpr
*/
public void visit_astore(final Instruction inst) {
final LocalVariable operand = (LocalVariable) inst.operand();
Expr expr = stack.peek();
if (expr.type().isAddress()) {
Assert.isTrue(sub != null);
Assert.isTrue(!saveValue);
expr = stack.pop(Type.ADDRESS);
sub.setReturnAddress(operand);
addStmt(new AddressStoreStmt(sub));
} else {
expr = stack.pop(Type.OBJECT);
final LocalExpr target = new LocalExpr(operand.index(), expr.type());
addStore(target, expr);
}
}
public void visit_iastore(final Instruction inst) {
final Expr value = stack.pop(Type.INTEGER);
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.INTEGER.arrayType());
final ArrayRefExpr target = new ArrayRefExpr(array, index,
Type.INTEGER, Type.INTEGER);
addStore(target, value);
}
public void visit_lastore(final Instruction inst) {
final Expr value = stack.pop(Type.LONG);
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.LONG.arrayType());
final ArrayRefExpr target = new ArrayRefExpr(array, index, Type.LONG,
Type.LONG);
addStore(target, value);
}
public void visit_fastore(final Instruction inst) {
final Expr value = stack.pop(Type.FLOAT);
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.FLOAT.arrayType());
final ArrayRefExpr target = new ArrayRefExpr(array, index, Type.FLOAT,
Type.FLOAT);
addStore(target, value);
}
public void visit_dastore(final Instruction inst) {
final Expr value = stack.pop(Type.DOUBLE);
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.DOUBLE.arrayType());
final ArrayRefExpr target = new ArrayRefExpr(array, index, Type.DOUBLE,
Type.DOUBLE);
addStore(target, value);
}
public void visit_aastore(final Instruction inst) {
final Expr value = stack.pop(Type.OBJECT);
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.OBJECT.arrayType());
final ArrayRefExpr target = new ArrayRefExpr(array, index, Type.OBJECT,
Type.OBJECT);
addStore(target, value);
}
public void visit_bastore(final Instruction inst) {
final Expr value = stack.pop(Type.BYTE);
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.BYTE.arrayType());
final ArrayRefExpr target = new ArrayRefExpr(array, index, Type.BYTE,
Type.BYTE);
addStore(target, value);
}
public void visit_castore(final Instruction inst) {
final Expr value = stack.pop(Type.CHARACTER);
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.CHARACTER.arrayType());
final ArrayRefExpr target = new ArrayRefExpr(array, index,
Type.CHARACTER, Type.CHARACTER);
addStore(target, value);
}
public void visit_sastore(final Instruction inst) {
final Expr value = stack.pop(Type.SHORT);
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.SHORT.arrayType());
final ArrayRefExpr target = new ArrayRefExpr(array, index, Type.SHORT,
Type.SHORT);
addStore(target, value);
}
/**
* Pop the expression off the top of the stack and add it as an ExprStmt to
* the statement list.
*
* @see ExprStmt
*/
public void visit_pop(final Instruction inst) {
final Expr expr = stack.pop1();
addStmt(new ExprStmt(expr));
}
public void visit_pop2(final Instruction inst) {
final Expr[] expr = stack.pop2();
if (expr.length == 1) {
addStmt(new ExprStmt(expr[0]));
} else {
addStmt(new ExprStmt(expr[0]));
addStmt(new ExprStmt(expr[1]));
}
}
/**
* When processing the <i>dup</i> instructions one of two situations can
* occur. If the <tt>USE_STACK</tt> flag is set, then a StackManipStmt is
* created to represent the transformation that the <i>dup</i> instruction
* performs on the stack. If the <tt>USE_STACK</tt> flag is not set, then
* the transformation is simulated by creating new local variables
* containing the appropriate element of the stack.
*
* @see LocalExpr
* @see StackExpr
* @see StackManipStmt
*/
public void visit_dup(final Instruction inst) {
// 0 -> 0 0
db(" dup");
if (Tree.USE_STACK) {
saveStack();
final StackExpr s0 = (StackExpr) stack.pop1();
final StackExpr[] s = new StackExpr[] { s0 };
manip(s, new int[] { 0, 0 }, StackManipStmt.DUP);
} else {
final Expr s0 = stack.pop1();
final LocalExpr t0 = newStackLocal(stack.height(), s0.type());
db(" s0: " + s0);
db(" t0: " + t0);
if (!t0.equalsExpr(s0)) {
db(" t0 <- s0");
addStore(t0, s0);
}
Expr copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
}
}
public void visit_dup_x1(final Instruction inst) {
// 0 1 -> 1 0 1
if (Tree.USE_STACK) {
saveStack();
final StackExpr s1 = (StackExpr) stack.pop1();
final StackExpr s0 = (StackExpr) stack.pop1();
final StackExpr[] s = new StackExpr[] { s0, s1 };
manip(s, new int[] { 1, 0, 1 }, StackManipStmt.DUP_X1);
} else {
final Expr s1 = stack.pop1();
final Expr s0 = stack.pop1();
final LocalExpr t0 = newStackLocal(stack.height(), s0.type());
final LocalExpr t1 = newStackLocal(stack.height() + 1, s1.type());
if (!t0.equalsExpr(s0)) {
addStore(t0, s0);
}
if (!t1.equalsExpr(s1)) {
addStore(t1, s1);
}
Expr copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
}
}
public void visit_dup_x2(final Instruction inst) {
// 0 1 2 -> 2 0 1 2
// 0-1 2 -> 2 0-1 2
db(" dup_x2");
if (Tree.USE_STACK) {
saveStack();
final StackExpr s2 = (StackExpr) stack.pop1();
final Expr[] s01 = stack.pop2();
if (s01.length == 2) {
// 0 1 2 -> 2 0 1 2
final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0],
(StackExpr) s01[1], s2 };
manip(s, new int[] { 2, 0, 1, 2 }, StackManipStmt.DUP_X2);
} else {
// 0-1 2 -> 2 0-1 2
final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0], s2 };
manip(s, new int[] { 1, 0, 1 }, StackManipStmt.DUP_X2);
}
} else {
final Expr s2 = stack.pop1();
final Expr[] s01 = stack.pop2();
db(" s2: " + s2);
db(" s01: " + s01[0] + (s01.length > 1 ? " " + s01[1] : ""));
if (s01.length == 2) {
// 0 1 2 -> 2 0 1 2
final LocalExpr t0 = newStackLocal(stack.height(), s01[0]
.type());
final LocalExpr t1 = newStackLocal(stack.height() + 1, s01[1]
.type());
final LocalExpr t2 = newStackLocal(stack.height() + 2, s2
.type());
db(" t0: " + t0);
db(" t1: " + t1);
db(" t2: " + t2);
if (!t0.equalsExpr(s01[0])) {
db(" t0 <- s01[0]");
addStore(t0, s01[0]);
}
if (!t1.equalsExpr(s01[1])) {
db(" t1 <- s01[1]");
addStore(t1, s01[1]);
}
if (!t2.equalsExpr(s2)) {
db(" t2 <- s2");
addStore(t2, s2);
}
Expr copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
} else {
// 0-1 2 -> 2 0-1 2
final LocalExpr t0 = newStackLocal(stack.height(), s01[0]
.type());
final LocalExpr t2 = newStackLocal(stack.height() + 2, s2
.type());
if (!t0.equalsExpr(s01[0])) {
addStore(t0, s01[0]);
}
if (!t2.equalsExpr(s2)) {
addStore(t2, s2);
}
Expr copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
}
}
}
public void visit_dup2(final Instruction inst) {
// 0 1 -> 0 1 0 1
// 0-1 -> 0-1 0-1
if (Tree.USE_STACK) {
saveStack();
final Expr[] s01 = stack.pop2();
if (s01.length == 1) {
// 0-1 -> 0-1 0-1
final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0] };
manip(s, new int[] { 0, 0 }, StackManipStmt.DUP2);
} else {
// 0 1 -> 0 1 0 1
Assert.isTrue(s01.length == 2);
final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0],
(StackExpr) s01[1] };
manip(s, new int[] { 0, 1, 0, 1 }, StackManipStmt.DUP2);
}
} else {
final Expr[] s01 = stack.pop2();
if (s01.length == 1) {
// 0-1 -> 0-1 0-1
final LocalExpr t0 = newStackLocal(stack.height(), s01[0]
.type());
if (!t0.equalsExpr(s01[0])) {
addStore(t0, s01[0]);
}
Expr copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
} else {
// 0 1 -> 0 1 0 1
final LocalExpr t0 = newStackLocal(stack.height(), s01[0]
.type());
final LocalExpr t1 = newStackLocal(stack.height() + 1, s01[1]
.type());
if (!t0.equalsExpr(s01[0])) {
addStore(t0, s01[0]);
}
if (!t1.equalsExpr(s01[1])) {
addStore(t1, s01[1]);
}
Expr copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
}
}
}
public void visit_dup2_x1(final Instruction inst) {
// 0 1 2 -> 1 2 0 1 2
// 0 1-2 -> 1-2 0 1-2
if (Tree.USE_STACK) {
saveStack();
final Expr[] s12 = stack.pop2();
final StackExpr s0 = (StackExpr) stack.pop1();
if (s12.length == 2) {
// 0 1 2 -> 1 2 0 1 2
final StackExpr[] s = new StackExpr[] { s0, (StackExpr) s12[0],
(StackExpr) s12[1] };
manip(s, new int[] { 1, 2, 0, 1, 2 }, StackManipStmt.DUP2_X1);
} else {
// 0 1-2 -> 1-2 0 1-2
final StackExpr[] s = new StackExpr[] { s0, (StackExpr) s12[0] };
manip(s, new int[] { 1, 0, 1 }, StackManipStmt.DUP2_X1);
}
} else {
final Expr[] s12 = stack.pop2();
final StackExpr s0 = (StackExpr) stack.pop1();
if (s12.length == 2) {
// 0 1 2 -> 1 2 0 1 2
final LocalExpr t0 = newStackLocal(stack.height(), s0.type());
final LocalExpr t1 = newStackLocal(stack.height() + 1, s12[0]
.type());
final LocalExpr t2 = newStackLocal(stack.height() + 2, s12[1]
.type());
if (!t0.equalsExpr(s0)) {
addStore(t0, s0);
}
if (!t1.equalsExpr(s12[0])) {
addStore(t1, s12[0]);
}
if (!t2.equalsExpr(s12[1])) {
addStore(t2, s12[1]);
}
Expr copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
} else {
// 0 1-2 -> 1-2 0 1-2
final LocalExpr t0 = newStackLocal(stack.height(), s0.type());
final LocalExpr t1 = newStackLocal(stack.height() + 1, s12[0]
.type());
if (!t0.equalsExpr(s0)) {
addStore(t0, s0);
}
if (!t1.equalsExpr(s12[0])) {
addStore(t1, s12[0]);
}
Expr copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
}
}
}
public void visit_dup2_x2(final Instruction inst) {
// 0 1 2 3 -> 2 3 0 1 2 3
// 0 1 2-3 -> 2-3 0 1 2-3
// 0-1 2 3 -> 2 3 0-1 2 3
// 0-1 2-3 -> 2-3 0-1 2-3
if (Tree.USE_STACK) {
saveStack();
final Expr[] s23 = stack.pop2();
final Expr[] s01 = stack.pop2();
if ((s01.length == 2) && (s23.length == 2)) {
// 0 1 2 3 -> 2 3 0 1 2 3
final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0],
(StackExpr) s01[1], (StackExpr) s23[0],
(StackExpr) s23[1] };
manip(s, new int[] { 2, 3, 0, 1, 2, 3 }, StackManipStmt.DUP2_X2);
} else if ((s01.length == 2) && (s23.length == 1)) {
// 0 1 2-3 -> 2-3 0 1 2-3
final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0],
(StackExpr) s01[1], (StackExpr) s23[0] };
manip(s, new int[] { 2, 0, 1, 2 }, StackManipStmt.DUP2_X2);
} else if ((s01.length == 1) && (s23.length == 2)) {
// 0-1 2 3 -> 2 3 0-1 2 3
final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0],
(StackExpr) s23[0], (StackExpr) s23[1] };
manip(s, new int[] { 1, 2, 0, 1, 2 }, StackManipStmt.DUP2_X2);
} else if ((s01.length == 1) && (s23.length == 2)) {
// 0-1 2-3 -> 2-3 0-1 2-3
final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0],
(StackExpr) s23[0] };
manip(s, new int[] { 1, 0, 1 }, StackManipStmt.DUP2_X2);
}
} else {
final Expr[] s23 = stack.pop2();
final Expr[] s01 = stack.pop2();
if ((s01.length == 2) && (s23.length == 2)) {
// 0 1 2 3 -> 2 3 0 1 2 3
final LocalExpr t0 = newStackLocal(stack.height(), s01[0]
.type());
final LocalExpr t1 = newStackLocal(stack.height() + 1, s01[1]
.type());
final LocalExpr t2 = newStackLocal(stack.height() + 2, s23[0]
.type());
final LocalExpr t3 = newStackLocal(stack.height() + 3, s23[1]
.type());
if (!t0.equalsExpr(s01[0])) {
addStore(t0, s01[0]);
}
if (!t1.equalsExpr(s01[1])) {
addStore(t1, s01[1]);
}
if (!t2.equalsExpr(s23[0])) {
addStore(t2, s23[0]);
}
if (!t3.equalsExpr(s23[1])) {
addStore(t3, s23[1]);
}
Expr copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t3.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t3.clone();
copy.setDef(null);
stack.push(copy);
} else if ((s01.length == 2) && (s23.length == 1)) {
// 0 1 2-3 -> 2-3 0 1 2-3
final LocalExpr t0 = newStackLocal(stack.height(), s01[0]
.type());
final LocalExpr t1 = newStackLocal(stack.height() + 1, s01[1]
.type());
final LocalExpr t2 = newStackLocal(stack.height() + 2, s23[0]
.type());
if (!t0.equalsExpr(s01[0])) {
addStore(t0, s01[0]);
}
if (!t1.equalsExpr(s01[1])) {
addStore(t1, s01[1]);
}
if (!t2.equalsExpr(s23[0])) {
addStore(t2, s23[0]);
}
Expr copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
} else if ((s01.length == 1) && (s23.length == 2)) {
// 0-1 2 3 -> 2 3 0-1 2 3
final LocalExpr t0 = newStackLocal(stack.height(), s01[0]
.type());
final LocalExpr t2 = newStackLocal(stack.height() + 2, s23[0]
.type());
final LocalExpr t3 = newStackLocal(stack.height() + 3, s23[1]
.type());
if (!t0.equalsExpr(s01[0])) {
addStore(t0, s01[0]);
}
if (!t2.equalsExpr(s23[0])) {
addStore(t2, s23[0]);
}
if (!t3.equalsExpr(s23[1])) {
addStore(t3, s23[1]);
}
Expr copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t3.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t3.clone();
copy.setDef(null);
stack.push(copy);
} else if ((s01.length == 1) && (s23.length == 2)) {
// 0-1 2-3 -> 2-3 0-1 2-3
final LocalExpr t0 = newStackLocal(stack.height(), s01[0]
.type());
final LocalExpr t2 = newStackLocal(stack.height() + 2, s23[0]
.type());
if (!t0.equalsExpr(s01[0])) {
addStore(t0, s01[0]);
}
if (!t2.equalsExpr(s23[0])) {
addStore(t2, s23[0]);
}
Expr copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t2.clone();
copy.setDef(null);
stack.push(copy);
}
}
}
public void visit_swap(final Instruction inst) {
// 0 1 -> 1 0
if (Tree.USE_STACK) {
saveStack();
final StackExpr s1 = (StackExpr) stack.pop1();
final StackExpr s0 = (StackExpr) stack.pop1();
final StackExpr[] s = new StackExpr[] { s0, s1 };
manip(s, new int[] { 1, 0 }, StackManipStmt.SWAP);
} else {
final Expr s1 = stack.pop1();
final Expr s0 = stack.pop1();
final LocalExpr t0 = newStackLocal(stack.height(), s0.type());
final LocalExpr t1 = newStackLocal(stack.height() + 1, s1.type());
if (!t0.equalsExpr(s0)) {
addStore(t0, s0);
}
if (!t1.equalsExpr(s1)) {
addStore(t1, s1);
}
Expr copy = (Expr) t1.clone();
copy.setDef(null);
stack.push(copy);
copy = (Expr) t0.clone();
copy.setDef(null);
stack.push(copy);
}
}
/**
* Produces a StackManipStmt that represents how the stack is changed as a
* result of a dup instruction. It should only be used when USE_STACK is
* true.
* <p>
* dup instructions change the top n elements of the JVM stack. This method
* takes the original top n elements of the stack, an integer array
* representing the transformation (for instance, if s[0] = 1, then the top
* element of the new stack should contain the second-from-the-top element
* of the old stack), and integer representing the dup instruction.
*
* @param source
* The interesting part of the stack before the dup instruction
* is executed.
* @param s
* An integer array representing the new order of the stack.
* @param kind
* The kind of stack manipulation taking place. (e.g.
* StackManipStmt.DUP_X1)
*
* @see StackManipStmt
*/
private void manip(final StackExpr[] source, final int[] s, final int kind) {
Assert.isTrue(Tree.USE_STACK);
int height = 0; // Height of the stack
// Calculate current height of the stack. Recall that the stack
// elements in source have already been popped off the stack.
for (int i = 0; i < stack.size(); i++) {
final Expr expr = stack.get(i);
height += expr.type().stackHeight();
}
// Create the new portion of the stack. Make new StackExpr
// representing the stack after the dup instruction. Push those
// new StackExprs onto the operand stack. Finally, create a
// StackManipStmt that represent the transformation of the old
// stack (before dup instruction) to the new stack (after dup
// instruction).
final StackExpr[] target = new StackExpr[s.length];
for (int i = 0; i < s.length; i++) {
target[i] = new StackExpr(height, source[s[i]].type());
final StackExpr copy = (StackExpr) target[i].clone();
copy.setDef(null);
stack.push(copy);
height += target[i].type().stackHeight();
}
appendStmt(new StackManipStmt(target, source, kind));
}
/**
* All <tt>visit_<i>x</i>add</tt>, <tt>visit_<i>x</i>sub</tt>,
* <tt>visit_<i>x</i>mul</tt>, <tt>visit_<i>x</i>div</tt>, etc.
* push an ArithExpr onto the operand stack.
*
* @see ArithExpr
*/
public void visit_iadd(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.ADD, left, right, Type.INTEGER);
stack.push(top);
}
public void visit_ladd(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ArithExpr(ArithExpr.ADD, left, right, Type.LONG);
stack.push(top);
}
public void visit_fadd(final Instruction inst) {
final Expr right = stack.pop(Type.FLOAT);
final Expr left = stack.pop(Type.FLOAT);
final Expr top = new ArithExpr(ArithExpr.ADD, left, right, Type.FLOAT);
stack.push(top);
}
public void visit_dadd(final Instruction inst) {
final Expr right = stack.pop(Type.DOUBLE);
final Expr left = stack.pop(Type.DOUBLE);
final Expr top = new ArithExpr(ArithExpr.ADD, left, right, Type.DOUBLE);
stack.push(top);
}
public void visit_isub(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.SUB, left, right, Type.INTEGER);
stack.push(top);
}
public void visit_lsub(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ArithExpr(ArithExpr.SUB, left, right, Type.LONG);
stack.push(top);
}
public void visit_fsub(final Instruction inst) {
final Expr right = stack.pop(Type.FLOAT);
final Expr left = stack.pop(Type.FLOAT);
final Expr top = new ArithExpr(ArithExpr.SUB, left, right, Type.FLOAT);
stack.push(top);
}
public void visit_dsub(final Instruction inst) {
final Expr right = stack.pop(Type.DOUBLE);
final Expr left = stack.pop(Type.DOUBLE);
final Expr top = new ArithExpr(ArithExpr.SUB, left, right, Type.DOUBLE);
stack.push(top);
}
public void visit_imul(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.MUL, left, right, Type.INTEGER);
stack.push(top);
}
public void visit_lmul(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ArithExpr(ArithExpr.MUL, left, right, Type.LONG);
stack.push(top);
}
public void visit_fmul(final Instruction inst) {
final Expr right = stack.pop(Type.FLOAT);
final Expr left = stack.pop(Type.FLOAT);
final Expr top = new ArithExpr(ArithExpr.MUL, left, right, Type.FLOAT);
stack.push(top);
}
public void visit_dmul(final Instruction inst) {
final Expr right = stack.pop(Type.DOUBLE);
final Expr left = stack.pop(Type.DOUBLE);
final Expr top = new ArithExpr(ArithExpr.MUL, left, right, Type.DOUBLE);
stack.push(top);
}
public void visit_idiv(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr check = new ZeroCheckExpr(right, Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.DIV, left, check, Type.INTEGER);
stack.push(top);
}
public void visit_ldiv(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr check = new ZeroCheckExpr(right, Type.LONG);
final Expr top = new ArithExpr(ArithExpr.DIV, left, check, Type.LONG);
stack.push(top);
}
public void visit_fdiv(final Instruction inst) {
final Expr right = stack.pop(Type.FLOAT);
final Expr left = stack.pop(Type.FLOAT);
final Expr top = new ArithExpr(ArithExpr.DIV, left, right, Type.FLOAT);
stack.push(top);
}
public void visit_ddiv(final Instruction inst) {
final Expr right = stack.pop(Type.DOUBLE);
final Expr left = stack.pop(Type.DOUBLE);
final Expr top = new ArithExpr(ArithExpr.DIV, left, right, Type.DOUBLE);
stack.push(top);
}
public void visit_irem(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr check = new ZeroCheckExpr(right, Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.REM, left, check, Type.INTEGER);
stack.push(top);
}
public void visit_lrem(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr check = new ZeroCheckExpr(right, Type.LONG);
final Expr top = new ArithExpr(ArithExpr.REM, left, check, Type.LONG);
stack.push(top);
}
public void visit_frem(final Instruction inst) {
final Expr right = stack.pop(Type.FLOAT);
final Expr left = stack.pop(Type.FLOAT);
final Expr top = new ArithExpr(ArithExpr.REM, left, right, Type.FLOAT);
stack.push(top);
}
public void visit_drem(final Instruction inst) {
final Expr right = stack.pop(Type.DOUBLE);
final Expr left = stack.pop(Type.DOUBLE);
final Expr top = new ArithExpr(ArithExpr.REM, left, right, Type.DOUBLE);
stack.push(top);
}
/**
* All <tt>visit_<i>x</i>neg</tt> push a NegExpr onto the stack.
*
* @see NegExpr
*/
public void visit_ineg(final Instruction inst) {
final Expr expr = stack.pop(Type.INTEGER);
final Expr top = new NegExpr(expr, Type.INTEGER);
stack.push(top);
}
public void visit_lneg(final Instruction inst) {
final Expr expr = stack.pop(Type.LONG);
final Expr top = new NegExpr(expr, Type.LONG);
stack.push(top);
}
public void visit_fneg(final Instruction inst) {
final Expr expr = stack.pop(Type.FLOAT);
final Expr top = new NegExpr(expr, Type.FLOAT);
stack.push(top);
}
public void visit_dneg(final Instruction inst) {
final Expr expr = stack.pop(Type.DOUBLE);
final Expr top = new NegExpr(expr, Type.DOUBLE);
stack.push(top);
}
/**
* All <tt>visit_<i>x</i>sh<i>d</i></tt> push a ShiftExpr onto the
* operand stack.
*
* @see ShiftExpr
*/
public void visit_ishl(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ShiftExpr(ShiftExpr.LEFT, left, right,
Type.INTEGER);
stack.push(top);
}
public void visit_lshl(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ShiftExpr(ShiftExpr.LEFT, left, right, Type.LONG);
stack.push(top);
}
public void visit_ishr(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ShiftExpr(ShiftExpr.RIGHT, left, right,
Type.INTEGER);
stack.push(top);
}
public void visit_lshr(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ShiftExpr(ShiftExpr.RIGHT, left, right, Type.LONG);
stack.push(top);
}
public void visit_iushr(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ShiftExpr(ShiftExpr.UNSIGNED_RIGHT, left, right,
Type.INTEGER);
stack.push(top);
}
public void visit_lushr(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ShiftExpr(ShiftExpr.UNSIGNED_RIGHT, left, right,
Type.LONG);
stack.push(top);
}
/**
* All <tt>visit_<i>x op</i></tt> push an ArithExpr onto the stack.
*
* @see ArithExpr
*/
public void visit_iand(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.AND, left, right, Type.INTEGER);
stack.push(top);
}
public void visit_land(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ArithExpr(ArithExpr.AND, left, right, Type.LONG);
stack.push(top);
}
public void visit_ior(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.IOR, left, right, Type.INTEGER);
stack.push(top);
}
public void visit_lor(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ArithExpr(ArithExpr.IOR, left, right, Type.LONG);
stack.push(top);
}
public void visit_ixor(final Instruction inst) {
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.XOR, left, right, Type.INTEGER);
stack.push(top);
}
public void visit_lxor(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ArithExpr(ArithExpr.XOR, left, right, Type.LONG);
stack.push(top);
}
/**
* Visiting an iinc involves creating a ConstantExpr, LocalExpr, ArithExpr
* StoreExpr, and a ExprStmt.
*/
public void visit_iinc(final Instruction inst) {
final IncOperand operand = (IncOperand) inst.operand();
int incr = operand.incr();
if (incr < 0) {
final Expr right = new ConstantExpr(new Integer(-incr),
Type.INTEGER);
final Expr left = new LocalExpr(operand.var().index(), Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.SUB, left, right,
Type.INTEGER);
final LocalExpr copy = (LocalExpr) left.clone();
copy.setDef(null);
addStmt(new ExprStmt(new StoreExpr(copy, top, left.type())));
} else if (incr > 0) {
final Expr right = new ConstantExpr(new Integer(incr), Type.INTEGER);
final Expr left = new LocalExpr(operand.var().index(), Type.INTEGER);
final Expr top = new ArithExpr(ArithExpr.ADD, left, right,
Type.INTEGER);
final LocalExpr copy = (LocalExpr) left.clone();
copy.setDef(null);
addStmt(new ExprStmt(new StoreExpr(copy, top, left.type())));
}
}
/**
* All cast visitors push a CastExpr onto the operand stack.
*/
public void visit_i2l(final Instruction inst) {
final Expr expr = stack.pop(Type.INTEGER);
final Expr top = new CastExpr(expr, Type.LONG, Type.LONG);
stack.push(top);
}
public void visit_i2f(final Instruction inst) {
final Expr expr = stack.pop(Type.INTEGER);
final Expr top = new CastExpr(expr, Type.FLOAT, Type.FLOAT);
stack.push(top);
}
public void visit_i2d(final Instruction inst) {
final Expr expr = stack.pop(Type.INTEGER);
final Expr top = new CastExpr(expr, Type.DOUBLE, Type.DOUBLE);
stack.push(top);
}
public void visit_l2i(final Instruction inst) {
final Expr expr = stack.pop(Type.LONG);
final Expr top = new CastExpr(expr, Type.INTEGER, Type.INTEGER);
stack.push(top);
}
public void visit_l2f(final Instruction inst) {
final Expr expr = stack.pop(Type.LONG);
final Expr top = new CastExpr(expr, Type.FLOAT, Type.FLOAT);
stack.push(top);
}
public void visit_l2d(final Instruction inst) {
final Expr expr = stack.pop(Type.LONG);
final Expr top = new CastExpr(expr, Type.DOUBLE, Type.DOUBLE);
stack.push(top);
}
public void visit_f2i(final Instruction inst) {
final Expr expr = stack.pop(Type.FLOAT);
final Expr top = new CastExpr(expr, Type.INTEGER, Type.INTEGER);
stack.push(top);
}
public void visit_f2l(final Instruction inst) {
final Expr expr = stack.pop(Type.FLOAT);
final Expr top = new CastExpr(expr, Type.LONG, Type.LONG);
stack.push(top);
}
public void visit_f2d(final Instruction inst) {
final Expr expr = stack.pop(Type.FLOAT);
final Expr top = new CastExpr(expr, Type.DOUBLE, Type.DOUBLE);
stack.push(top);
}
public void visit_d2i(final Instruction inst) {
final Expr expr = stack.pop(Type.DOUBLE);
final Expr top = new CastExpr(expr, Type.INTEGER, Type.INTEGER);
stack.push(top);
}
public void visit_d2l(final Instruction inst) {
final Expr expr = stack.pop(Type.DOUBLE);
final Expr top = new CastExpr(expr, Type.LONG, Type.LONG);
stack.push(top);
}
public void visit_d2f(final Instruction inst) {
final Expr expr = stack.pop(Type.DOUBLE);
final Expr top = new CastExpr(expr, Type.FLOAT, Type.FLOAT);
stack.push(top);
}
public void visit_i2b(final Instruction inst) {
final Expr expr = stack.pop(Type.INTEGER);
final Expr top = new CastExpr(expr, Type.BYTE, Type.INTEGER);
stack.push(top);
}
public void visit_i2c(final Instruction inst) {
final Expr expr = stack.pop(Type.INTEGER);
final Expr top = new CastExpr(expr, Type.CHARACTER, Type.INTEGER);
stack.push(top);
}
public void visit_i2s(final Instruction inst) {
final Expr expr = stack.pop(Type.INTEGER);
final Expr top = new CastExpr(expr, Type.SHORT, Type.INTEGER);
stack.push(top);
}
/**
* All <tt>visit_<i>x</i>cmp</tt> push an ArithExpr onto the stack.
*
* @see ArithExpr
*/
public void visit_lcmp(final Instruction inst) {
final Expr right = stack.pop(Type.LONG);
final Expr left = stack.pop(Type.LONG);
final Expr top = new ArithExpr(ArithExpr.CMP, left, right, Type.INTEGER);
stack.push(top);
}
public void visit_fcmpl(final Instruction inst) {
final Expr right = stack.pop(Type.FLOAT);
final Expr left = stack.pop(Type.FLOAT);
final Expr top = new ArithExpr(ArithExpr.CMPL, left, right,
Type.INTEGER);
stack.push(top);
}
public void visit_fcmpg(final Instruction inst) {
final Expr right = stack.pop(Type.FLOAT);
final Expr left = stack.pop(Type.FLOAT);
final Expr top = new ArithExpr(ArithExpr.CMPG, left, right,
Type.INTEGER);
stack.push(top);
}
public void visit_dcmpl(final Instruction inst) {
final Expr right = stack.pop(Type.DOUBLE);
final Expr left = stack.pop(Type.DOUBLE);
final Expr top = new ArithExpr(ArithExpr.CMPL, left, right,
Type.INTEGER);
stack.push(top);
}
public void visit_dcmpg(final Instruction inst) {
final Expr right = stack.pop(Type.DOUBLE);
final Expr left = stack.pop(Type.DOUBLE);
final Expr top = new ArithExpr(ArithExpr.CMPG, left, right,
Type.INTEGER);
stack.push(top);
}
/**
* All <tt>visit_<i>x</i>eg</tt> add an IfZeroStmt to the statement
* list.
*
* @see IfZeroStmt
*/
public void visit_ifeq(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfZeroStmt(IfStmt.EQ, left, t, next));
}
public void visit_ifne(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfZeroStmt(IfStmt.NE, left, t, next));
}
public void visit_iflt(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfZeroStmt(IfStmt.LT, left, t, next));
}
public void visit_ifge(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfZeroStmt(IfStmt.GE, left, t, next));
}
public void visit_ifgt(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfZeroStmt(IfStmt.GT, left, t, next));
}
public void visit_ifle(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfZeroStmt(IfStmt.LE, left, t, next));
}
/**
* All <tt>visit_if_<i>x</i>cmp<i>y</i></tt> add a IfCmpStmt to the
* statement list.
*/
public void visit_if_icmpeq(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfCmpStmt(IfStmt.EQ, left, right, t, next));
}
public void visit_if_icmpne(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfCmpStmt(IfStmt.NE, left, right, t, next));
}
public void visit_if_icmplt(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfCmpStmt(IfStmt.LT, left, right, t, next));
}
public void visit_if_icmpge(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfCmpStmt(IfStmt.GE, left, right, t, next));
}
public void visit_if_icmpgt(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfCmpStmt(IfStmt.GT, left, right, t, next));
}
public void visit_if_icmple(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr right = stack.pop(Type.INTEGER);
final Expr left = stack.pop(Type.INTEGER);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfCmpStmt(IfStmt.LE, left, right, t, next));
}
public void visit_if_acmpeq(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr right = stack.pop(Type.OBJECT);
final Expr left = stack.pop(Type.OBJECT);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfCmpStmt(IfStmt.EQ, left, right, t, next));
}
public void visit_if_acmpne(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr right = stack.pop(Type.OBJECT);
final Expr left = stack.pop(Type.OBJECT);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfCmpStmt(IfStmt.NE, left, right, t, next));
}
/**
* Adds a GotoStmt to the statement list.
*
* @see GotoStmt
*/
public void visit_goto(final Instruction inst) {
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new GotoStmt(t));
}
/**
* Adds a JsrStmt to the statement list.
*
* @see JsrStmt
*/
public void visit_jsr(final Instruction inst) {
// Push the return address after we add the statement.
// This prevents it from being saved to a local variable.
// It's illegal to load a return address from a local variable,
// so we can't save it.
final Subroutine sub = block.graph().labelSub((Label) inst.operand());
addStmt(new JsrStmt(sub, next));
stack.push(new ReturnAddressExpr(Type.ADDRESS));
}
/**
* Adds a RetStmt to the statement list.
*
* @see RetStmt
*/
public void visit_ret(final Instruction inst) {
Assert.isTrue(sub != null);
addStmt(new RetStmt(sub));
}
/**
* Add a SwitchStmt to the statement list.
*
* @see SwitchStmt
*/
public void visit_switch(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr index = stack.pop(Type.INTEGER);
final Switch sw = (Switch) inst.operand();
final Block defaultTarget = (Block) block.graph().getNode(
sw.defaultTarget());
Assert.isTrue(defaultTarget != null, "No block for " + inst);
final Block[] targets = new Block[sw.targets().length];
for (int i = 0; i < targets.length; i++) {
targets[i] = (Block) block.graph().getNode(sw.targets()[i]);
Assert.isTrue(targets[i] != null, "No block for " + inst);
}
addStmt(new SwitchStmt(index, defaultTarget, targets, sw.values()));
}
/**
* All <tt>visit_<i>x</i>return</tt> add a ReturnExprStmt to the
* statement list.
*
* @see ReturnExprStmt
*/
public void visit_ireturn(final Instruction inst) {
final Expr expr = stack.pop(Type.INTEGER);
addStmt(new ReturnExprStmt(expr));
}
public void visit_lreturn(final Instruction inst) {
final Expr expr = stack.pop(Type.LONG);
addStmt(new ReturnExprStmt(expr));
}
public void visit_freturn(final Instruction inst) {
final Expr expr = stack.pop(Type.FLOAT);
addStmt(new ReturnExprStmt(expr));
}
public void visit_dreturn(final Instruction inst) {
final Expr expr = stack.pop(Type.DOUBLE);
addStmt(new ReturnExprStmt(expr));
}
public void visit_areturn(final Instruction inst) {
final Expr expr = stack.pop(Type.OBJECT);
addStmt(new ReturnExprStmt(expr));
}
/**
* Adds a ReturnStmt to the statement list.
*/
public void visit_return(final Instruction inst) {
addStmt(new ReturnStmt());
}
/**
* Pushes a StaticFieldExpr onto the operand stack.
*/
public void visit_getstatic(final Instruction inst) {
final MemberRef field = (MemberRef) inst.operand();
final Type type = field.nameAndType().type();
try {
final EditorContext context = block.graph().method()
.declaringClass().context();
final FieldEditor e = context.editField(field);
if (e.isFinal()) {
if (e.constantValue() != null) {
final Expr top = new ConstantExpr(e.constantValue(), type);
stack.push(top);
context.release(e.fieldInfo());
return;
}
}
context.release(e.fieldInfo());
} catch (final NoSuchFieldException e) {
// No field found. Silently assume non-final.
}
final Expr top = new StaticFieldExpr(field, type);
stack.push(top);
}
public void visit_putstatic(final Instruction inst) {
final MemberRef field = (MemberRef) inst.operand();
final Type type = field.nameAndType().type();
final Expr value = stack.pop(type);
final StaticFieldExpr target = new StaticFieldExpr(field, type);
addStore(target, value);
}
public void visit_putstatic_nowb(final Instruction inst) {
visit_putstatic(inst);
}
/**
* Pushes a FieldExpr onto the operand stack.
*/
public void visit_getfield(final Instruction inst) {
final MemberRef field = (MemberRef) inst.operand();
final Type type = field.nameAndType().type();
final Expr obj = stack.pop(Type.OBJECT);
final Expr check = new ZeroCheckExpr(obj, obj.type());
final Expr top = new FieldExpr(check, field, type);
stack.push(top);
}
public void visit_putfield(final Instruction inst) {
final MemberRef field = (MemberRef) inst.operand();
final Type type = field.nameAndType().type();
final Expr value = stack.pop(type);
final Expr obj = stack.pop(Type.OBJECT);
Expr ucCheck = obj;
if (Tree.USE_PERSISTENT) {
ucCheck = new UCExpr(obj, UCExpr.POINTER, obj.type());
}
final Expr check = new ZeroCheckExpr(ucCheck, obj.type());
final FieldExpr target = new FieldExpr(check, field, type);
addStore(target, value);
}
// Don't insert UCExpr
public void visit_putfield_nowb(final Instruction inst) {
final MemberRef field = (MemberRef) inst.operand();
final Type type = field.nameAndType().type();
final Expr value = stack.pop(type);
final Expr obj = stack.pop(Type.OBJECT);
final Expr check = new ZeroCheckExpr(obj, obj.type());
final FieldExpr target = new FieldExpr(check, field, type);
addStore(target, value);
}
/**
* All <tt>visit_invoke<i>x</i></tt> deal with a CallMethodExpr or a
* CallStaticExpr.
*
* @see CallMethodExpr
* @see CallStaticExpr
*/
public void visit_invokevirtual(final Instruction inst) {
addCall(inst, CallMethodExpr.VIRTUAL);
}
public void visit_invokespecial(final Instruction inst) {
addCall(inst, CallMethodExpr.NONVIRTUAL);
}
public void visit_invokestatic(final Instruction inst) {
addCall(inst, 0);
}
public void visit_invokeinterface(final Instruction inst) {
addCall(inst, CallMethodExpr.INTERFACE);
}
/**
* Creates either a CallMethodExpr or a CallStaticExpr to represent a method
* call. After obtaining some information about the method. The parameters
* to the methods are popped from the operand stack. If the method is not
* static, the "this" object is popped from the operand stack. A
* CallMethodExpr is created for a non-static method and a CallStaticExpr is
* created for a static method. If the method returns a value, the Call*Expr
* is pushed onto the stack. If the method has no return value, it is
* wrapped in an ExprStmt and is added to the statement list.
*/
private void addCall(final Instruction inst, final int kind) {
final MemberRef method = (MemberRef) inst.operand();
final Type type = method.nameAndType().type();
final Type[] paramTypes = type.paramTypes();
final Expr[] params = new Expr[paramTypes.length];
for (int i = paramTypes.length - 1; i >= 0; i--) {
params[i] = stack.pop(paramTypes[i]);
}
Expr top;
if (inst.opcodeClass() != Opcode.opcx_invokestatic) {
final Expr obj = stack.pop(Type.OBJECT);
top = new CallMethodExpr(kind, obj, params, method, type
.returnType());
} else {
top = new CallStaticExpr(params, method, type.returnType());
}
if (type.returnType().equals(Type.VOID)) {
addStmt(new ExprStmt(top));
} else {
stack.push(top);
}
}
/**
* Pushes a NewExpr onto the operand stack.
*
* @see NewExpr
*/
public void visit_new(final Instruction inst) {
final Type type = (Type) inst.operand();
final Expr top = new NewExpr(type, Type.OBJECT);
stack.push(top);
db(" new: " + top);
}
/**
* Pushes a NewArrayExpr onto the operand stack.
*/
public void visit_newarray(final Instruction inst) {
final Type type = (Type) inst.operand();
final Expr size = stack.pop(Type.INTEGER);
final Expr top = new NewArrayExpr(size, type, type.arrayType());
stack.push(top);
}
/**
* Pushes an ArrayLengthExpr onto the operand stack.
*
* @see ArrayLengthExpr
*/
public void visit_arraylength(final Instruction inst) {
final Expr array = stack.pop(Type.OBJECT);
final Expr top = new ArrayLengthExpr(array, Type.INTEGER);
stack.push(top);
}
/**
* Adds a ThrowStmt to the statement list.
*
* @see ThrowStmt
*/
public void visit_athrow(final Instruction inst) {
final Expr expr = stack.pop(Type.THROWABLE);
addStmt(new ThrowStmt(expr));
}
/**
* Pushes a CastExpr onto the operand stack.
*
* @see CastExpr
*/
public void visit_checkcast(final Instruction inst) {
final Expr expr = stack.pop(Type.OBJECT);
final Type type = (Type) inst.operand();
final Expr top = new CastExpr(expr, type, type);
stack.push(top);
}
/**
* Pushes an InstanceOfExpr onto the operand stack.
*
* @see InstanceOfExpr
*/
public void visit_instanceof(final Instruction inst) {
final Type type = (Type) inst.operand();
final Expr expr = stack.pop(Type.OBJECT);
final Expr top = new InstanceOfExpr(expr, type, Type.INTEGER);
stack.push(top);
}
/**
* Both <tt>monitor</tt> visitors add a MonitorStmt to the statement list.
*
* @see MonitorStmt
*/
public void visit_monitorenter(final Instruction inst) {
final Expr obj = stack.pop(Type.OBJECT);
addStmt(new MonitorStmt(MonitorStmt.ENTER, obj));
}
public void visit_monitorexit(final Instruction inst) {
final Expr obj = stack.pop(Type.OBJECT);
addStmt(new MonitorStmt(MonitorStmt.EXIT, obj));
}
/**
* Push a NewMultiArrayExpr onto the operand stack.
*
* @see NewMultiArrayExpr
*/
public void visit_multianewarray(final Instruction inst) {
final MultiArrayOperand operand = (MultiArrayOperand) inst.operand();
final Expr[] dim = new Expr[operand.dimensions()];
for (int i = dim.length - 1; i >= 0; i--) {
dim[i] = stack.pop(Type.INTEGER);
}
final Type type = operand.type();
final Expr top = new NewMultiArrayExpr(dim, type
.elementType(dim.length), type);
stack.push(top);
}
/**
* Both <tt>visit_<i>x</i>null</tt> add an IfZeroStmt to the statement
* list.
*
* ssee IfZeroStmt
*/
public void visit_ifnull(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr left = stack.pop(Type.OBJECT);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfZeroStmt(IfStmt.EQ, left, t, next));
}
public void visit_ifnonnull(final Instruction inst) {
// It isn't necessary to saveStack since removing critical edges
// guarantees that no code will be inserted before the branch
// since there cannot be more than one predecessor of either of
// the successor nodes (and hence no phi statements, even in SSAPRE).
// saveStack();
final Expr left = stack.pop(Type.OBJECT);
final Block t = (Block) block.graph().getNode(inst.operand());
Assert.isTrue(t != null, "No block for " + inst);
addStmt(new IfZeroStmt(IfStmt.NE, left, t, next));
}
/**
* Replaces the expression on the top of the stack with an RCExpr.
*
* @see RCExpr
*/
public void visit_rc(final Instruction inst) {
final Integer depth = (Integer) inst.operand();
final Expr object = stack.peek(depth.intValue());
stack.replace(depth.intValue(), new RCExpr(object, object.type()));
}
/**
*
*/
public void visit_aupdate(final Instruction inst) {
Integer depth = (Integer) inst.operand();
if (Tree.AUPDATE_FIX_HACK) {
// Hack to fix a bug in old bloat-generated code:
if (depth.intValue() == 1) {
final Expr object = stack.peek();
if (object.type().isWide()) {
depth = new Integer(2);
inst.setOperand(depth);
Tree.AUPDATE_FIX_HACK_CHANGED = true;
}
}
}
final Expr object = stack.peek(depth.intValue());
stack.replace(depth.intValue(), new UCExpr(object, UCExpr.POINTER,
object.type()));
}
/**
* Replace the expression at the stack depth specified in the instruction
* with a UCExpr.
*
* @see UCExpr
*/
public void visit_supdate(final Instruction inst) {
final Integer depth = (Integer) inst.operand();
final Expr object = stack.peek(depth.intValue());
stack.replace(depth.intValue(), new UCExpr(object, UCExpr.SCALAR,
object.type()));
}
/**
* Add a SCStmt to the statement list
*
* @see SCStmt
*/
public void visit_aswizzle(final Instruction inst) {
final Expr index = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.OBJECT.arrayType());
addStmt(new SCStmt(array, index));
}
/**
* Add a SRStmt to the statement list.
*
* @see SRStmt
*/
public void visit_aswrange(final Instruction inst) {
final Expr end = stack.pop(Type.INTEGER);
final Expr start = stack.pop(Type.INTEGER);
final Expr array = stack.pop(Type.OBJECT.arrayType());
addStmt(new SRStmt(array, start, end));
}
/**
* Visit all the statements in the statement list.
*/
public void visitForceChildren(final TreeVisitor visitor) {
final LinkedList list = new LinkedList(stmts);
if (visitor.reverse()) {
final ListIterator iter = list.listIterator(stmts.size());
while (iter.hasPrevious()) {
final Stmt s = (Stmt) iter.previous();
s.visit(visitor);
}
} else {
final ListIterator iter = list.listIterator();
while (iter.hasNext()) {
final Stmt s = (Stmt) iter.next();
s.visit(visitor);
}
}
}
public void visit(final TreeVisitor visitor) {
visitor.visitTree(this);
}
public Node parent() {
return null;
}
public Block block() {
return block;
}
}