0001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
0002:
0003: This file is part of the db4o open source object database.
0004:
0005: db4o is free software; you can redistribute it and/or modify it under
0006: the terms of version 2 of the GNU General Public License as published
0007: by the Free Software Foundation and as clarified by db4objects' GPL
0008: interpretation policy, available at
0009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
0010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
0011: Suite 350, San Mateo, CA 94403, USA.
0012:
0013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
0014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: for more details.
0017:
0018: You should have received a copy of the GNU General Public License along
0019: with this program; if not, write to the Free Software Foundation, Inc.,
0020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
0021: package EDU.purdue.cs.bloat.tree;
0022:
0023: import java.util.*;
0024:
0025: import EDU.purdue.cs.bloat.cfg.*;
0026: import EDU.purdue.cs.bloat.editor.*;
0027: import EDU.purdue.cs.bloat.reflect.*;
0028: import EDU.purdue.cs.bloat.util.*;
0029:
0030: /**
0031: * Tree represents the expression tree of a basic Block. It consists of an
0032: * operand (expression) stack comprised of expressions and a list of statements
0033: * contained in the block.
0034: *
0035: * @see Block
0036: * @see Expr
0037: * @see OperandStack
0038: * @see Stmt see StmtList
0039: */
0040: public class Tree extends Node implements InstructionVisitor, Opcode {
0041: public static boolean DEBUG = false;
0042:
0043: public static boolean FLATTEN = false;
0044:
0045: public static boolean USE_STACK = true; // Do we use stack vars?
0046:
0047: public static boolean AUPDATE_FIX_HACK = false;
0048:
0049: public static boolean AUPDATE_FIX_HACK_CHANGED = false;
0050:
0051: public static boolean USE_PERSISTENT = false; // Insert UCExpr by default
0052:
0053: Block block; // Block that is represented by this Tree
0054:
0055: Subroutine sub; // The Subroutine that we're currently in
0056:
0057: Block next; // The Block after this one
0058:
0059: OperandStack stack; // The program stack for this block
0060:
0061: StmtList stmts; // The statements in the basic block
0062:
0063: Stack savedStack;
0064:
0065: static int stackpos = 0;
0066:
0067: boolean saveValue; // Do we push a StoreExpr on operand stack?
0068:
0069: // Some dup instruction combinations cause saveStack to generate
0070: // temporaries that clobber other temporaries. So, we use nextindex
0071: // to ensure that a uniquely-name temporary is created by
0072: // saveStack. Yes, this will introduce a lot of new temporaries,
0073: // but expression propagation should eliminate a lot of them.
0074: private int nextIndex = 0;
0075:
0076: private void db(final String s) {
0077: if (Tree.DEBUG) {
0078: System.out.println(s);
0079: }
0080: }
0081:
0082: /**
0083: * Constructor.
0084: *
0085: * @param block
0086: * The basic Block of code represented in this Tree.
0087: * @param predStack
0088: * The contents of the operand stack from the previous basic
0089: * Block.
0090: */
0091: public Tree(final Block block, final OperandStack predStack) {
0092: this .block = block;
0093:
0094: if (Tree.DEBUG) {
0095: System.out.println(" new tree for " + block);
0096: }
0097:
0098: stack = new OperandStack();
0099:
0100: stmts = new StmtList();
0101:
0102: // The first statement in the Tree is the label indicating the start
0103: // of the basic Block.
0104: appendStmt(new LabelStmt(block.label()));
0105:
0106: // Make a copy of predStack
0107: for (int i = 0; i < predStack.size(); i++) {
0108: final Expr expr = predStack.get(i);
0109: final Expr copy = (Expr) expr.clone();
0110: copy.setDef(null);
0111: stack.push(copy);
0112: }
0113: }
0114:
0115: /**
0116: * Cleans up this node. Does nothing in this case.
0117: */
0118: public void cleanupOnly() {
0119: }
0120:
0121: /**
0122: * Add a Collection of local variables to the block. Add an InitStmt to the
0123: * statement list.
0124: *
0125: * @see LocalExpr
0126: * @see InitStmt
0127: */
0128: public void initLocals(final Collection locals) {
0129: final LocalExpr[] t = new LocalExpr[locals.size()];
0130:
0131: if (t.length == 0) {
0132: return;
0133: }
0134:
0135: final Iterator iter = locals.iterator();
0136:
0137: for (int i = 0; iter.hasNext(); i++) {
0138: t[i] = (LocalExpr) iter.next();
0139: }
0140:
0141: addStmt(new InitStmt(t));
0142: }
0143:
0144: /**
0145: * Removes a statement from the statement list.
0146: *
0147: * @param stmt
0148: * The statement to remove
0149: */
0150: public void removeStmt(final Stmt stmt) {
0151: stmts.remove(stmt);
0152: }
0153:
0154: /**
0155: * Removes the last non-Label statement from the statement list.
0156: */
0157: public void removeLastStmt() {
0158: final ListIterator iter = stmts.listIterator(stmts.size());
0159:
0160: while (iter.hasPrevious()) {
0161: final Stmt s = (Stmt) iter.previous();
0162:
0163: if (s instanceof LabelStmt) {
0164: continue;
0165: }
0166:
0167: iter.remove();
0168: return;
0169: }
0170: }
0171:
0172: /**
0173: * @return The statement list
0174: */
0175: public List stmts() {
0176: return stmts;
0177: }
0178:
0179: /**
0180: * StmtList is a linked list of statements. A number of methods are
0181: * overridden because some adjustments may need to be made to the Nodes in
0182: * the tree when certain operations are performed.
0183: */
0184: class StmtList extends LinkedList {
0185: /**
0186: * Clear the contents of this statement list.
0187: */
0188: public void clear() {
0189: final Iterator iter = iterator();
0190:
0191: while (iter.hasNext()) {
0192: ((Stmt) iter.next()).cleanup();
0193: }
0194:
0195: super .clear();
0196: }
0197:
0198: /**
0199: * Remove a statement from the list and clean up afterwards.
0200: */
0201: public boolean remove(final Object o) {
0202: if (super .remove(o)) {
0203: ((Stmt) o).cleanup();
0204: return true;
0205: }
0206:
0207: return false;
0208: }
0209:
0210: /**
0211: * Remove all of the statements in a Collection from this statement
0212: * list.
0213: *
0214: * @param c
0215: * A Collection containing the statements to remove.
0216: * @return True, if the contents of this statement list changed.
0217: */
0218: public boolean removeAll(final Collection c) {
0219: boolean changed = false;
0220:
0221: if (c == this ) {
0222: changed = size() > 0;
0223: clear();
0224: } else {
0225: final Iterator iter = c.iterator();
0226:
0227: while (iter.hasNext()) {
0228: changed = remove(iter.next()) || changed;
0229: }
0230: }
0231:
0232: return changed;
0233: }
0234:
0235: /**
0236: * Remove all statements in this list except those that are in a
0237: * specified Collection.
0238: *
0239: * @param c
0240: * The statements to keep.
0241: * @return True, if the contents of this statement list changed.
0242: */
0243: public boolean retainAll(final Collection c) {
0244: boolean changed = false;
0245:
0246: if (c == this ) {
0247: return false;
0248: }
0249:
0250: final Iterator iter = iterator();
0251:
0252: while (iter.hasNext()) {
0253: if (!c.contains(iter.next())) {
0254: changed = true;
0255: iter.remove();
0256: }
0257: }
0258:
0259: return changed;
0260: }
0261:
0262: /**
0263: * Set the value of a given statement.
0264: *
0265: * @param index
0266: * Index of the statement to change.
0267: * @param element
0268: * New value of statement at index.
0269: *
0270: * @return Statement previously at position index.
0271: */
0272: public Object set(final int index, final Object element) {
0273: if (index < size()) {
0274: final Stmt s = (Stmt) get(index);
0275:
0276: if (s != element) {
0277: s.cleanup();
0278: }
0279: }
0280:
0281: return super .set(index, element);
0282: }
0283:
0284: /**
0285: * Removes the statement at index
0286: *
0287: * @return Statement previously at position index.
0288: */
0289: public Object remove(final int index) {
0290: final Object o = super .remove(index);
0291:
0292: if (o != null) {
0293: ((Stmt) o).cleanup();
0294: }
0295:
0296: return o;
0297: }
0298:
0299: /**
0300: * Removes statements in a given index range.
0301: */
0302: /*
0303: * public void removeRange(int fromIndex, int toIndex) { int remaining =
0304: * toIndex - fromIndex;
0305: *
0306: * ListIterator iter = listIterator(fromIndex);
0307: *
0308: * while (iter.hasNext() && remaining-- > 0) { ((Stmt)
0309: * iter.next()).cleanup(); }
0310: *
0311: * super.removeRange(fromIndex, toIndex); }
0312: */
0313:
0314: /**
0315: * @return A ListIterator starting with the first statement in the
0316: * statement list.
0317: */
0318: public ListIterator listIterator() {
0319: return listIterator(0);
0320: }
0321:
0322: /**
0323: * @return A ListIterator starting a given index.
0324: */
0325: public ListIterator listIterator(final int index) {
0326: final ListIterator iter = super .listIterator(index);
0327:
0328: return new ListIterator() {
0329: Object last = null;
0330:
0331: public boolean hasNext() {
0332: return iter.hasNext();
0333: }
0334:
0335: public Object next() {
0336: last = iter.next();
0337: return last;
0338: }
0339:
0340: public boolean hasPrevious() {
0341: return iter.hasPrevious();
0342: }
0343:
0344: public Object previous() {
0345: last = iter.previous();
0346: return last;
0347: }
0348:
0349: public int nextIndex() {
0350: return iter.nextIndex();
0351: }
0352:
0353: public int previousIndex() {
0354: return iter.previousIndex();
0355: }
0356:
0357: public void add(final Object obj) {
0358: Assert.isTrue(obj instanceof Stmt);
0359: ((Stmt) obj).setParent(Tree.this );
0360: last = null;
0361: iter.add(obj);
0362: }
0363:
0364: public void set(final Object obj) {
0365: if (last == null) {
0366: throw new NoSuchElementException();
0367: }
0368:
0369: Assert.isTrue(obj instanceof Stmt);
0370: ((Stmt) obj).setParent(Tree.this );
0371:
0372: ((Stmt) last).cleanup();
0373: last = null;
0374:
0375: iter.set(obj);
0376: }
0377:
0378: public void remove() {
0379: if (last == null) {
0380: throw new NoSuchElementException();
0381: }
0382:
0383: ((Stmt) last).cleanup();
0384: last = null;
0385:
0386: iter.remove();
0387: }
0388: };
0389: }
0390:
0391: /**
0392: * @return An Iterator over this statement list.
0393: */
0394: public Iterator iterator() {
0395: final Iterator iter = super .iterator();
0396:
0397: return new Iterator() {
0398: Object last = null;
0399:
0400: public boolean hasNext() {
0401: return iter.hasNext();
0402: }
0403:
0404: public Object next() {
0405: last = iter.next();
0406: return last;
0407: }
0408:
0409: public void remove() {
0410: if (last == null) {
0411: throw new NoSuchElementException();
0412: }
0413:
0414: ((Stmt) last).cleanup();
0415: last = null;
0416:
0417: iter.remove();
0418: }
0419: };
0420: }
0421: }
0422:
0423: /**
0424: * Returns the last non-Label statement in the statement list.
0425: */
0426: public Stmt lastStmt() {
0427: final ListIterator iter = stmts.listIterator(stmts.size());
0428:
0429: while (iter.hasPrevious()) {
0430: final Stmt s = (Stmt) iter.previous();
0431:
0432: if (s instanceof LabelStmt) {
0433: continue;
0434: }
0435:
0436: return s;
0437: }
0438:
0439: return null;
0440: }
0441:
0442: /**
0443: * Returns the operand stack.
0444: */
0445: public OperandStack stack() {
0446: return stack;
0447: }
0448:
0449: /**
0450: * Inserts a statement into the statement list after another given
0451: * statement.
0452: *
0453: * @param stmt
0454: * The statement to add.
0455: * @param after
0456: * The statement after which to add stmt.
0457: */
0458: public void addStmtAfter(final Stmt stmt, final Stmt after) {
0459: if (Tree.DEBUG) {
0460: System.out.println("insert: " + stmt + " after " + after);
0461: }
0462:
0463: final ListIterator iter = stmts.listIterator();
0464:
0465: while (iter.hasNext()) {
0466: final Stmt s = (Stmt) iter.next();
0467:
0468: if (s == after) {
0469: iter.add(stmt);
0470: stmt.setParent(this );
0471: return;
0472: }
0473: }
0474:
0475: throw new RuntimeException(after + " not found");
0476: }
0477:
0478: /**
0479: * Inserts a statement into the statement list before a specified statement.
0480: *
0481: * @param stmt
0482: * The statement to insert
0483: * @param before
0484: * The statement before which to add stmt.
0485: */
0486: public void addStmtBefore(final Stmt stmt, final Stmt before) {
0487: if (Tree.DEBUG) {
0488: System.out.println("insert: " + stmt + " before " + before);
0489: }
0490:
0491: final ListIterator iter = stmts.listIterator();
0492:
0493: while (iter.hasNext()) {
0494: final Stmt s = (Stmt) iter.next();
0495:
0496: if (s == before) {
0497: iter.previous();
0498: iter.add(stmt);
0499: stmt.setParent(this );
0500: return;
0501: }
0502: }
0503:
0504: throw new RuntimeException(before + " not found");
0505: }
0506:
0507: /**
0508: * Add an statement to the statement list before the first non-Label
0509: * statement.
0510: *
0511: * @param stmt
0512: * The statement to add.
0513: */
0514: public void prependStmt(final Stmt stmt) {
0515: if (Tree.DEBUG) {
0516: System.out.println("prepend: " + stmt + " in " + block);
0517: }
0518:
0519: final ListIterator iter = stmts.listIterator();
0520:
0521: while (iter.hasNext()) {
0522: final Stmt s = (Stmt) iter.next();
0523:
0524: if (!(s instanceof LabelStmt)) {
0525: iter.previous();
0526: iter.add(stmt);
0527: stmt.setParent(this );
0528: return;
0529: }
0530: }
0531:
0532: appendStmt(stmt);
0533: }
0534:
0535: /**
0536: * When we build the expression tree, there may be items left over on the
0537: * operand stack. We want to save these items. If USE_STACK is true, then we
0538: * place these items into stack variables. If USE_STACK is false, then we
0539: * place the items into local variables.
0540: */
0541: private void saveStack() {
0542: int height = 0;
0543:
0544: for (int i = 0; i < stack.size(); i++) {
0545: final Expr expr = stack.get(i);
0546:
0547: if (Tree.USE_STACK) {
0548: // Save to a stack variable only if we'll create a new
0549: // variable there.
0550: if (!(expr instanceof StackExpr)
0551: || (((StackExpr) expr).index() != height)) {
0552:
0553: final StackExpr target = new StackExpr(height, expr
0554: .type());
0555:
0556: // Make a new statement to store the expression that was
0557: // part of the stack into memory.
0558: final Stmt store = new ExprStmt(new StoreExpr(
0559: target, expr, expr.type()));
0560:
0561: appendStmt(store);
0562:
0563: final StackExpr copy = (StackExpr) target.clone();
0564: copy.setDef(null);
0565: stack.set(i, copy);
0566: }
0567:
0568: } else {
0569: if (!(expr instanceof LocalExpr)
0570: || !((LocalExpr) expr).fromStack()
0571: || (((LocalExpr) expr).index() != height)) {
0572:
0573: final LocalExpr target = newStackLocal(nextIndex++,
0574: expr.type());
0575:
0576: final Stmt store = new ExprStmt(new StoreExpr(
0577: target, expr, expr.type()));
0578:
0579: appendStmt(store);
0580:
0581: final LocalExpr copy = (LocalExpr) target.clone();
0582: copy.setDef(null);
0583: stack.set(i, copy);
0584: }
0585: }
0586:
0587: height += expr.type().stackHeight();
0588: }
0589: }
0590:
0591: /**
0592: * Add a statement to this Tree statement list and specify that this is the
0593: * statement's parent.
0594: */
0595: private void appendStmt(final Stmt stmt) {
0596: if (Tree.DEBUG) {
0597: System.out.println(" append: " + stmt);
0598: }
0599:
0600: stmt.setParent(this );
0601: stmts.add(stmt);
0602: }
0603:
0604: /**
0605: * Save the contents of the stack and add stmt to the statement list.
0606: *
0607: * @param stmt
0608: * A statement to add to the statement list.
0609: */
0610: public void addStmt(final Stmt stmt) {
0611: saveStack();
0612: appendStmt(stmt);
0613: }
0614:
0615: /**
0616: * Adds a statement to the statement list before the last jump statement. It
0617: * is assumed that the last statement in the statement list is a jump
0618: * statement.
0619: *
0620: * @see JumpStmt
0621: */
0622: public void addStmtBeforeJump(final Stmt stmt) {
0623: final Stmt last = lastStmt();
0624: Assert.isTrue(last instanceof JumpStmt, "Last statement of "
0625: + block + " is " + last + ", not a jump");
0626: addStmtBefore(stmt, last);
0627: }
0628:
0629: /**
0630: * Throw a new ClassFormatException with information about method and class
0631: * that this basic block is in.
0632: *
0633: * @param msg
0634: * String description of the exception.
0635: *
0636: * @see ClassFormatException
0637: */
0638: private void throwClassFormatException(final String msg) {
0639: final MethodEditor method = block.graph().method();
0640:
0641: throw new ClassFormatException("Method "
0642: + method.declaringClass().type().className() + "."
0643: + method.name() + " " + method.type() + ": " + msg);
0644: }
0645:
0646: /**
0647: * The last instruction we saw. addInst(Instruction) needs this information.
0648: */
0649: Instruction last = null;
0650:
0651: /**
0652: * Adds an instruction that jumps to another basic block.
0653: *
0654: * @param inst
0655: * The instruction to add.
0656: * @param next
0657: * The basic block after the jump. Remember that a jump ends a
0658: * basic block.
0659: *
0660: * @see Instruction#isJsr
0661: * @see Instruction#isConditionalJump
0662: */
0663: public void addInstruction(final Instruction inst, final Block next) {
0664: Assert.isTrue(inst.isJsr() || inst.isConditionalJump(),
0665: "Wrong addInstruction called with " + inst);
0666: Assert.isTrue(next != null, "Null next block for " + inst);
0667:
0668: this .next = next;
0669: addInst(inst);
0670: }
0671:
0672: /**
0673: * Adds an instruction that does not change the control flow (a normal
0674: * instruction).
0675: *
0676: * @param inst
0677: * Instruction to add.
0678: */
0679: public void addInstruction(final Instruction inst) {
0680: Assert.isTrue(!inst.isJsr() && !inst.isConditionalJump(),
0681: "Wrong addInstruction called with " + inst);
0682:
0683: this .next = null;
0684: addInst(inst);
0685: }
0686:
0687: /**
0688: * Add an instruction such as <i>ret</i> or <i>astore</i> that may involve
0689: * a subroutine.
0690: *
0691: * @param inst
0692: * Instruction to add.
0693: * @param sub
0694: * Subroutine in which inst resides. The <i>ret</i> instruction
0695: * always resides in a Subroutine. An <i>astore</i> may store
0696: * the return address of a subroutine in a local variable.
0697: *
0698: * @see Instruction#isRet
0699: */
0700: public void addInstruction(final Instruction inst,
0701: final Subroutine sub) {
0702: Assert.isTrue(inst.isRet()
0703: || (inst.opcodeClass() == Opcode.opcx_astore),
0704: "Wrong addInstruction called with " + inst);
0705:
0706: this .sub = sub;
0707: this .next = null;
0708: addInst(inst);
0709: }
0710:
0711: /**
0712: * Add a label to the statement list. A label is inserted before a dup
0713: * statement, but after any other statement.
0714: *
0715: * @param label
0716: * Label to add.
0717: */
0718: public void addLabel(final Label label) {
0719: // Add before a dup, but after any other instruction.
0720: if (last != null) {
0721: switch (last.opcodeClass()) {
0722: case opcx_dup:
0723: case opcx_dup2:
0724: case opcx_dup_x1:
0725: case opcx_dup2_x1:
0726: case opcx_dup_x2:
0727: case opcx_dup2_x2:
0728: break;
0729: default:
0730: addInst(last, false);
0731: last = null;
0732: break;
0733: }
0734: }
0735:
0736: addStmt(new LabelStmt(label));
0737: }
0738:
0739: /**
0740: * Private method that adds an instruction to the Tree. The visit method of
0741: * the instruction is called with this tree as the visitor. The instruction,
0742: * in turn, calls the appropriate method of this for adding the instruction
0743: * to the statement list.
0744: *
0745: * @param inst
0746: * The <tt>Instruction</tt> to add to the <tt>Tree</tt>
0747: * @param saveValue
0748: * Do we save expressions on the operand stack to stack variables
0749: * or local variables.
0750: */
0751: private void addInst(final Instruction inst, final boolean saveValue) {
0752: if (Tree.DEBUG) {
0753: // Print the contents of the stack
0754: for (int i = 0; i < stack.size(); i++) {
0755: final Expr exp = stack.peek(i);
0756: System.out.println((i > 0 ? "-" + i : " " + i) + ": "
0757: + exp);
0758: }
0759: }
0760:
0761: if (Tree.DEBUG) {
0762: System.out
0763: .println(" add " + inst + " save=" + saveValue);
0764: }
0765:
0766: try {
0767: this .saveValue = saveValue;
0768:
0769: if (Tree.FLATTEN) {
0770: saveStack();
0771: }
0772:
0773: inst.visit(this );
0774:
0775: } catch (final EmptyStackException e) {
0776: throwClassFormatException("Empty operand stack at " + inst);
0777: return;
0778: }
0779: }
0780:
0781: /**
0782: * Private method that adds an instruction to the tree. Before dispatching
0783: * the addition off to addInst(Instruction, boolean), it optimizes(?) dup
0784: * instructions as outlined below:
0785: */
0786: // (S0, S1) := dup(X)
0787: // L := S1 --> use (L := X)
0788: // use S0
0789: //
0790: // (S0, S1, S2) := dup_x1(X, Y)
0791: // S1.f := S2 --> use (X.f := Y)
0792: // use S0
0793: //
0794: // (S0, S1, S2, S3) := dup_x2(X, Y, Z)
0795: // S1[S2] := S3 --> use (X[Y] := Z)
0796: // use S0
0797: //
0798: private void addInst(final Instruction inst) {
0799: // Build the tree, trying to convert dup-stores
0800:
0801: if (last == null) {
0802: last = inst;
0803:
0804: } else {
0805: switch (last.opcodeClass()) {
0806: case opcx_dup:
0807: switch (inst.opcodeClass()) {
0808: case opcx_astore:
0809: case opcx_fstore:
0810: case opcx_istore:
0811: case opcx_putstatic:
0812: addInst(inst, true);
0813: last = null;
0814: break;
0815: }
0816: break;
0817: case opcx_dup2:
0818: switch (inst.opcodeClass()) {
0819: case opcx_dstore:
0820: case opcx_lstore:
0821: case opcx_putstatic:
0822: addInst(inst, true);
0823: last = null;
0824: break;
0825: }
0826: break;
0827: case opcx_dup_x1:
0828: switch (inst.opcodeClass()) {
0829: case opcx_putfield:
0830: case opcx_putfield_nowb:
0831: addInst(inst, true);
0832: last = null;
0833: break;
0834: }
0835: break;
0836: case opcx_dup2_x1:
0837: switch (inst.opcodeClass()) {
0838: case opcx_putfield:
0839: case opcx_putfield_nowb:
0840: addInst(inst, true);
0841: last = null;
0842: break;
0843: }
0844: break;
0845: case opcx_dup_x2:
0846: switch (inst.opcodeClass()) {
0847: case opcx_aastore:
0848: case opcx_bastore:
0849: case opcx_castore:
0850: case opcx_fastore:
0851: case opcx_iastore:
0852: case opcx_sastore:
0853: addInst(inst, true);
0854: last = null;
0855: break;
0856: }
0857: break;
0858: case opcx_dup2_x2:
0859: switch (inst.opcodeClass()) {
0860: case opcx_dastore:
0861: case opcx_lastore:
0862: addInst(inst, true);
0863: last = null;
0864: break;
0865: }
0866: break;
0867: }
0868:
0869: if (last != null) {
0870: addInst(last, false);
0871: last = inst;
0872: }
0873: }
0874:
0875: // We should have dealt with the old last instruction
0876: Assert.isTrue((last == null) || (last == inst));
0877:
0878: if (inst.isJump() || inst.isSwitch() || inst.isThrow()
0879: || inst.isReturn() || inst.isJsr() || inst.isRet()) {
0880: addInst(inst, false);
0881: last = null;
0882: }
0883: }
0884:
0885: /**
0886: * Returns a new StackExpr for the top of the operand stack.
0887: */
0888: public StackExpr newStack(final Type type) {
0889: return new StackExpr(Tree.stackpos++, type);
0890: }
0891:
0892: /**
0893: * Returns a new LocalExpr that represents an element of the stack. They are
0894: * created when the USE_STACK flag is not set.
0895: *
0896: * @param index
0897: * Stack index of variable.
0898: * @param type
0899: * The type of the LocalExpr
0900: */
0901: public LocalExpr newStackLocal(final int index, final Type type) {
0902: if (index >= nextIndex) {
0903: nextIndex = index + 1;
0904: }
0905: return new LocalExpr(index, true, type);
0906: }
0907:
0908: /**
0909: * Returns a new LocalExpr that is not allocated on the stack.
0910: *
0911: * @param index
0912: * Stack index of variable.
0913: * @param type
0914: * The type of the LocalExpr
0915: */
0916: public LocalExpr newLocal(final int index, final Type type) {
0917: return new LocalExpr(index, false, type);
0918: }
0919:
0920: /**
0921: * Returns a local variable (<tt>LocalExpr</tt>) located in this method.
0922: *
0923: * @param type
0924: * The type of the new LocalExpr.
0925: */
0926: public LocalExpr newLocal(final Type type) {
0927: final LocalVariable var = block.graph().method().newLocal(type);
0928: return new LocalExpr(var.index(), type);
0929: }
0930:
0931: /**
0932: * Returns a String representation of this Tree.
0933: */
0934: public String toString() {
0935: String x = "(TREE " + block + " stack=";
0936:
0937: for (int i = 0; i < stack.size(); i++) {
0938: final Expr expr = stack.get(i);
0939: x += expr.type().shortName();
0940: }
0941:
0942: return x + ")";
0943: }
0944:
0945: /**
0946: * Adds no statements to the statement list.
0947: */
0948: public void visit_nop(final Instruction inst) {
0949: }
0950:
0951: /**
0952: * Pushes a ConstantExpr onto the operand stack.
0953: *
0954: * @see ConstantExpr
0955: */
0956: public void visit_ldc(final Instruction inst) {
0957: final Object value = inst.operand();
0958: Type type;
0959:
0960: if (value == null) {
0961: type = Type.NULL;
0962: } else if (value instanceof Integer) {
0963: type = Type.INTEGER;
0964: } else if (value instanceof Long) {
0965: type = Type.LONG;
0966: } else if (value instanceof Float) {
0967: type = Type.FLOAT;
0968: } else if (value instanceof Double) {
0969: type = Type.DOUBLE;
0970: } else if (value instanceof String) {
0971: type = Type.STRING;
0972: }
0973: // FIXME this won't work - check usages
0974: else if (value instanceof Type) {
0975: type = Type.CLASS;
0976: } else {
0977: throwClassFormatException("Illegal constant type: "
0978: + value.getClass().getName() + ": " + value);
0979: return;
0980: }
0981:
0982: final Expr top = new ConstantExpr(value, type);
0983: stack.push(top);
0984: }
0985:
0986: /**
0987: * All <tt>visit_<i>x</i>load</tt> push a LocalExpr onto the operand
0988: * stack.
0989: *
0990: * @see LocalExpr
0991: */
0992: public void visit_iload(final Instruction inst) {
0993: final LocalVariable operand = (LocalVariable) inst.operand();
0994: final Expr top = new LocalExpr(operand.index(), Type.INTEGER);
0995: stack.push(top);
0996: }
0997:
0998: public void visit_lload(final Instruction inst) {
0999: final LocalVariable operand = (LocalVariable) inst.operand();
1000: final Expr top = new LocalExpr(operand.index(), Type.LONG);
1001: stack.push(top);
1002: }
1003:
1004: public void visit_fload(final Instruction inst) {
1005: final LocalVariable operand = (LocalVariable) inst.operand();
1006: final Expr top = new LocalExpr(operand.index(), Type.FLOAT);
1007: stack.push(top);
1008: }
1009:
1010: public void visit_dload(final Instruction inst) {
1011: final LocalVariable operand = (LocalVariable) inst.operand();
1012: final Expr top = new LocalExpr(operand.index(), Type.DOUBLE);
1013: stack.push(top);
1014: }
1015:
1016: public void visit_aload(final Instruction inst) {
1017: final LocalVariable operand = (LocalVariable) inst.operand();
1018: final Expr top = new LocalExpr(operand.index(), Type.OBJECT);
1019: stack.push(top);
1020:
1021: db(" aload: " + top);
1022: }
1023:
1024: /**
1025: * All <tt>visit_<i>x</i>aload</tt> push an ArrayRefExpr onto the
1026: * operand stack.
1027: */
1028: public void visit_iaload(final Instruction inst) {
1029: final Expr index = stack.pop(Type.INTEGER);
1030: final Expr array = stack.pop(Type.INTEGER.arrayType());
1031: final Expr top = new ArrayRefExpr(array, index, Type.INTEGER,
1032: Type.INTEGER);
1033: stack.push(top);
1034: }
1035:
1036: public void visit_laload(final Instruction inst) {
1037: final Expr index = stack.pop(Type.INTEGER);
1038: final Expr array = stack.pop(Type.LONG.arrayType());
1039: final Expr top = new ArrayRefExpr(array, index, Type.LONG,
1040: Type.LONG);
1041: stack.push(top);
1042: }
1043:
1044: public void visit_faload(final Instruction inst) {
1045: final Expr index = stack.pop(Type.INTEGER);
1046: final Expr array = stack.pop(Type.FLOAT.arrayType());
1047: final Expr top = new ArrayRefExpr(array, index, Type.FLOAT,
1048: Type.FLOAT);
1049: stack.push(top);
1050: }
1051:
1052: public void visit_daload(final Instruction inst) {
1053: final Expr index = stack.pop(Type.INTEGER);
1054: final Expr array = stack.pop(Type.DOUBLE.arrayType());
1055: final Expr top = new ArrayRefExpr(array, index, Type.DOUBLE,
1056: Type.DOUBLE);
1057: stack.push(top);
1058: }
1059:
1060: public void visit_aaload(final Instruction inst) {
1061: final Expr index = stack.pop(Type.INTEGER);
1062: final Expr array = stack.pop(Type.OBJECT.arrayType());
1063: final Expr top = new ArrayRefExpr(array, index, Type.OBJECT,
1064: Type.OBJECT);
1065: stack.push(top);
1066: }
1067:
1068: public void visit_baload(final Instruction inst) {
1069: final Expr index = stack.pop(Type.INTEGER);
1070: final Expr array = stack.pop(Type.BYTE.arrayType());
1071: final Expr top = new ArrayRefExpr(array, index, Type.BYTE,
1072: Type.BYTE);
1073: stack.push(top);
1074: }
1075:
1076: public void visit_caload(final Instruction inst) {
1077: final Expr index = stack.pop(Type.INTEGER);
1078: final Expr array = stack.pop(Type.CHARACTER.arrayType());
1079: final Expr top = new ArrayRefExpr(array, index, Type.CHARACTER,
1080: Type.CHARACTER);
1081: stack.push(top);
1082: }
1083:
1084: public void visit_saload(final Instruction inst) {
1085: final Expr index = stack.pop(Type.INTEGER);
1086: final Expr array = stack.pop(Type.SHORT.arrayType());
1087: final Expr top = new ArrayRefExpr(array, index, Type.SHORT,
1088: Type.SHORT);
1089: stack.push(top);
1090: }
1091:
1092: /**
1093: * Deals with an expression that stores a value. It either pushes it on the
1094: * operand stack or adds a statement depending on the value of saveValue.
1095: *
1096: * @param target
1097: * The location to where we are storing the value.
1098: * @param expr
1099: * The expression whose value we are storing.
1100: */
1101: private void addStore(final MemExpr target, final Expr expr) {
1102: if (saveValue) {
1103: stack.push(new StoreExpr(target, expr, expr.type()));
1104:
1105: } else {
1106: addStmt(new ExprStmt(new StoreExpr(target, expr, expr
1107: .type())));
1108: }
1109: }
1110:
1111: /**
1112: * All <tt>visit_<i>x</i>store</tt> add a LocalExpr statement to the
1113: * statement list.
1114: */
1115: public void visit_istore(final Instruction inst) {
1116: final LocalVariable operand = (LocalVariable) inst.operand();
1117: final Expr expr = stack.pop(Type.INTEGER);
1118: final LocalExpr target = new LocalExpr(operand.index(), expr
1119: .type());
1120: addStore(target, expr);
1121: }
1122:
1123: public void visit_lstore(final Instruction inst) {
1124: final LocalVariable operand = (LocalVariable) inst.operand();
1125: final Expr expr = stack.pop(Type.LONG);
1126: final LocalExpr target = new LocalExpr(operand.index(), expr
1127: .type());
1128: addStore(target, expr);
1129: }
1130:
1131: public void visit_fstore(final Instruction inst) {
1132: final LocalVariable operand = (LocalVariable) inst.operand();
1133: final Expr expr = stack.pop(Type.FLOAT);
1134: final LocalExpr target = new LocalExpr(operand.index(), expr
1135: .type());
1136: addStore(target, expr);
1137: }
1138:
1139: public void visit_dstore(final Instruction inst) {
1140: final LocalVariable operand = (LocalVariable) inst.operand();
1141: final Expr expr = stack.pop(Type.DOUBLE);
1142: final LocalExpr target = new LocalExpr(operand.index(), expr
1143: .type());
1144: addStore(target, expr);
1145: }
1146:
1147: /**
1148: * Visit an <i>astore</i> instruction. If the type of the operand to the
1149: * instruction is an address add an AddressStoreStmt to the tree, else add a
1150: * StoreStmt to the tree consisting of a LocalExpr and the top Expr on the
1151: * operand stack.
1152: *
1153: * @see AddressStoreStmt
1154: * @see LocalExpr
1155: * @see StoreExpr
1156: */
1157: public void visit_astore(final Instruction inst) {
1158: final LocalVariable operand = (LocalVariable) inst.operand();
1159:
1160: Expr expr = stack.peek();
1161:
1162: if (expr.type().isAddress()) {
1163: Assert.isTrue(sub != null);
1164: Assert.isTrue(!saveValue);
1165: expr = stack.pop(Type.ADDRESS);
1166: sub.setReturnAddress(operand);
1167: addStmt(new AddressStoreStmt(sub));
1168: } else {
1169: expr = stack.pop(Type.OBJECT);
1170: final LocalExpr target = new LocalExpr(operand.index(),
1171: expr.type());
1172: addStore(target, expr);
1173: }
1174: }
1175:
1176: public void visit_iastore(final Instruction inst) {
1177: final Expr value = stack.pop(Type.INTEGER);
1178: final Expr index = stack.pop(Type.INTEGER);
1179: final Expr array = stack.pop(Type.INTEGER.arrayType());
1180: final ArrayRefExpr target = new ArrayRefExpr(array, index,
1181: Type.INTEGER, Type.INTEGER);
1182: addStore(target, value);
1183: }
1184:
1185: public void visit_lastore(final Instruction inst) {
1186: final Expr value = stack.pop(Type.LONG);
1187: final Expr index = stack.pop(Type.INTEGER);
1188: final Expr array = stack.pop(Type.LONG.arrayType());
1189: final ArrayRefExpr target = new ArrayRefExpr(array, index,
1190: Type.LONG, Type.LONG);
1191: addStore(target, value);
1192: }
1193:
1194: public void visit_fastore(final Instruction inst) {
1195: final Expr value = stack.pop(Type.FLOAT);
1196: final Expr index = stack.pop(Type.INTEGER);
1197: final Expr array = stack.pop(Type.FLOAT.arrayType());
1198: final ArrayRefExpr target = new ArrayRefExpr(array, index,
1199: Type.FLOAT, Type.FLOAT);
1200: addStore(target, value);
1201: }
1202:
1203: public void visit_dastore(final Instruction inst) {
1204: final Expr value = stack.pop(Type.DOUBLE);
1205: final Expr index = stack.pop(Type.INTEGER);
1206: final Expr array = stack.pop(Type.DOUBLE.arrayType());
1207: final ArrayRefExpr target = new ArrayRefExpr(array, index,
1208: Type.DOUBLE, Type.DOUBLE);
1209: addStore(target, value);
1210: }
1211:
1212: public void visit_aastore(final Instruction inst) {
1213: final Expr value = stack.pop(Type.OBJECT);
1214: final Expr index = stack.pop(Type.INTEGER);
1215: final Expr array = stack.pop(Type.OBJECT.arrayType());
1216: final ArrayRefExpr target = new ArrayRefExpr(array, index,
1217: Type.OBJECT, Type.OBJECT);
1218: addStore(target, value);
1219: }
1220:
1221: public void visit_bastore(final Instruction inst) {
1222: final Expr value = stack.pop(Type.BYTE);
1223: final Expr index = stack.pop(Type.INTEGER);
1224: final Expr array = stack.pop(Type.BYTE.arrayType());
1225: final ArrayRefExpr target = new ArrayRefExpr(array, index,
1226: Type.BYTE, Type.BYTE);
1227: addStore(target, value);
1228: }
1229:
1230: public void visit_castore(final Instruction inst) {
1231: final Expr value = stack.pop(Type.CHARACTER);
1232: final Expr index = stack.pop(Type.INTEGER);
1233: final Expr array = stack.pop(Type.CHARACTER.arrayType());
1234: final ArrayRefExpr target = new ArrayRefExpr(array, index,
1235: Type.CHARACTER, Type.CHARACTER);
1236: addStore(target, value);
1237: }
1238:
1239: public void visit_sastore(final Instruction inst) {
1240: final Expr value = stack.pop(Type.SHORT);
1241: final Expr index = stack.pop(Type.INTEGER);
1242: final Expr array = stack.pop(Type.SHORT.arrayType());
1243: final ArrayRefExpr target = new ArrayRefExpr(array, index,
1244: Type.SHORT, Type.SHORT);
1245: addStore(target, value);
1246: }
1247:
1248: /**
1249: * Pop the expression off the top of the stack and add it as an ExprStmt to
1250: * the statement list.
1251: *
1252: * @see ExprStmt
1253: */
1254: public void visit_pop(final Instruction inst) {
1255: final Expr expr = stack.pop1();
1256: addStmt(new ExprStmt(expr));
1257: }
1258:
1259: public void visit_pop2(final Instruction inst) {
1260: final Expr[] expr = stack.pop2();
1261:
1262: if (expr.length == 1) {
1263: addStmt(new ExprStmt(expr[0]));
1264: } else {
1265: addStmt(new ExprStmt(expr[0]));
1266: addStmt(new ExprStmt(expr[1]));
1267: }
1268: }
1269:
1270: /**
1271: * When processing the <i>dup</i> instructions one of two situations can
1272: * occur. If the <tt>USE_STACK</tt> flag is set, then a StackManipStmt is
1273: * created to represent the transformation that the <i>dup</i> instruction
1274: * performs on the stack. If the <tt>USE_STACK</tt> flag is not set, then
1275: * the transformation is simulated by creating new local variables
1276: * containing the appropriate element of the stack.
1277: *
1278: * @see LocalExpr
1279: * @see StackExpr
1280: * @see StackManipStmt
1281: */
1282: public void visit_dup(final Instruction inst) {
1283: // 0 -> 0 0
1284:
1285: db(" dup");
1286:
1287: if (Tree.USE_STACK) {
1288: saveStack();
1289:
1290: final StackExpr s0 = (StackExpr) stack.pop1();
1291:
1292: final StackExpr[] s = new StackExpr[] { s0 };
1293: manip(s, new int[] { 0, 0 }, StackManipStmt.DUP);
1294:
1295: } else {
1296: final Expr s0 = stack.pop1();
1297:
1298: final LocalExpr t0 = newStackLocal(stack.height(), s0
1299: .type());
1300:
1301: db(" s0: " + s0);
1302: db(" t0: " + t0);
1303:
1304: if (!t0.equalsExpr(s0)) {
1305: db(" t0 <- s0");
1306: addStore(t0, s0);
1307: }
1308:
1309: Expr copy = (Expr) t0.clone();
1310: copy.setDef(null);
1311: stack.push(copy);
1312:
1313: copy = (Expr) t0.clone();
1314: copy.setDef(null);
1315: stack.push(copy);
1316: }
1317: }
1318:
1319: public void visit_dup_x1(final Instruction inst) {
1320: // 0 1 -> 1 0 1
1321:
1322: if (Tree.USE_STACK) {
1323: saveStack();
1324:
1325: final StackExpr s1 = (StackExpr) stack.pop1();
1326: final StackExpr s0 = (StackExpr) stack.pop1();
1327:
1328: final StackExpr[] s = new StackExpr[] { s0, s1 };
1329: manip(s, new int[] { 1, 0, 1 }, StackManipStmt.DUP_X1);
1330:
1331: } else {
1332: final Expr s1 = stack.pop1();
1333: final Expr s0 = stack.pop1();
1334:
1335: final LocalExpr t0 = newStackLocal(stack.height(), s0
1336: .type());
1337: final LocalExpr t1 = newStackLocal(stack.height() + 1, s1
1338: .type());
1339:
1340: if (!t0.equalsExpr(s0)) {
1341: addStore(t0, s0);
1342: }
1343:
1344: if (!t1.equalsExpr(s1)) {
1345: addStore(t1, s1);
1346: }
1347:
1348: Expr copy = (Expr) t1.clone();
1349: copy.setDef(null);
1350: stack.push(copy);
1351:
1352: copy = (Expr) t0.clone();
1353: copy.setDef(null);
1354: stack.push(copy);
1355:
1356: copy = (Expr) t1.clone();
1357: copy.setDef(null);
1358: stack.push(copy);
1359: }
1360: }
1361:
1362: public void visit_dup_x2(final Instruction inst) {
1363: // 0 1 2 -> 2 0 1 2
1364: // 0-1 2 -> 2 0-1 2
1365:
1366: db(" dup_x2");
1367:
1368: if (Tree.USE_STACK) {
1369: saveStack();
1370:
1371: final StackExpr s2 = (StackExpr) stack.pop1();
1372: final Expr[] s01 = stack.pop2();
1373:
1374: if (s01.length == 2) {
1375: // 0 1 2 -> 2 0 1 2
1376: final StackExpr[] s = new StackExpr[] {
1377: (StackExpr) s01[0], (StackExpr) s01[1], s2 };
1378: manip(s, new int[] { 2, 0, 1, 2 },
1379: StackManipStmt.DUP_X2);
1380: } else {
1381: // 0-1 2 -> 2 0-1 2
1382: final StackExpr[] s = new StackExpr[] {
1383: (StackExpr) s01[0], s2 };
1384: manip(s, new int[] { 1, 0, 1 }, StackManipStmt.DUP_X2);
1385: }
1386:
1387: } else {
1388: final Expr s2 = stack.pop1();
1389: final Expr[] s01 = stack.pop2();
1390:
1391: db(" s2: " + s2);
1392: db(" s01: " + s01[0]
1393: + (s01.length > 1 ? " " + s01[1] : ""));
1394:
1395: if (s01.length == 2) {
1396: // 0 1 2 -> 2 0 1 2
1397: final LocalExpr t0 = newStackLocal(stack.height(),
1398: s01[0].type());
1399: final LocalExpr t1 = newStackLocal(stack.height() + 1,
1400: s01[1].type());
1401: final LocalExpr t2 = newStackLocal(stack.height() + 2,
1402: s2.type());
1403:
1404: db(" t0: " + t0);
1405: db(" t1: " + t1);
1406: db(" t2: " + t2);
1407:
1408: if (!t0.equalsExpr(s01[0])) {
1409: db(" t0 <- s01[0]");
1410: addStore(t0, s01[0]);
1411: }
1412:
1413: if (!t1.equalsExpr(s01[1])) {
1414: db(" t1 <- s01[1]");
1415: addStore(t1, s01[1]);
1416: }
1417:
1418: if (!t2.equalsExpr(s2)) {
1419: db(" t2 <- s2");
1420: addStore(t2, s2);
1421: }
1422:
1423: Expr copy = (Expr) t2.clone();
1424: copy.setDef(null);
1425: stack.push(copy);
1426:
1427: copy = (Expr) t0.clone();
1428: copy.setDef(null);
1429: stack.push(copy);
1430:
1431: copy = (Expr) t1.clone();
1432: copy.setDef(null);
1433: stack.push(copy);
1434:
1435: copy = (Expr) t2.clone();
1436: copy.setDef(null);
1437: stack.push(copy);
1438:
1439: } else {
1440: // 0-1 2 -> 2 0-1 2
1441: final LocalExpr t0 = newStackLocal(stack.height(),
1442: s01[0].type());
1443: final LocalExpr t2 = newStackLocal(stack.height() + 2,
1444: s2.type());
1445:
1446: if (!t0.equalsExpr(s01[0])) {
1447: addStore(t0, s01[0]);
1448: }
1449:
1450: if (!t2.equalsExpr(s2)) {
1451: addStore(t2, s2);
1452: }
1453:
1454: Expr copy = (Expr) t2.clone();
1455: copy.setDef(null);
1456: stack.push(copy);
1457:
1458: copy = (Expr) t0.clone();
1459: copy.setDef(null);
1460: stack.push(copy);
1461:
1462: copy = (Expr) t2.clone();
1463: copy.setDef(null);
1464: stack.push(copy);
1465: }
1466: }
1467: }
1468:
1469: public void visit_dup2(final Instruction inst) {
1470: // 0 1 -> 0 1 0 1
1471: // 0-1 -> 0-1 0-1
1472:
1473: if (Tree.USE_STACK) {
1474: saveStack();
1475:
1476: final Expr[] s01 = stack.pop2();
1477:
1478: if (s01.length == 1) {
1479: // 0-1 -> 0-1 0-1
1480: final StackExpr[] s = new StackExpr[] { (StackExpr) s01[0] };
1481: manip(s, new int[] { 0, 0 }, StackManipStmt.DUP2);
1482: } else {
1483: // 0 1 -> 0 1 0 1
1484:
1485: Assert.isTrue(s01.length == 2);
1486:
1487: final StackExpr[] s = new StackExpr[] {
1488: (StackExpr) s01[0], (StackExpr) s01[1] };
1489: manip(s, new int[] { 0, 1, 0, 1 }, StackManipStmt.DUP2);
1490: }
1491: } else {
1492: final Expr[] s01 = stack.pop2();
1493:
1494: if (s01.length == 1) {
1495: // 0-1 -> 0-1 0-1
1496: final LocalExpr t0 = newStackLocal(stack.height(),
1497: s01[0].type());
1498:
1499: if (!t0.equalsExpr(s01[0])) {
1500: addStore(t0, s01[0]);
1501: }
1502:
1503: Expr copy = (Expr) t0.clone();
1504: copy.setDef(null);
1505: stack.push(copy);
1506:
1507: copy = (Expr) t0.clone();
1508: copy.setDef(null);
1509: stack.push(copy);
1510: } else {
1511: // 0 1 -> 0 1 0 1
1512: final LocalExpr t0 = newStackLocal(stack.height(),
1513: s01[0].type());
1514: final LocalExpr t1 = newStackLocal(stack.height() + 1,
1515: s01[1].type());
1516:
1517: if (!t0.equalsExpr(s01[0])) {
1518: addStore(t0, s01[0]);
1519: }
1520:
1521: if (!t1.equalsExpr(s01[1])) {
1522: addStore(t1, s01[1]);
1523: }
1524:
1525: Expr copy = (Expr) t0.clone();
1526: copy.setDef(null);
1527: stack.push(copy);
1528:
1529: copy = (Expr) t1.clone();
1530: copy.setDef(null);
1531: stack.push(copy);
1532:
1533: copy = (Expr) t0.clone();
1534: copy.setDef(null);
1535: stack.push(copy);
1536:
1537: copy = (Expr) t1.clone();
1538: copy.setDef(null);
1539: stack.push(copy);
1540: }
1541: }
1542: }
1543:
1544: public void visit_dup2_x1(final Instruction inst) {
1545: // 0 1 2 -> 1 2 0 1 2
1546: // 0 1-2 -> 1-2 0 1-2
1547:
1548: if (Tree.USE_STACK) {
1549: saveStack();
1550:
1551: final Expr[] s12 = stack.pop2();
1552: final StackExpr s0 = (StackExpr) stack.pop1();
1553:
1554: if (s12.length == 2) {
1555: // 0 1 2 -> 1 2 0 1 2
1556: final StackExpr[] s = new StackExpr[] { s0,
1557: (StackExpr) s12[0], (StackExpr) s12[1] };
1558: manip(s, new int[] { 1, 2, 0, 1, 2 },
1559: StackManipStmt.DUP2_X1);
1560: } else {
1561: // 0 1-2 -> 1-2 0 1-2
1562: final StackExpr[] s = new StackExpr[] { s0,
1563: (StackExpr) s12[0] };
1564: manip(s, new int[] { 1, 0, 1 }, StackManipStmt.DUP2_X1);
1565: }
1566: } else {
1567: final Expr[] s12 = stack.pop2();
1568: final StackExpr s0 = (StackExpr) stack.pop1();
1569:
1570: if (s12.length == 2) {
1571: // 0 1 2 -> 1 2 0 1 2
1572: final LocalExpr t0 = newStackLocal(stack.height(), s0
1573: .type());
1574: final LocalExpr t1 = newStackLocal(stack.height() + 1,
1575: s12[0].type());
1576: final LocalExpr t2 = newStackLocal(stack.height() + 2,
1577: s12[1].type());
1578:
1579: if (!t0.equalsExpr(s0)) {
1580: addStore(t0, s0);
1581: }
1582:
1583: if (!t1.equalsExpr(s12[0])) {
1584: addStore(t1, s12[0]);
1585: }
1586:
1587: if (!t2.equalsExpr(s12[1])) {
1588: addStore(t2, s12[1]);
1589: }
1590:
1591: Expr copy = (Expr) t1.clone();
1592: copy.setDef(null);
1593: stack.push(copy);
1594:
1595: copy = (Expr) t2.clone();
1596: copy.setDef(null);
1597: stack.push(copy);
1598:
1599: copy = (Expr) t0.clone();
1600: copy.setDef(null);
1601: stack.push(copy);
1602:
1603: copy = (Expr) t1.clone();
1604: copy.setDef(null);
1605: stack.push(copy);
1606:
1607: copy = (Expr) t2.clone();
1608: copy.setDef(null);
1609: stack.push(copy);
1610: } else {
1611: // 0 1-2 -> 1-2 0 1-2
1612: final LocalExpr t0 = newStackLocal(stack.height(), s0
1613: .type());
1614: final LocalExpr t1 = newStackLocal(stack.height() + 1,
1615: s12[0].type());
1616:
1617: if (!t0.equalsExpr(s0)) {
1618: addStore(t0, s0);
1619: }
1620:
1621: if (!t1.equalsExpr(s12[0])) {
1622: addStore(t1, s12[0]);
1623: }
1624:
1625: Expr copy = (Expr) t1.clone();
1626: copy.setDef(null);
1627: stack.push(copy);
1628:
1629: copy = (Expr) t0.clone();
1630: copy.setDef(null);
1631: stack.push(copy);
1632:
1633: copy = (Expr) t1.clone();
1634: copy.setDef(null);
1635: stack.push(copy);
1636: }
1637: }
1638: }
1639:
1640: public void visit_dup2_x2(final Instruction inst) {
1641: // 0 1 2 3 -> 2 3 0 1 2 3
1642: // 0 1 2-3 -> 2-3 0 1 2-3
1643: // 0-1 2 3 -> 2 3 0-1 2 3
1644: // 0-1 2-3 -> 2-3 0-1 2-3
1645:
1646: if (Tree.USE_STACK) {
1647: saveStack();
1648:
1649: final Expr[] s23 = stack.pop2();
1650: final Expr[] s01 = stack.pop2();
1651:
1652: if ((s01.length == 2) && (s23.length == 2)) {
1653: // 0 1 2 3 -> 2 3 0 1 2 3
1654: final StackExpr[] s = new StackExpr[] {
1655: (StackExpr) s01[0], (StackExpr) s01[1],
1656: (StackExpr) s23[0], (StackExpr) s23[1] };
1657: manip(s, new int[] { 2, 3, 0, 1, 2, 3 },
1658: StackManipStmt.DUP2_X2);
1659: } else if ((s01.length == 2) && (s23.length == 1)) {
1660: // 0 1 2-3 -> 2-3 0 1 2-3
1661: final StackExpr[] s = new StackExpr[] {
1662: (StackExpr) s01[0], (StackExpr) s01[1],
1663: (StackExpr) s23[0] };
1664: manip(s, new int[] { 2, 0, 1, 2 },
1665: StackManipStmt.DUP2_X2);
1666: } else if ((s01.length == 1) && (s23.length == 2)) {
1667: // 0-1 2 3 -> 2 3 0-1 2 3
1668: final StackExpr[] s = new StackExpr[] {
1669: (StackExpr) s01[0], (StackExpr) s23[0],
1670: (StackExpr) s23[1] };
1671: manip(s, new int[] { 1, 2, 0, 1, 2 },
1672: StackManipStmt.DUP2_X2);
1673: } else if ((s01.length == 1) && (s23.length == 2)) {
1674: // 0-1 2-3 -> 2-3 0-1 2-3
1675: final StackExpr[] s = new StackExpr[] {
1676: (StackExpr) s01[0], (StackExpr) s23[0] };
1677: manip(s, new int[] { 1, 0, 1 }, StackManipStmt.DUP2_X2);
1678: }
1679: } else {
1680: final Expr[] s23 = stack.pop2();
1681: final Expr[] s01 = stack.pop2();
1682:
1683: if ((s01.length == 2) && (s23.length == 2)) {
1684: // 0 1 2 3 -> 2 3 0 1 2 3
1685: final LocalExpr t0 = newStackLocal(stack.height(),
1686: s01[0].type());
1687: final LocalExpr t1 = newStackLocal(stack.height() + 1,
1688: s01[1].type());
1689: final LocalExpr t2 = newStackLocal(stack.height() + 2,
1690: s23[0].type());
1691: final LocalExpr t3 = newStackLocal(stack.height() + 3,
1692: s23[1].type());
1693:
1694: if (!t0.equalsExpr(s01[0])) {
1695: addStore(t0, s01[0]);
1696: }
1697:
1698: if (!t1.equalsExpr(s01[1])) {
1699: addStore(t1, s01[1]);
1700: }
1701:
1702: if (!t2.equalsExpr(s23[0])) {
1703: addStore(t2, s23[0]);
1704: }
1705:
1706: if (!t3.equalsExpr(s23[1])) {
1707: addStore(t3, s23[1]);
1708: }
1709:
1710: Expr copy = (Expr) t2.clone();
1711: copy.setDef(null);
1712: stack.push(copy);
1713:
1714: copy = (Expr) t3.clone();
1715: copy.setDef(null);
1716: stack.push(copy);
1717:
1718: copy = (Expr) t0.clone();
1719: copy.setDef(null);
1720: stack.push(copy);
1721:
1722: copy = (Expr) t1.clone();
1723: copy.setDef(null);
1724: stack.push(copy);
1725:
1726: copy = (Expr) t2.clone();
1727: copy.setDef(null);
1728: stack.push(copy);
1729:
1730: copy = (Expr) t3.clone();
1731: copy.setDef(null);
1732: stack.push(copy);
1733: } else if ((s01.length == 2) && (s23.length == 1)) {
1734: // 0 1 2-3 -> 2-3 0 1 2-3
1735: final LocalExpr t0 = newStackLocal(stack.height(),
1736: s01[0].type());
1737: final LocalExpr t1 = newStackLocal(stack.height() + 1,
1738: s01[1].type());
1739: final LocalExpr t2 = newStackLocal(stack.height() + 2,
1740: s23[0].type());
1741:
1742: if (!t0.equalsExpr(s01[0])) {
1743: addStore(t0, s01[0]);
1744: }
1745:
1746: if (!t1.equalsExpr(s01[1])) {
1747: addStore(t1, s01[1]);
1748: }
1749:
1750: if (!t2.equalsExpr(s23[0])) {
1751: addStore(t2, s23[0]);
1752: }
1753:
1754: Expr copy = (Expr) t2.clone();
1755: copy.setDef(null);
1756: stack.push(copy);
1757:
1758: copy = (Expr) t0.clone();
1759: copy.setDef(null);
1760: stack.push(copy);
1761:
1762: copy = (Expr) t1.clone();
1763: copy.setDef(null);
1764: stack.push(copy);
1765:
1766: copy = (Expr) t2.clone();
1767: copy.setDef(null);
1768: stack.push(copy);
1769: } else if ((s01.length == 1) && (s23.length == 2)) {
1770: // 0-1 2 3 -> 2 3 0-1 2 3
1771: final LocalExpr t0 = newStackLocal(stack.height(),
1772: s01[0].type());
1773: final LocalExpr t2 = newStackLocal(stack.height() + 2,
1774: s23[0].type());
1775: final LocalExpr t3 = newStackLocal(stack.height() + 3,
1776: s23[1].type());
1777:
1778: if (!t0.equalsExpr(s01[0])) {
1779: addStore(t0, s01[0]);
1780: }
1781:
1782: if (!t2.equalsExpr(s23[0])) {
1783: addStore(t2, s23[0]);
1784: }
1785:
1786: if (!t3.equalsExpr(s23[1])) {
1787: addStore(t3, s23[1]);
1788: }
1789:
1790: Expr copy = (Expr) t2.clone();
1791: copy.setDef(null);
1792: stack.push(copy);
1793:
1794: copy = (Expr) t3.clone();
1795: copy.setDef(null);
1796: stack.push(copy);
1797:
1798: copy = (Expr) t0.clone();
1799: copy.setDef(null);
1800: stack.push(copy);
1801:
1802: copy = (Expr) t2.clone();
1803: copy.setDef(null);
1804: stack.push(copy);
1805:
1806: copy = (Expr) t3.clone();
1807: copy.setDef(null);
1808: stack.push(copy);
1809: } else if ((s01.length == 1) && (s23.length == 2)) {
1810: // 0-1 2-3 -> 2-3 0-1 2-3
1811: final LocalExpr t0 = newStackLocal(stack.height(),
1812: s01[0].type());
1813: final LocalExpr t2 = newStackLocal(stack.height() + 2,
1814: s23[0].type());
1815:
1816: if (!t0.equalsExpr(s01[0])) {
1817: addStore(t0, s01[0]);
1818: }
1819:
1820: if (!t2.equalsExpr(s23[0])) {
1821: addStore(t2, s23[0]);
1822: }
1823:
1824: Expr copy = (Expr) t2.clone();
1825: copy.setDef(null);
1826: stack.push(copy);
1827:
1828: copy = (Expr) t0.clone();
1829: copy.setDef(null);
1830: stack.push(copy);
1831:
1832: copy = (Expr) t2.clone();
1833: copy.setDef(null);
1834: stack.push(copy);
1835: }
1836: }
1837: }
1838:
1839: public void visit_swap(final Instruction inst) {
1840: // 0 1 -> 1 0
1841:
1842: if (Tree.USE_STACK) {
1843: saveStack();
1844:
1845: final StackExpr s1 = (StackExpr) stack.pop1();
1846: final StackExpr s0 = (StackExpr) stack.pop1();
1847:
1848: final StackExpr[] s = new StackExpr[] { s0, s1 };
1849: manip(s, new int[] { 1, 0 }, StackManipStmt.SWAP);
1850: } else {
1851: final Expr s1 = stack.pop1();
1852: final Expr s0 = stack.pop1();
1853:
1854: final LocalExpr t0 = newStackLocal(stack.height(), s0
1855: .type());
1856: final LocalExpr t1 = newStackLocal(stack.height() + 1, s1
1857: .type());
1858:
1859: if (!t0.equalsExpr(s0)) {
1860: addStore(t0, s0);
1861: }
1862:
1863: if (!t1.equalsExpr(s1)) {
1864: addStore(t1, s1);
1865: }
1866:
1867: Expr copy = (Expr) t1.clone();
1868: copy.setDef(null);
1869: stack.push(copy);
1870:
1871: copy = (Expr) t0.clone();
1872: copy.setDef(null);
1873: stack.push(copy);
1874: }
1875: }
1876:
1877: /**
1878: * Produces a StackManipStmt that represents how the stack is changed as a
1879: * result of a dup instruction. It should only be used when USE_STACK is
1880: * true.
1881: * <p>
1882: * dup instructions change the top n elements of the JVM stack. This method
1883: * takes the original top n elements of the stack, an integer array
1884: * representing the transformation (for instance, if s[0] = 1, then the top
1885: * element of the new stack should contain the second-from-the-top element
1886: * of the old stack), and integer representing the dup instruction.
1887: *
1888: * @param source
1889: * The interesting part of the stack before the dup instruction
1890: * is executed.
1891: * @param s
1892: * An integer array representing the new order of the stack.
1893: * @param kind
1894: * The kind of stack manipulation taking place. (e.g.
1895: * StackManipStmt.DUP_X1)
1896: *
1897: * @see StackManipStmt
1898: */
1899: private void manip(final StackExpr[] source, final int[] s,
1900: final int kind) {
1901: Assert.isTrue(Tree.USE_STACK);
1902:
1903: int height = 0; // Height of the stack
1904:
1905: // Calculate current height of the stack. Recall that the stack
1906: // elements in source have already been popped off the stack.
1907: for (int i = 0; i < stack.size(); i++) {
1908: final Expr expr = stack.get(i);
1909: height += expr.type().stackHeight();
1910: }
1911:
1912: // Create the new portion of the stack. Make new StackExpr
1913: // representing the stack after the dup instruction. Push those
1914: // new StackExprs onto the operand stack. Finally, create a
1915: // StackManipStmt that represent the transformation of the old
1916: // stack (before dup instruction) to the new stack (after dup
1917: // instruction).
1918: final StackExpr[] target = new StackExpr[s.length];
1919:
1920: for (int i = 0; i < s.length; i++) {
1921: target[i] = new StackExpr(height, source[s[i]].type());
1922: final StackExpr copy = (StackExpr) target[i].clone();
1923: copy.setDef(null);
1924: stack.push(copy);
1925: height += target[i].type().stackHeight();
1926: }
1927:
1928: appendStmt(new StackManipStmt(target, source, kind));
1929: }
1930:
1931: /**
1932: * All <tt>visit_<i>x</i>add</tt>, <tt>visit_<i>x</i>sub</tt>,
1933: * <tt>visit_<i>x</i>mul</tt>, <tt>visit_<i>x</i>div</tt>, etc.
1934: * push an ArithExpr onto the operand stack.
1935: *
1936: * @see ArithExpr
1937: */
1938: public void visit_iadd(final Instruction inst) {
1939: final Expr right = stack.pop(Type.INTEGER);
1940: final Expr left = stack.pop(Type.INTEGER);
1941: final Expr top = new ArithExpr(ArithExpr.ADD, left, right,
1942: Type.INTEGER);
1943: stack.push(top);
1944: }
1945:
1946: public void visit_ladd(final Instruction inst) {
1947: final Expr right = stack.pop(Type.LONG);
1948: final Expr left = stack.pop(Type.LONG);
1949: final Expr top = new ArithExpr(ArithExpr.ADD, left, right,
1950: Type.LONG);
1951: stack.push(top);
1952: }
1953:
1954: public void visit_fadd(final Instruction inst) {
1955: final Expr right = stack.pop(Type.FLOAT);
1956: final Expr left = stack.pop(Type.FLOAT);
1957: final Expr top = new ArithExpr(ArithExpr.ADD, left, right,
1958: Type.FLOAT);
1959: stack.push(top);
1960: }
1961:
1962: public void visit_dadd(final Instruction inst) {
1963: final Expr right = stack.pop(Type.DOUBLE);
1964: final Expr left = stack.pop(Type.DOUBLE);
1965: final Expr top = new ArithExpr(ArithExpr.ADD, left, right,
1966: Type.DOUBLE);
1967: stack.push(top);
1968: }
1969:
1970: public void visit_isub(final Instruction inst) {
1971: final Expr right = stack.pop(Type.INTEGER);
1972: final Expr left = stack.pop(Type.INTEGER);
1973: final Expr top = new ArithExpr(ArithExpr.SUB, left, right,
1974: Type.INTEGER);
1975: stack.push(top);
1976: }
1977:
1978: public void visit_lsub(final Instruction inst) {
1979: final Expr right = stack.pop(Type.LONG);
1980: final Expr left = stack.pop(Type.LONG);
1981: final Expr top = new ArithExpr(ArithExpr.SUB, left, right,
1982: Type.LONG);
1983: stack.push(top);
1984: }
1985:
1986: public void visit_fsub(final Instruction inst) {
1987: final Expr right = stack.pop(Type.FLOAT);
1988: final Expr left = stack.pop(Type.FLOAT);
1989: final Expr top = new ArithExpr(ArithExpr.SUB, left, right,
1990: Type.FLOAT);
1991: stack.push(top);
1992: }
1993:
1994: public void visit_dsub(final Instruction inst) {
1995: final Expr right = stack.pop(Type.DOUBLE);
1996: final Expr left = stack.pop(Type.DOUBLE);
1997: final Expr top = new ArithExpr(ArithExpr.SUB, left, right,
1998: Type.DOUBLE);
1999: stack.push(top);
2000: }
2001:
2002: public void visit_imul(final Instruction inst) {
2003: final Expr right = stack.pop(Type.INTEGER);
2004: final Expr left = stack.pop(Type.INTEGER);
2005: final Expr top = new ArithExpr(ArithExpr.MUL, left, right,
2006: Type.INTEGER);
2007: stack.push(top);
2008: }
2009:
2010: public void visit_lmul(final Instruction inst) {
2011: final Expr right = stack.pop(Type.LONG);
2012: final Expr left = stack.pop(Type.LONG);
2013: final Expr top = new ArithExpr(ArithExpr.MUL, left, right,
2014: Type.LONG);
2015: stack.push(top);
2016: }
2017:
2018: public void visit_fmul(final Instruction inst) {
2019: final Expr right = stack.pop(Type.FLOAT);
2020: final Expr left = stack.pop(Type.FLOAT);
2021: final Expr top = new ArithExpr(ArithExpr.MUL, left, right,
2022: Type.FLOAT);
2023: stack.push(top);
2024: }
2025:
2026: public void visit_dmul(final Instruction inst) {
2027: final Expr right = stack.pop(Type.DOUBLE);
2028: final Expr left = stack.pop(Type.DOUBLE);
2029: final Expr top = new ArithExpr(ArithExpr.MUL, left, right,
2030: Type.DOUBLE);
2031: stack.push(top);
2032: }
2033:
2034: public void visit_idiv(final Instruction inst) {
2035: final Expr right = stack.pop(Type.INTEGER);
2036: final Expr left = stack.pop(Type.INTEGER);
2037: final Expr check = new ZeroCheckExpr(right, Type.INTEGER);
2038: final Expr top = new ArithExpr(ArithExpr.DIV, left, check,
2039: Type.INTEGER);
2040: stack.push(top);
2041: }
2042:
2043: public void visit_ldiv(final Instruction inst) {
2044: final Expr right = stack.pop(Type.LONG);
2045: final Expr left = stack.pop(Type.LONG);
2046: final Expr check = new ZeroCheckExpr(right, Type.LONG);
2047: final Expr top = new ArithExpr(ArithExpr.DIV, left, check,
2048: Type.LONG);
2049: stack.push(top);
2050: }
2051:
2052: public void visit_fdiv(final Instruction inst) {
2053: final Expr right = stack.pop(Type.FLOAT);
2054: final Expr left = stack.pop(Type.FLOAT);
2055: final Expr top = new ArithExpr(ArithExpr.DIV, left, right,
2056: Type.FLOAT);
2057: stack.push(top);
2058: }
2059:
2060: public void visit_ddiv(final Instruction inst) {
2061: final Expr right = stack.pop(Type.DOUBLE);
2062: final Expr left = stack.pop(Type.DOUBLE);
2063: final Expr top = new ArithExpr(ArithExpr.DIV, left, right,
2064: Type.DOUBLE);
2065: stack.push(top);
2066: }
2067:
2068: public void visit_irem(final Instruction inst) {
2069: final Expr right = stack.pop(Type.INTEGER);
2070: final Expr left = stack.pop(Type.INTEGER);
2071: final Expr check = new ZeroCheckExpr(right, Type.INTEGER);
2072: final Expr top = new ArithExpr(ArithExpr.REM, left, check,
2073: Type.INTEGER);
2074: stack.push(top);
2075: }
2076:
2077: public void visit_lrem(final Instruction inst) {
2078: final Expr right = stack.pop(Type.LONG);
2079: final Expr left = stack.pop(Type.LONG);
2080: final Expr check = new ZeroCheckExpr(right, Type.LONG);
2081: final Expr top = new ArithExpr(ArithExpr.REM, left, check,
2082: Type.LONG);
2083: stack.push(top);
2084: }
2085:
2086: public void visit_frem(final Instruction inst) {
2087: final Expr right = stack.pop(Type.FLOAT);
2088: final Expr left = stack.pop(Type.FLOAT);
2089: final Expr top = new ArithExpr(ArithExpr.REM, left, right,
2090: Type.FLOAT);
2091: stack.push(top);
2092: }
2093:
2094: public void visit_drem(final Instruction inst) {
2095: final Expr right = stack.pop(Type.DOUBLE);
2096: final Expr left = stack.pop(Type.DOUBLE);
2097: final Expr top = new ArithExpr(ArithExpr.REM, left, right,
2098: Type.DOUBLE);
2099: stack.push(top);
2100: }
2101:
2102: /**
2103: * All <tt>visit_<i>x</i>neg</tt> push a NegExpr onto the stack.
2104: *
2105: * @see NegExpr
2106: */
2107: public void visit_ineg(final Instruction inst) {
2108: final Expr expr = stack.pop(Type.INTEGER);
2109: final Expr top = new NegExpr(expr, Type.INTEGER);
2110: stack.push(top);
2111: }
2112:
2113: public void visit_lneg(final Instruction inst) {
2114: final Expr expr = stack.pop(Type.LONG);
2115: final Expr top = new NegExpr(expr, Type.LONG);
2116: stack.push(top);
2117: }
2118:
2119: public void visit_fneg(final Instruction inst) {
2120: final Expr expr = stack.pop(Type.FLOAT);
2121: final Expr top = new NegExpr(expr, Type.FLOAT);
2122: stack.push(top);
2123: }
2124:
2125: public void visit_dneg(final Instruction inst) {
2126: final Expr expr = stack.pop(Type.DOUBLE);
2127: final Expr top = new NegExpr(expr, Type.DOUBLE);
2128: stack.push(top);
2129: }
2130:
2131: /**
2132: * All <tt>visit_<i>x</i>sh<i>d</i></tt> push a ShiftExpr onto the
2133: * operand stack.
2134: *
2135: * @see ShiftExpr
2136: */
2137: public void visit_ishl(final Instruction inst) {
2138: final Expr right = stack.pop(Type.INTEGER);
2139: final Expr left = stack.pop(Type.INTEGER);
2140: final Expr top = new ShiftExpr(ShiftExpr.LEFT, left, right,
2141: Type.INTEGER);
2142: stack.push(top);
2143: }
2144:
2145: public void visit_lshl(final Instruction inst) {
2146: final Expr right = stack.pop(Type.INTEGER);
2147: final Expr left = stack.pop(Type.LONG);
2148: final Expr top = new ShiftExpr(ShiftExpr.LEFT, left, right,
2149: Type.LONG);
2150: stack.push(top);
2151: }
2152:
2153: public void visit_ishr(final Instruction inst) {
2154: final Expr right = stack.pop(Type.INTEGER);
2155: final Expr left = stack.pop(Type.INTEGER);
2156: final Expr top = new ShiftExpr(ShiftExpr.RIGHT, left, right,
2157: Type.INTEGER);
2158: stack.push(top);
2159: }
2160:
2161: public void visit_lshr(final Instruction inst) {
2162: final Expr right = stack.pop(Type.INTEGER);
2163: final Expr left = stack.pop(Type.LONG);
2164: final Expr top = new ShiftExpr(ShiftExpr.RIGHT, left, right,
2165: Type.LONG);
2166: stack.push(top);
2167: }
2168:
2169: public void visit_iushr(final Instruction inst) {
2170: final Expr right = stack.pop(Type.INTEGER);
2171: final Expr left = stack.pop(Type.INTEGER);
2172: final Expr top = new ShiftExpr(ShiftExpr.UNSIGNED_RIGHT, left,
2173: right, Type.INTEGER);
2174: stack.push(top);
2175: }
2176:
2177: public void visit_lushr(final Instruction inst) {
2178: final Expr right = stack.pop(Type.INTEGER);
2179: final Expr left = stack.pop(Type.LONG);
2180: final Expr top = new ShiftExpr(ShiftExpr.UNSIGNED_RIGHT, left,
2181: right, Type.LONG);
2182: stack.push(top);
2183: }
2184:
2185: /**
2186: * All <tt>visit_<i>x op</i></tt> push an ArithExpr onto the stack.
2187: *
2188: * @see ArithExpr
2189: */
2190: public void visit_iand(final Instruction inst) {
2191: final Expr right = stack.pop(Type.INTEGER);
2192: final Expr left = stack.pop(Type.INTEGER);
2193: final Expr top = new ArithExpr(ArithExpr.AND, left, right,
2194: Type.INTEGER);
2195: stack.push(top);
2196: }
2197:
2198: public void visit_land(final Instruction inst) {
2199: final Expr right = stack.pop(Type.LONG);
2200: final Expr left = stack.pop(Type.LONG);
2201: final Expr top = new ArithExpr(ArithExpr.AND, left, right,
2202: Type.LONG);
2203: stack.push(top);
2204: }
2205:
2206: public void visit_ior(final Instruction inst) {
2207: final Expr right = stack.pop(Type.INTEGER);
2208: final Expr left = stack.pop(Type.INTEGER);
2209: final Expr top = new ArithExpr(ArithExpr.IOR, left, right,
2210: Type.INTEGER);
2211: stack.push(top);
2212: }
2213:
2214: public void visit_lor(final Instruction inst) {
2215: final Expr right = stack.pop(Type.LONG);
2216: final Expr left = stack.pop(Type.LONG);
2217: final Expr top = new ArithExpr(ArithExpr.IOR, left, right,
2218: Type.LONG);
2219: stack.push(top);
2220: }
2221:
2222: public void visit_ixor(final Instruction inst) {
2223: final Expr right = stack.pop(Type.INTEGER);
2224: final Expr left = stack.pop(Type.INTEGER);
2225: final Expr top = new ArithExpr(ArithExpr.XOR, left, right,
2226: Type.INTEGER);
2227: stack.push(top);
2228: }
2229:
2230: public void visit_lxor(final Instruction inst) {
2231: final Expr right = stack.pop(Type.LONG);
2232: final Expr left = stack.pop(Type.LONG);
2233: final Expr top = new ArithExpr(ArithExpr.XOR, left, right,
2234: Type.LONG);
2235: stack.push(top);
2236: }
2237:
2238: /**
2239: * Visiting an iinc involves creating a ConstantExpr, LocalExpr, ArithExpr
2240: * StoreExpr, and a ExprStmt.
2241: */
2242: public void visit_iinc(final Instruction inst) {
2243: final IncOperand operand = (IncOperand) inst.operand();
2244: int incr = operand.incr();
2245:
2246: if (incr < 0) {
2247: final Expr right = new ConstantExpr(new Integer(-incr),
2248: Type.INTEGER);
2249: final Expr left = new LocalExpr(operand.var().index(),
2250: Type.INTEGER);
2251:
2252: final Expr top = new ArithExpr(ArithExpr.SUB, left, right,
2253: Type.INTEGER);
2254:
2255: final LocalExpr copy = (LocalExpr) left.clone();
2256: copy.setDef(null);
2257: addStmt(new ExprStmt(new StoreExpr(copy, top, left.type())));
2258: } else if (incr > 0) {
2259: final Expr right = new ConstantExpr(new Integer(incr),
2260: Type.INTEGER);
2261: final Expr left = new LocalExpr(operand.var().index(),
2262: Type.INTEGER);
2263:
2264: final Expr top = new ArithExpr(ArithExpr.ADD, left, right,
2265: Type.INTEGER);
2266:
2267: final LocalExpr copy = (LocalExpr) left.clone();
2268: copy.setDef(null);
2269: addStmt(new ExprStmt(new StoreExpr(copy, top, left.type())));
2270: }
2271: }
2272:
2273: /**
2274: * All cast visitors push a CastExpr onto the operand stack.
2275: */
2276: public void visit_i2l(final Instruction inst) {
2277: final Expr expr = stack.pop(Type.INTEGER);
2278: final Expr top = new CastExpr(expr, Type.LONG, Type.LONG);
2279: stack.push(top);
2280: }
2281:
2282: public void visit_i2f(final Instruction inst) {
2283: final Expr expr = stack.pop(Type.INTEGER);
2284: final Expr top = new CastExpr(expr, Type.FLOAT, Type.FLOAT);
2285: stack.push(top);
2286: }
2287:
2288: public void visit_i2d(final Instruction inst) {
2289: final Expr expr = stack.pop(Type.INTEGER);
2290: final Expr top = new CastExpr(expr, Type.DOUBLE, Type.DOUBLE);
2291: stack.push(top);
2292: }
2293:
2294: public void visit_l2i(final Instruction inst) {
2295: final Expr expr = stack.pop(Type.LONG);
2296: final Expr top = new CastExpr(expr, Type.INTEGER, Type.INTEGER);
2297: stack.push(top);
2298: }
2299:
2300: public void visit_l2f(final Instruction inst) {
2301: final Expr expr = stack.pop(Type.LONG);
2302: final Expr top = new CastExpr(expr, Type.FLOAT, Type.FLOAT);
2303: stack.push(top);
2304: }
2305:
2306: public void visit_l2d(final Instruction inst) {
2307: final Expr expr = stack.pop(Type.LONG);
2308: final Expr top = new CastExpr(expr, Type.DOUBLE, Type.DOUBLE);
2309: stack.push(top);
2310: }
2311:
2312: public void visit_f2i(final Instruction inst) {
2313: final Expr expr = stack.pop(Type.FLOAT);
2314: final Expr top = new CastExpr(expr, Type.INTEGER, Type.INTEGER);
2315: stack.push(top);
2316: }
2317:
2318: public void visit_f2l(final Instruction inst) {
2319: final Expr expr = stack.pop(Type.FLOAT);
2320: final Expr top = new CastExpr(expr, Type.LONG, Type.LONG);
2321: stack.push(top);
2322: }
2323:
2324: public void visit_f2d(final Instruction inst) {
2325: final Expr expr = stack.pop(Type.FLOAT);
2326: final Expr top = new CastExpr(expr, Type.DOUBLE, Type.DOUBLE);
2327: stack.push(top);
2328: }
2329:
2330: public void visit_d2i(final Instruction inst) {
2331: final Expr expr = stack.pop(Type.DOUBLE);
2332: final Expr top = new CastExpr(expr, Type.INTEGER, Type.INTEGER);
2333: stack.push(top);
2334: }
2335:
2336: public void visit_d2l(final Instruction inst) {
2337: final Expr expr = stack.pop(Type.DOUBLE);
2338: final Expr top = new CastExpr(expr, Type.LONG, Type.LONG);
2339: stack.push(top);
2340: }
2341:
2342: public void visit_d2f(final Instruction inst) {
2343: final Expr expr = stack.pop(Type.DOUBLE);
2344: final Expr top = new CastExpr(expr, Type.FLOAT, Type.FLOAT);
2345: stack.push(top);
2346: }
2347:
2348: public void visit_i2b(final Instruction inst) {
2349: final Expr expr = stack.pop(Type.INTEGER);
2350: final Expr top = new CastExpr(expr, Type.BYTE, Type.INTEGER);
2351: stack.push(top);
2352: }
2353:
2354: public void visit_i2c(final Instruction inst) {
2355: final Expr expr = stack.pop(Type.INTEGER);
2356: final Expr top = new CastExpr(expr, Type.CHARACTER,
2357: Type.INTEGER);
2358: stack.push(top);
2359: }
2360:
2361: public void visit_i2s(final Instruction inst) {
2362: final Expr expr = stack.pop(Type.INTEGER);
2363: final Expr top = new CastExpr(expr, Type.SHORT, Type.INTEGER);
2364: stack.push(top);
2365: }
2366:
2367: /**
2368: * All <tt>visit_<i>x</i>cmp</tt> push an ArithExpr onto the stack.
2369: *
2370: * @see ArithExpr
2371: */
2372: public void visit_lcmp(final Instruction inst) {
2373: final Expr right = stack.pop(Type.LONG);
2374: final Expr left = stack.pop(Type.LONG);
2375: final Expr top = new ArithExpr(ArithExpr.CMP, left, right,
2376: Type.INTEGER);
2377: stack.push(top);
2378: }
2379:
2380: public void visit_fcmpl(final Instruction inst) {
2381: final Expr right = stack.pop(Type.FLOAT);
2382: final Expr left = stack.pop(Type.FLOAT);
2383: final Expr top = new ArithExpr(ArithExpr.CMPL, left, right,
2384: Type.INTEGER);
2385: stack.push(top);
2386: }
2387:
2388: public void visit_fcmpg(final Instruction inst) {
2389: final Expr right = stack.pop(Type.FLOAT);
2390: final Expr left = stack.pop(Type.FLOAT);
2391: final Expr top = new ArithExpr(ArithExpr.CMPG, left, right,
2392: Type.INTEGER);
2393: stack.push(top);
2394: }
2395:
2396: public void visit_dcmpl(final Instruction inst) {
2397: final Expr right = stack.pop(Type.DOUBLE);
2398: final Expr left = stack.pop(Type.DOUBLE);
2399: final Expr top = new ArithExpr(ArithExpr.CMPL, left, right,
2400: Type.INTEGER);
2401: stack.push(top);
2402: }
2403:
2404: public void visit_dcmpg(final Instruction inst) {
2405: final Expr right = stack.pop(Type.DOUBLE);
2406: final Expr left = stack.pop(Type.DOUBLE);
2407: final Expr top = new ArithExpr(ArithExpr.CMPG, left, right,
2408: Type.INTEGER);
2409: stack.push(top);
2410: }
2411:
2412: /**
2413: * All <tt>visit_<i>x</i>eg</tt> add an IfZeroStmt to the statement
2414: * list.
2415: *
2416: * @see IfZeroStmt
2417: */
2418: public void visit_ifeq(final Instruction inst) {
2419: // It isn't necessary to saveStack since removing critical edges
2420: // guarantees that no code will be inserted before the branch
2421: // since there cannot be more than one predecessor of either of
2422: // the successor nodes (and hence no phi statements, even in SSAPRE).
2423: // saveStack();
2424:
2425: final Expr left = stack.pop(Type.INTEGER);
2426: final Block t = (Block) block.graph().getNode(inst.operand());
2427: Assert.isTrue(t != null, "No block for " + inst);
2428:
2429: addStmt(new IfZeroStmt(IfStmt.EQ, left, t, next));
2430: }
2431:
2432: public void visit_ifne(final Instruction inst) {
2433: // It isn't necessary to saveStack since removing critical edges
2434: // guarantees that no code will be inserted before the branch
2435: // since there cannot be more than one predecessor of either of
2436: // the successor nodes (and hence no phi statements, even in SSAPRE).
2437: // saveStack();
2438:
2439: final Expr left = stack.pop(Type.INTEGER);
2440: final Block t = (Block) block.graph().getNode(inst.operand());
2441: Assert.isTrue(t != null, "No block for " + inst);
2442:
2443: addStmt(new IfZeroStmt(IfStmt.NE, left, t, next));
2444: }
2445:
2446: public void visit_iflt(final Instruction inst) {
2447: // It isn't necessary to saveStack since removing critical edges
2448: // guarantees that no code will be inserted before the branch
2449: // since there cannot be more than one predecessor of either of
2450: // the successor nodes (and hence no phi statements, even in SSAPRE).
2451: // saveStack();
2452:
2453: final Expr left = stack.pop(Type.INTEGER);
2454: final Block t = (Block) block.graph().getNode(inst.operand());
2455: Assert.isTrue(t != null, "No block for " + inst);
2456:
2457: addStmt(new IfZeroStmt(IfStmt.LT, left, t, next));
2458: }
2459:
2460: public void visit_ifge(final Instruction inst) {
2461: // It isn't necessary to saveStack since removing critical edges
2462: // guarantees that no code will be inserted before the branch
2463: // since there cannot be more than one predecessor of either of
2464: // the successor nodes (and hence no phi statements, even in SSAPRE).
2465: // saveStack();
2466:
2467: final Expr left = stack.pop(Type.INTEGER);
2468: final Block t = (Block) block.graph().getNode(inst.operand());
2469: Assert.isTrue(t != null, "No block for " + inst);
2470:
2471: addStmt(new IfZeroStmt(IfStmt.GE, left, t, next));
2472: }
2473:
2474: public void visit_ifgt(final Instruction inst) {
2475: // It isn't necessary to saveStack since removing critical edges
2476: // guarantees that no code will be inserted before the branch
2477: // since there cannot be more than one predecessor of either of
2478: // the successor nodes (and hence no phi statements, even in SSAPRE).
2479: // saveStack();
2480:
2481: final Expr left = stack.pop(Type.INTEGER);
2482: final Block t = (Block) block.graph().getNode(inst.operand());
2483: Assert.isTrue(t != null, "No block for " + inst);
2484:
2485: addStmt(new IfZeroStmt(IfStmt.GT, left, t, next));
2486: }
2487:
2488: public void visit_ifle(final Instruction inst) {
2489: // It isn't necessary to saveStack since removing critical edges
2490: // guarantees that no code will be inserted before the branch
2491: // since there cannot be more than one predecessor of either of
2492: // the successor nodes (and hence no phi statements, even in SSAPRE).
2493: // saveStack();
2494:
2495: final Expr left = stack.pop(Type.INTEGER);
2496: final Block t = (Block) block.graph().getNode(inst.operand());
2497: Assert.isTrue(t != null, "No block for " + inst);
2498:
2499: addStmt(new IfZeroStmt(IfStmt.LE, left, t, next));
2500: }
2501:
2502: /**
2503: * All <tt>visit_if_<i>x</i>cmp<i>y</i></tt> add a IfCmpStmt to the
2504: * statement list.
2505: */
2506: public void visit_if_icmpeq(final Instruction inst) {
2507: // It isn't necessary to saveStack since removing critical edges
2508: // guarantees that no code will be inserted before the branch
2509: // since there cannot be more than one predecessor of either of
2510: // the successor nodes (and hence no phi statements, even in SSAPRE).
2511: // saveStack();
2512:
2513: final Expr right = stack.pop(Type.INTEGER);
2514: final Expr left = stack.pop(Type.INTEGER);
2515: final Block t = (Block) block.graph().getNode(inst.operand());
2516: Assert.isTrue(t != null, "No block for " + inst);
2517:
2518: addStmt(new IfCmpStmt(IfStmt.EQ, left, right, t, next));
2519: }
2520:
2521: public void visit_if_icmpne(final Instruction inst) {
2522: // It isn't necessary to saveStack since removing critical edges
2523: // guarantees that no code will be inserted before the branch
2524: // since there cannot be more than one predecessor of either of
2525: // the successor nodes (and hence no phi statements, even in SSAPRE).
2526: // saveStack();
2527:
2528: final Expr right = stack.pop(Type.INTEGER);
2529: final Expr left = stack.pop(Type.INTEGER);
2530: final Block t = (Block) block.graph().getNode(inst.operand());
2531: Assert.isTrue(t != null, "No block for " + inst);
2532:
2533: addStmt(new IfCmpStmt(IfStmt.NE, left, right, t, next));
2534: }
2535:
2536: public void visit_if_icmplt(final Instruction inst) {
2537: // It isn't necessary to saveStack since removing critical edges
2538: // guarantees that no code will be inserted before the branch
2539: // since there cannot be more than one predecessor of either of
2540: // the successor nodes (and hence no phi statements, even in SSAPRE).
2541: // saveStack();
2542:
2543: final Expr right = stack.pop(Type.INTEGER);
2544: final Expr left = stack.pop(Type.INTEGER);
2545: final Block t = (Block) block.graph().getNode(inst.operand());
2546: Assert.isTrue(t != null, "No block for " + inst);
2547:
2548: addStmt(new IfCmpStmt(IfStmt.LT, left, right, t, next));
2549: }
2550:
2551: public void visit_if_icmpge(final Instruction inst) {
2552: // It isn't necessary to saveStack since removing critical edges
2553: // guarantees that no code will be inserted before the branch
2554: // since there cannot be more than one predecessor of either of
2555: // the successor nodes (and hence no phi statements, even in SSAPRE).
2556: // saveStack();
2557:
2558: final Expr right = stack.pop(Type.INTEGER);
2559: final Expr left = stack.pop(Type.INTEGER);
2560: final Block t = (Block) block.graph().getNode(inst.operand());
2561: Assert.isTrue(t != null, "No block for " + inst);
2562:
2563: addStmt(new IfCmpStmt(IfStmt.GE, left, right, t, next));
2564: }
2565:
2566: public void visit_if_icmpgt(final Instruction inst) {
2567: // It isn't necessary to saveStack since removing critical edges
2568: // guarantees that no code will be inserted before the branch
2569: // since there cannot be more than one predecessor of either of
2570: // the successor nodes (and hence no phi statements, even in SSAPRE).
2571: // saveStack();
2572:
2573: final Expr right = stack.pop(Type.INTEGER);
2574: final Expr left = stack.pop(Type.INTEGER);
2575: final Block t = (Block) block.graph().getNode(inst.operand());
2576: Assert.isTrue(t != null, "No block for " + inst);
2577:
2578: addStmt(new IfCmpStmt(IfStmt.GT, left, right, t, next));
2579: }
2580:
2581: public void visit_if_icmple(final Instruction inst) {
2582: // It isn't necessary to saveStack since removing critical edges
2583: // guarantees that no code will be inserted before the branch
2584: // since there cannot be more than one predecessor of either of
2585: // the successor nodes (and hence no phi statements, even in SSAPRE).
2586: // saveStack();
2587:
2588: final Expr right = stack.pop(Type.INTEGER);
2589: final Expr left = stack.pop(Type.INTEGER);
2590: final Block t = (Block) block.graph().getNode(inst.operand());
2591: Assert.isTrue(t != null, "No block for " + inst);
2592:
2593: addStmt(new IfCmpStmt(IfStmt.LE, left, right, t, next));
2594: }
2595:
2596: public void visit_if_acmpeq(final Instruction inst) {
2597: // It isn't necessary to saveStack since removing critical edges
2598: // guarantees that no code will be inserted before the branch
2599: // since there cannot be more than one predecessor of either of
2600: // the successor nodes (and hence no phi statements, even in SSAPRE).
2601: // saveStack();
2602:
2603: final Expr right = stack.pop(Type.OBJECT);
2604: final Expr left = stack.pop(Type.OBJECT);
2605: final Block t = (Block) block.graph().getNode(inst.operand());
2606: Assert.isTrue(t != null, "No block for " + inst);
2607:
2608: addStmt(new IfCmpStmt(IfStmt.EQ, left, right, t, next));
2609: }
2610:
2611: public void visit_if_acmpne(final Instruction inst) {
2612: // It isn't necessary to saveStack since removing critical edges
2613: // guarantees that no code will be inserted before the branch
2614: // since there cannot be more than one predecessor of either of
2615: // the successor nodes (and hence no phi statements, even in SSAPRE).
2616: // saveStack();
2617:
2618: final Expr right = stack.pop(Type.OBJECT);
2619: final Expr left = stack.pop(Type.OBJECT);
2620: final Block t = (Block) block.graph().getNode(inst.operand());
2621: Assert.isTrue(t != null, "No block for " + inst);
2622:
2623: addStmt(new IfCmpStmt(IfStmt.NE, left, right, t, next));
2624: }
2625:
2626: /**
2627: * Adds a GotoStmt to the statement list.
2628: *
2629: * @see GotoStmt
2630: */
2631: public void visit_goto(final Instruction inst) {
2632: final Block t = (Block) block.graph().getNode(inst.operand());
2633: Assert.isTrue(t != null, "No block for " + inst);
2634: addStmt(new GotoStmt(t));
2635: }
2636:
2637: /**
2638: * Adds a JsrStmt to the statement list.
2639: *
2640: * @see JsrStmt
2641: */
2642: public void visit_jsr(final Instruction inst) {
2643: // Push the return address after we add the statement.
2644: // This prevents it from being saved to a local variable.
2645: // It's illegal to load a return address from a local variable,
2646: // so we can't save it.
2647: final Subroutine sub = block.graph().labelSub(
2648: (Label) inst.operand());
2649: addStmt(new JsrStmt(sub, next));
2650: stack.push(new ReturnAddressExpr(Type.ADDRESS));
2651: }
2652:
2653: /**
2654: * Adds a RetStmt to the statement list.
2655: *
2656: * @see RetStmt
2657: */
2658: public void visit_ret(final Instruction inst) {
2659: Assert.isTrue(sub != null);
2660: addStmt(new RetStmt(sub));
2661: }
2662:
2663: /**
2664: * Add a SwitchStmt to the statement list.
2665: *
2666: * @see SwitchStmt
2667: */
2668: public void visit_switch(final Instruction inst) {
2669: // It isn't necessary to saveStack since removing critical edges
2670: // guarantees that no code will be inserted before the branch
2671: // since there cannot be more than one predecessor of either of
2672: // the successor nodes (and hence no phi statements, even in SSAPRE).
2673: // saveStack();
2674:
2675: final Expr index = stack.pop(Type.INTEGER);
2676:
2677: final Switch sw = (Switch) inst.operand();
2678:
2679: final Block defaultTarget = (Block) block.graph().getNode(
2680: sw.defaultTarget());
2681: Assert.isTrue(defaultTarget != null, "No block for " + inst);
2682:
2683: final Block[] targets = new Block[sw.targets().length];
2684:
2685: for (int i = 0; i < targets.length; i++) {
2686: targets[i] = (Block) block.graph().getNode(sw.targets()[i]);
2687: Assert.isTrue(targets[i] != null, "No block for " + inst);
2688: }
2689:
2690: addStmt(new SwitchStmt(index, defaultTarget, targets, sw
2691: .values()));
2692: }
2693:
2694: /**
2695: * All <tt>visit_<i>x</i>return</tt> add a ReturnExprStmt to the
2696: * statement list.
2697: *
2698: * @see ReturnExprStmt
2699: */
2700: public void visit_ireturn(final Instruction inst) {
2701: final Expr expr = stack.pop(Type.INTEGER);
2702: addStmt(new ReturnExprStmt(expr));
2703: }
2704:
2705: public void visit_lreturn(final Instruction inst) {
2706: final Expr expr = stack.pop(Type.LONG);
2707: addStmt(new ReturnExprStmt(expr));
2708: }
2709:
2710: public void visit_freturn(final Instruction inst) {
2711: final Expr expr = stack.pop(Type.FLOAT);
2712: addStmt(new ReturnExprStmt(expr));
2713: }
2714:
2715: public void visit_dreturn(final Instruction inst) {
2716: final Expr expr = stack.pop(Type.DOUBLE);
2717: addStmt(new ReturnExprStmt(expr));
2718: }
2719:
2720: public void visit_areturn(final Instruction inst) {
2721: final Expr expr = stack.pop(Type.OBJECT);
2722: addStmt(new ReturnExprStmt(expr));
2723: }
2724:
2725: /**
2726: * Adds a ReturnStmt to the statement list.
2727: */
2728: public void visit_return(final Instruction inst) {
2729: addStmt(new ReturnStmt());
2730: }
2731:
2732: /**
2733: * Pushes a StaticFieldExpr onto the operand stack.
2734: */
2735: public void visit_getstatic(final Instruction inst) {
2736: final MemberRef field = (MemberRef) inst.operand();
2737: final Type type = field.nameAndType().type();
2738:
2739: try {
2740: final EditorContext context = block.graph().method()
2741: .declaringClass().context();
2742: final FieldEditor e = context.editField(field);
2743:
2744: if (e.isFinal()) {
2745: if (e.constantValue() != null) {
2746: final Expr top = new ConstantExpr(
2747: e.constantValue(), type);
2748: stack.push(top);
2749: context.release(e.fieldInfo());
2750: return;
2751: }
2752: }
2753:
2754: context.release(e.fieldInfo());
2755: } catch (final NoSuchFieldException e) {
2756: // No field found. Silently assume non-final.
2757: }
2758:
2759: final Expr top = new StaticFieldExpr(field, type);
2760: stack.push(top);
2761: }
2762:
2763: public void visit_putstatic(final Instruction inst) {
2764: final MemberRef field = (MemberRef) inst.operand();
2765: final Type type = field.nameAndType().type();
2766: final Expr value = stack.pop(type);
2767: final StaticFieldExpr target = new StaticFieldExpr(field, type);
2768: addStore(target, value);
2769: }
2770:
2771: public void visit_putstatic_nowb(final Instruction inst) {
2772: visit_putstatic(inst);
2773: }
2774:
2775: /**
2776: * Pushes a FieldExpr onto the operand stack.
2777: */
2778: public void visit_getfield(final Instruction inst) {
2779: final MemberRef field = (MemberRef) inst.operand();
2780: final Type type = field.nameAndType().type();
2781: final Expr obj = stack.pop(Type.OBJECT);
2782: final Expr check = new ZeroCheckExpr(obj, obj.type());
2783: final Expr top = new FieldExpr(check, field, type);
2784: stack.push(top);
2785: }
2786:
2787: public void visit_putfield(final Instruction inst) {
2788: final MemberRef field = (MemberRef) inst.operand();
2789: final Type type = field.nameAndType().type();
2790: final Expr value = stack.pop(type);
2791: final Expr obj = stack.pop(Type.OBJECT);
2792: Expr ucCheck = obj;
2793:
2794: if (Tree.USE_PERSISTENT) {
2795: ucCheck = new UCExpr(obj, UCExpr.POINTER, obj.type());
2796: }
2797:
2798: final Expr check = new ZeroCheckExpr(ucCheck, obj.type());
2799: final FieldExpr target = new FieldExpr(check, field, type);
2800: addStore(target, value);
2801: }
2802:
2803: // Don't insert UCExpr
2804: public void visit_putfield_nowb(final Instruction inst) {
2805: final MemberRef field = (MemberRef) inst.operand();
2806: final Type type = field.nameAndType().type();
2807: final Expr value = stack.pop(type);
2808: final Expr obj = stack.pop(Type.OBJECT);
2809: final Expr check = new ZeroCheckExpr(obj, obj.type());
2810: final FieldExpr target = new FieldExpr(check, field, type);
2811: addStore(target, value);
2812: }
2813:
2814: /**
2815: * All <tt>visit_invoke<i>x</i></tt> deal with a CallMethodExpr or a
2816: * CallStaticExpr.
2817: *
2818: * @see CallMethodExpr
2819: * @see CallStaticExpr
2820: */
2821: public void visit_invokevirtual(final Instruction inst) {
2822: addCall(inst, CallMethodExpr.VIRTUAL);
2823: }
2824:
2825: public void visit_invokespecial(final Instruction inst) {
2826: addCall(inst, CallMethodExpr.NONVIRTUAL);
2827: }
2828:
2829: public void visit_invokestatic(final Instruction inst) {
2830: addCall(inst, 0);
2831: }
2832:
2833: public void visit_invokeinterface(final Instruction inst) {
2834: addCall(inst, CallMethodExpr.INTERFACE);
2835: }
2836:
2837: /**
2838: * Creates either a CallMethodExpr or a CallStaticExpr to represent a method
2839: * call. After obtaining some information about the method. The parameters
2840: * to the methods are popped from the operand stack. If the method is not
2841: * static, the "this" object is popped from the operand stack. A
2842: * CallMethodExpr is created for a non-static method and a CallStaticExpr is
2843: * created for a static method. If the method returns a value, the Call*Expr
2844: * is pushed onto the stack. If the method has no return value, it is
2845: * wrapped in an ExprStmt and is added to the statement list.
2846: */
2847: private void addCall(final Instruction inst, final int kind) {
2848: final MemberRef method = (MemberRef) inst.operand();
2849: final Type type = method.nameAndType().type();
2850:
2851: final Type[] paramTypes = type.paramTypes();
2852: final Expr[] params = new Expr[paramTypes.length];
2853:
2854: for (int i = paramTypes.length - 1; i >= 0; i--) {
2855: params[i] = stack.pop(paramTypes[i]);
2856: }
2857:
2858: Expr top;
2859:
2860: if (inst.opcodeClass() != Opcode.opcx_invokestatic) {
2861: final Expr obj = stack.pop(Type.OBJECT);
2862:
2863: top = new CallMethodExpr(kind, obj, params, method, type
2864: .returnType());
2865:
2866: } else {
2867: top = new CallStaticExpr(params, method, type.returnType());
2868: }
2869:
2870: if (type.returnType().equals(Type.VOID)) {
2871: addStmt(new ExprStmt(top));
2872:
2873: } else {
2874: stack.push(top);
2875: }
2876: }
2877:
2878: /**
2879: * Pushes a NewExpr onto the operand stack.
2880: *
2881: * @see NewExpr
2882: */
2883: public void visit_new(final Instruction inst) {
2884: final Type type = (Type) inst.operand();
2885: final Expr top = new NewExpr(type, Type.OBJECT);
2886: stack.push(top);
2887:
2888: db(" new: " + top);
2889: }
2890:
2891: /**
2892: * Pushes a NewArrayExpr onto the operand stack.
2893: */
2894: public void visit_newarray(final Instruction inst) {
2895: final Type type = (Type) inst.operand();
2896: final Expr size = stack.pop(Type.INTEGER);
2897: final Expr top = new NewArrayExpr(size, type, type.arrayType());
2898: stack.push(top);
2899: }
2900:
2901: /**
2902: * Pushes an ArrayLengthExpr onto the operand stack.
2903: *
2904: * @see ArrayLengthExpr
2905: */
2906: public void visit_arraylength(final Instruction inst) {
2907: final Expr array = stack.pop(Type.OBJECT);
2908: final Expr top = new ArrayLengthExpr(array, Type.INTEGER);
2909: stack.push(top);
2910: }
2911:
2912: /**
2913: * Adds a ThrowStmt to the statement list.
2914: *
2915: * @see ThrowStmt
2916: */
2917: public void visit_athrow(final Instruction inst) {
2918: final Expr expr = stack.pop(Type.THROWABLE);
2919: addStmt(new ThrowStmt(expr));
2920: }
2921:
2922: /**
2923: * Pushes a CastExpr onto the operand stack.
2924: *
2925: * @see CastExpr
2926: */
2927: public void visit_checkcast(final Instruction inst) {
2928: final Expr expr = stack.pop(Type.OBJECT);
2929: final Type type = (Type) inst.operand();
2930: final Expr top = new CastExpr(expr, type, type);
2931: stack.push(top);
2932: }
2933:
2934: /**
2935: * Pushes an InstanceOfExpr onto the operand stack.
2936: *
2937: * @see InstanceOfExpr
2938: */
2939: public void visit_instanceof (final Instruction inst) {
2940: final Type type = (Type) inst.operand();
2941: final Expr expr = stack.pop(Type.OBJECT);
2942: final Expr top = new InstanceOfExpr(expr, type, Type.INTEGER);
2943: stack.push(top);
2944: }
2945:
2946: /**
2947: * Both <tt>monitor</tt> visitors add a MonitorStmt to the statement list.
2948: *
2949: * @see MonitorStmt
2950: */
2951: public void visit_monitorenter(final Instruction inst) {
2952: final Expr obj = stack.pop(Type.OBJECT);
2953: addStmt(new MonitorStmt(MonitorStmt.ENTER, obj));
2954: }
2955:
2956: public void visit_monitorexit(final Instruction inst) {
2957: final Expr obj = stack.pop(Type.OBJECT);
2958: addStmt(new MonitorStmt(MonitorStmt.EXIT, obj));
2959: }
2960:
2961: /**
2962: * Push a NewMultiArrayExpr onto the operand stack.
2963: *
2964: * @see NewMultiArrayExpr
2965: */
2966: public void visit_multianewarray(final Instruction inst) {
2967: final MultiArrayOperand operand = (MultiArrayOperand) inst
2968: .operand();
2969:
2970: final Expr[] dim = new Expr[operand.dimensions()];
2971:
2972: for (int i = dim.length - 1; i >= 0; i--) {
2973: dim[i] = stack.pop(Type.INTEGER);
2974: }
2975:
2976: final Type type = operand.type();
2977:
2978: final Expr top = new NewMultiArrayExpr(dim, type
2979: .elementType(dim.length), type);
2980:
2981: stack.push(top);
2982: }
2983:
2984: /**
2985: * Both <tt>visit_<i>x</i>null</tt> add an IfZeroStmt to the statement
2986: * list.
2987: *
2988: * ssee IfZeroStmt
2989: */
2990: public void visit_ifnull(final Instruction inst) {
2991: // It isn't necessary to saveStack since removing critical edges
2992: // guarantees that no code will be inserted before the branch
2993: // since there cannot be more than one predecessor of either of
2994: // the successor nodes (and hence no phi statements, even in SSAPRE).
2995: // saveStack();
2996:
2997: final Expr left = stack.pop(Type.OBJECT);
2998: final Block t = (Block) block.graph().getNode(inst.operand());
2999: Assert.isTrue(t != null, "No block for " + inst);
3000:
3001: addStmt(new IfZeroStmt(IfStmt.EQ, left, t, next));
3002: }
3003:
3004: public void visit_ifnonnull(final Instruction inst) {
3005: // It isn't necessary to saveStack since removing critical edges
3006: // guarantees that no code will be inserted before the branch
3007: // since there cannot be more than one predecessor of either of
3008: // the successor nodes (and hence no phi statements, even in SSAPRE).
3009: // saveStack();
3010:
3011: final Expr left = stack.pop(Type.OBJECT);
3012: final Block t = (Block) block.graph().getNode(inst.operand());
3013: Assert.isTrue(t != null, "No block for " + inst);
3014:
3015: addStmt(new IfZeroStmt(IfStmt.NE, left, t, next));
3016: }
3017:
3018: /**
3019: * Replaces the expression on the top of the stack with an RCExpr.
3020: *
3021: * @see RCExpr
3022: */
3023: public void visit_rc(final Instruction inst) {
3024: final Integer depth = (Integer) inst.operand();
3025: final Expr object = stack.peek(depth.intValue());
3026: stack.replace(depth.intValue(), new RCExpr(object, object
3027: .type()));
3028: }
3029:
3030: /**
3031: *
3032: */
3033: public void visit_aupdate(final Instruction inst) {
3034: Integer depth = (Integer) inst.operand();
3035:
3036: if (Tree.AUPDATE_FIX_HACK) {
3037: // Hack to fix a bug in old bloat-generated code:
3038:
3039: if (depth.intValue() == 1) {
3040: final Expr object = stack.peek();
3041:
3042: if (object.type().isWide()) {
3043: depth = new Integer(2);
3044: inst.setOperand(depth);
3045: Tree.AUPDATE_FIX_HACK_CHANGED = true;
3046: }
3047: }
3048: }
3049:
3050: final Expr object = stack.peek(depth.intValue());
3051: stack.replace(depth.intValue(), new UCExpr(object,
3052: UCExpr.POINTER, object.type()));
3053: }
3054:
3055: /**
3056: * Replace the expression at the stack depth specified in the instruction
3057: * with a UCExpr.
3058: *
3059: * @see UCExpr
3060: */
3061: public void visit_supdate(final Instruction inst) {
3062: final Integer depth = (Integer) inst.operand();
3063: final Expr object = stack.peek(depth.intValue());
3064: stack.replace(depth.intValue(), new UCExpr(object,
3065: UCExpr.SCALAR, object.type()));
3066: }
3067:
3068: /**
3069: * Add a SCStmt to the statement list
3070: *
3071: * @see SCStmt
3072: */
3073: public void visit_aswizzle(final Instruction inst) {
3074: final Expr index = stack.pop(Type.INTEGER);
3075: final Expr array = stack.pop(Type.OBJECT.arrayType());
3076:
3077: addStmt(new SCStmt(array, index));
3078:
3079: }
3080:
3081: /**
3082: * Add a SRStmt to the statement list.
3083: *
3084: * @see SRStmt
3085: */
3086: public void visit_aswrange(final Instruction inst) {
3087: final Expr end = stack.pop(Type.INTEGER);
3088: final Expr start = stack.pop(Type.INTEGER);
3089: final Expr array = stack.pop(Type.OBJECT.arrayType());
3090:
3091: addStmt(new SRStmt(array, start, end));
3092: }
3093:
3094: /**
3095: * Visit all the statements in the statement list.
3096: */
3097: public void visitForceChildren(final TreeVisitor visitor) {
3098: final LinkedList list = new LinkedList(stmts);
3099:
3100: if (visitor.reverse()) {
3101: final ListIterator iter = list.listIterator(stmts.size());
3102:
3103: while (iter.hasPrevious()) {
3104: final Stmt s = (Stmt) iter.previous();
3105: s.visit(visitor);
3106: }
3107: } else {
3108: final ListIterator iter = list.listIterator();
3109:
3110: while (iter.hasNext()) {
3111: final Stmt s = (Stmt) iter.next();
3112: s.visit(visitor);
3113: }
3114: }
3115: }
3116:
3117: public void visit(final TreeVisitor visitor) {
3118: visitor.visitTree(this );
3119: }
3120:
3121: public Node parent() {
3122: return null;
3123: }
3124:
3125: public Block block() {
3126: return block;
3127: }
3128: }
|