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.codegen;
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.tree.*;
0028: import EDU.purdue.cs.bloat.util.*;
0029:
0030: /**
0031: * CodeGenerator performs some final optimizations and is used (via a visitor)
0032: * to generate bytecode for the contents of a control flow graph.
0033: *
0034: * @see FlowGraph
0035: */
0036: public class CodeGenerator extends TreeVisitor implements Opcode {
0037: public static boolean DEBUG = false;
0038:
0039: public static boolean USE_PERSISTENT = false; // Generate _nowb
0040:
0041: /**
0042: * Use information about placement of local variables to eliminate loads and
0043: * stores in favor of stack manipulations
0044: */
0045: public static boolean OPT_STACK = false;
0046:
0047: public static boolean DB_OPT_STACK = false;
0048:
0049: protected MethodEditor method;
0050:
0051: protected Set visited;
0052:
0053: protected Map postponedInstructions;
0054:
0055: protected Block next;
0056:
0057: protected int stackHeight; // The current height of the stack
0058:
0059: StackOptimizer currentSO; // object used to determine where to apply
0060:
0061: // stack optimization
0062:
0063: /**
0064: * Constructor.
0065: *
0066: * @param method
0067: * The method for which bytecode is generated.
0068: */
0069: public CodeGenerator(final MethodEditor method) {
0070: this .method = method;
0071: this .postponedInstructions = new HashMap();
0072: }
0073:
0074: /**
0075: * Visits the nodes in the method's control flow graph and ensures that
0076: * information about the method's basic blocks is consistent and correct.
0077: *
0078: * @param cfg
0079: * The control flow graph associated with this method.
0080: */
0081: public void visitFlowGraph(final FlowGraph cfg) {
0082: // Generate the code.
0083:
0084: visited = new HashSet();
0085: visited.add(cfg.source());
0086: visited.add(cfg.sink());
0087:
0088: final Iterator e = cfg.trace().iterator();
0089:
0090: Assert.isTrue(e.hasNext(), "trace is empty");
0091:
0092: stackHeight = 0; // At beginning of method stack has height 0
0093:
0094: Block block = (Block) e.next();
0095:
0096: // Visit each block in the method (via the trace in the method's CFG)
0097: // and ensure that the first (and ONLY the first) label in the code
0098: // is marked as starting a block.
0099: while (block != null) {
0100: if (e.hasNext()) {
0101: next = (Block) e.next();
0102:
0103: } else {
0104: next = null;
0105: }
0106:
0107: if (CodeGenerator.DEBUG) {
0108: System.out.println("code for " + block);
0109: }
0110:
0111: // Make sure the first label is marked as starting a block
0112: // and the rest are marked as not starting a block.
0113: block.visit(new TreeVisitor() {
0114: boolean startsBlock = true;
0115:
0116: public void visitLabelStmt(final LabelStmt stmt) {
0117: stmt.label().setStartsBlock(startsBlock);
0118: startsBlock = false;
0119: }
0120:
0121: public void visitStmt(final Stmt stmt) {
0122: }
0123: });
0124:
0125: // Generate the code for each block
0126: visited.add(block);
0127: // currentSO is the StackOptimizer object that discerns
0128: // where dups may be used instead of loads
0129: if (CodeGenerator.OPT_STACK) {
0130: currentSO = block.stackOptimizer();
0131: }
0132: block.visitChildren(this );
0133:
0134: block = next;
0135: }
0136:
0137: Assert.isTrue(visited.size() == cfg.size(),
0138: "did not visit all blocks while generating code");
0139:
0140: next = null;
0141: visited = null;
0142:
0143: // Go through the catch blocks and determine the what the
0144: // protected regions are that correspond to the catch blocks.
0145: // Create TryCatch objects to represent the protected regions.
0146:
0147: final Iterator iter = cfg.catchBlocks().iterator();
0148:
0149: while (iter.hasNext()) {
0150: final Block catchBlock = (Block) iter.next();
0151: final Handler handler = (Handler) cfg.handlersMap().get(
0152: catchBlock);
0153:
0154: Type type = handler.catchType();
0155:
0156: if (type.isNull()) {
0157: type = null;
0158: }
0159:
0160: // First block in protected block
0161: Block begin = null;
0162:
0163: final Iterator blocks = cfg.trace().iterator();
0164:
0165: while (blocks.hasNext()) {
0166: block = (Block) blocks.next();
0167:
0168: if (handler.protectedBlocks().contains(block)) {
0169: if (begin == null) {
0170: begin = block;
0171: }
0172:
0173: } else if (begin != null) {
0174: // The block is no longer protected, its the end of the
0175: // protected region
0176: final TryCatch tc = new TryCatch(begin.label(),
0177: block.label(), catchBlock.label(), type);
0178: method.addTryCatch(tc);
0179:
0180: begin = null;
0181: }
0182: }
0183: }
0184: }
0185:
0186: /**
0187: * Simplifies the control flow of a method by changing jump and return
0188: * statements into gotos where appropriate.
0189: */
0190: public void simplifyControlFlow(final FlowGraph cfg) {
0191: // Remove any blocks from the CFG that consist of solely jumps
0192: removeEmptyBlocks(cfg);
0193:
0194: cfg.visit(new TreeVisitor() {
0195: public void visitJsrStmt(final JsrStmt stmt) {
0196: final Subroutine sub = stmt.sub();
0197:
0198: // If there is only 1 path through the sub, replace both
0199: // the jsr and the ret with gotos.
0200: if (sub.numPaths() == 1) {
0201: final Block exit = sub.exit();
0202:
0203: // Remember that it is not required for a subroutine to have
0204: // a ret. So, no exit block may be identified and we'll
0205: // have to make sure one exists.
0206: if (exit != null) {
0207: final JumpStmt oldJump = (JumpStmt) exit.tree()
0208: .lastStmt();
0209: final JumpStmt jump = new GotoStmt(stmt
0210: .follow());
0211: jump.catchTargets().addAll(
0212: oldJump.catchTargets());
0213: oldJump.replaceWith(jump);
0214: }
0215:
0216: final JumpStmt jump = new GotoStmt(sub.entry());
0217: jump.catchTargets().addAll(stmt.catchTargets());
0218: stmt.replaceWith(jump);
0219:
0220: // The subroutine is no longer really a subroutine
0221: cfg.removeSub(sub);
0222:
0223: // Clean up the CFG by removing all AddressStoreStmts that
0224: // store the address of the "removed" subroutine.
0225: cfg.visit(new TreeVisitor() {
0226: Iterator iter;
0227:
0228: public void visitTree(final Tree tree) {
0229: iter = tree.stmts().iterator();
0230:
0231: while (iter.hasNext()) {
0232: final Stmt s = (Stmt) iter.next();
0233:
0234: if (s instanceof AddressStoreStmt) {
0235: final AddressStoreStmt store = (AddressStoreStmt) s;
0236:
0237: if (store.sub() == sub) {
0238: iter.remove();
0239: }
0240: }
0241: }
0242: }
0243: });
0244: }
0245: }
0246:
0247: public void visitStmt(final Stmt stmt) {
0248: }
0249: });
0250: }
0251:
0252: /**
0253: * Replace PhiStmts with copies that accomplish what the PhiStmts represent.
0254: * Then remove the PhiStmts from the control flow graph.
0255: */
0256: public void replacePhis(final FlowGraph cfg) {
0257: replaceCatchPhis(cfg);
0258: replaceJoinPhis(cfg);
0259:
0260: // Remove the phis.
0261: cfg.visit(new TreeVisitor() {
0262: public void visitTree(final Tree tree) {
0263: final Iterator e = tree.stmts().iterator();
0264:
0265: while (e.hasNext()) {
0266: final Stmt s = (Stmt) e.next();
0267:
0268: if (s instanceof PhiStmt) {
0269: e.remove();
0270: }
0271: }
0272: }
0273: });
0274: }
0275:
0276: /**
0277: * Replace each PhiCatchStmt with assignments at its operands' defs.
0278: */
0279: private void replaceCatchPhis(final FlowGraph cfg) {
0280: cfg.visit(new TreeVisitor() {
0281: HashMap seen = new HashMap();
0282:
0283: public void visitFlowGraph(final FlowGraph graph) {
0284: final Iterator iter = graph.catchBlocks().iterator();
0285:
0286: // Examine each block that begins an exception handler
0287: while (iter.hasNext()) {
0288: final Block block = (Block) iter.next();
0289: block.visit(this );
0290: }
0291: }
0292:
0293: public void visitPhiCatchStmt(final PhiCatchStmt phi) {
0294: final LocalExpr target = (LocalExpr) phi.target();
0295: final int index = target.index();
0296:
0297: final Iterator iter = phi.operands().iterator();
0298:
0299: // Examine every operand of the PhiCatchStmt. If necessary,
0300: // insert copies of the operand to the target after the last
0301: // occurrence of the operand.
0302: while (iter.hasNext()) {
0303: final LocalExpr expr = (LocalExpr) iter.next();
0304: final LocalExpr def = (LocalExpr) expr.def();
0305:
0306: if (def == null) {
0307: continue;
0308: }
0309:
0310: if (CodeGenerator.DEBUG) {
0311: System.out.println("inserting for " + phi
0312: + " at " + def);
0313: }
0314:
0315: BitSet s = (BitSet) seen.get(def);
0316:
0317: if (s == null) {
0318: s = new BitSet();
0319: seen.put(def, s);
0320:
0321: final BitSet t = s;
0322:
0323: // Visit the parent expression and make note of which
0324: // local variables were encountered in StoreExprs. That
0325: // is, have we already generated a copy for the operand
0326: // of
0327: // interest?
0328: def.parent().visit(new TreeVisitor() {
0329: public void visitStoreExpr(
0330: final StoreExpr expr) {
0331: if (CodeGenerator.DEBUG) {
0332: System.out
0333: .println(" merging with "
0334: + expr);
0335: }
0336:
0337: final Expr lhs = expr.target();
0338: final Expr rhs = expr.expr();
0339:
0340: if (lhs instanceof LocalExpr) {
0341: t.set(((LocalExpr) lhs).index());
0342: }
0343:
0344: if (rhs instanceof LocalExpr) {
0345: t.set(((LocalExpr) rhs).index());
0346:
0347: } else if (rhs instanceof StoreExpr) {
0348: // Visit RHS. LHS be ignored by visitNode.
0349: super .visitStoreExpr(expr);
0350: }
0351: }
0352:
0353: public void visitNode(final Node node) {
0354: }
0355: });
0356: }
0357:
0358: // If we've already inserted a copy (StoreStmt) for the
0359: // local variable, skip it
0360: if (s.get(index)) {
0361: continue;
0362: }
0363:
0364: s.set(index);
0365:
0366: Assert.isTrue(def != null);
0367:
0368: if (def.parent() instanceof Stmt) {
0369: // Insert a new Stmt to copy into the target
0370:
0371: final Stmt stmt = (Stmt) def.parent();
0372: final Stmt store = createStore(target, def);
0373: def.block().tree().addStmtAfter(store, stmt);
0374:
0375: } else {
0376: Assert
0377: .isTrue(def.parent() instanceof StoreExpr);
0378:
0379: // Replace s := r with s := (t := r)
0380: final StoreExpr p = (StoreExpr) def.parent();
0381: final Expr rhs = p.expr();
0382:
0383: if ((rhs instanceof LocalExpr)
0384: && (((LocalExpr) rhs).index() == def
0385: .index())) {
0386: // No need to insert a copy. Just change the index
0387: // (local variable to which LocalExpr is assigned)
0388: // to be
0389: // the same as the target
0390: def.setIndex(index);
0391:
0392: } else {
0393: rhs.setParent(null);
0394:
0395: // Copy the rhs into the target
0396: final StoreExpr store = new StoreExpr(
0397: (LocalExpr) target.clone(), rhs,
0398: rhs.type());
0399:
0400: p.visit(new ReplaceVisitor(rhs, store));
0401: }
0402: }
0403: }
0404: }
0405:
0406: public void visitStmt(final Stmt stmt) {
0407: }
0408: });
0409: }
0410:
0411: /**
0412: * Replace PhiJoinStmts with assignments at the end of the predecessor
0413: * blocks. Note that from now on the FUD chains are broken since there can
0414: * be more than one def of a variable.
0415: */
0416: private void replaceJoinPhis(final FlowGraph cfg) {
0417: // Go in trace order since liveness was computed under this
0418: // assumption.
0419:
0420: final Iterator iter = cfg.trace().iterator();
0421:
0422: while (iter.hasNext()) {
0423: final Block block = (Block) iter.next();
0424:
0425: if (block == cfg.sink()) {
0426: continue;
0427: }
0428:
0429: block.visit(new TreeVisitor() {
0430: public void visitPhiJoinStmt(final PhiJoinStmt stmt) {
0431: // If an operand of the Phi statement is undefined, insert
0432: // code to assign 0 to the operand. The value should never
0433: // be used, but the verifier will squawk about using an
0434: // undefined local variable.
0435:
0436: final Iterator preds = cfg.preds(stmt.block())
0437: .iterator();
0438:
0439: while (preds.hasNext()) {
0440: final Block pred = (Block) preds.next();
0441:
0442: final Expr operand = stmt.operandAt(pred);
0443:
0444: if ((stmt.target() instanceof LocalExpr)
0445: && (operand instanceof LocalExpr)) {
0446:
0447: final LocalExpr t = (LocalExpr) stmt
0448: .target();
0449: final LocalExpr s = (LocalExpr) operand;
0450:
0451: if (t.index() == s.index()) {
0452: // The target and the operand are already
0453: // allocated to
0454: // the same variable. Don't bother making a
0455: // copy.
0456: continue;
0457: }
0458: }
0459:
0460: final Tree tree = pred.tree();
0461:
0462: // Insert stores before the last stmt to ensure
0463: // we don't redefine locals used the the branch stmt.
0464: final Stmt last = tree.lastStmt();
0465:
0466: last.visitChildren(new TreeVisitor() {
0467: // The last statement in the block should be a jump.
0468: // If
0469: // the jump statement contains an expression,
0470: // replace
0471: // that expression with a stack variable. Before the
0472: // jump, insert a store of the expression into the
0473: // stack
0474: // variable. This is done so that the store to the
0475: // PhiJoinStmt's operand does not interfere with any
0476: // local variables that might appear in the
0477: // expression.
0478: //
0479: // operand = ...
0480: // JUMP (exp)
0481: // |
0482: // v
0483: // target = PhiJoin(operand)
0484: // ...
0485: // Becomes
0486: //
0487: // operand = ...
0488: // var = exp
0489: // target = operand
0490: // JUMP (var)
0491: // |
0492: // v
0493: // target = PhiJoin(operand) // Removed later
0494: // ...
0495:
0496: public void visitExpr(final Expr expr) {
0497: StackExpr var = tree.newStack(expr
0498: .type());
0499: var.setValueNumber(expr.valueNumber());
0500:
0501: final Node p = expr.parent();
0502: expr.setParent(null);
0503: p.visit(new ReplaceVisitor(expr, var));
0504:
0505: var = (StackExpr) var.clone();
0506: final StoreExpr store = new StoreExpr(
0507: var, expr, expr.type());
0508: store
0509: .setValueNumber(expr
0510: .valueNumber());
0511:
0512: final Stmt storeStmt = new ExprStmt(
0513: store);
0514: storeStmt.setValueNumber(expr
0515: .valueNumber());
0516:
0517: tree.addStmtBeforeJump(storeStmt);
0518: }
0519:
0520: public void visitStackExpr(
0521: final StackExpr expr) {
0522: }
0523: });
0524:
0525: final Stmt store = createStore(stmt.target(),
0526: operand);
0527:
0528: if (CodeGenerator.DEBUG) {
0529: System.out.println("insert for " + stmt
0530: + " " + store + " in " + pred);
0531: }
0532:
0533: tree.addStmtBeforeJump(store);
0534: }
0535: }
0536:
0537: public void visitStmt(final Stmt stmt) {
0538: }
0539: });
0540: }
0541: }
0542:
0543: /**
0544: * Removes blocks that contain no other statements than gotos, jumps,
0545: * returns, or labels. Other blocks that are invovled with the blocks being
0546: * removed are updated appropriately.
0547: */
0548: private void removeEmptyBlocks(final FlowGraph cfg) {
0549: final Set emptyBlocks = new HashSet();
0550:
0551: Iterator e = cfg.nodes().iterator();
0552:
0553: BLOCKS: while (e.hasNext()) {
0554: final Block block = (Block) e.next();
0555:
0556: // Collect any blocks that contain only gotos,
0557: // jsrs, rets, or labels.
0558: final Iterator stmts = block.tree().stmts().iterator();
0559:
0560: while (stmts.hasNext()) {
0561: final Stmt stmt = (Stmt) stmts.next();
0562:
0563: if ((stmt instanceof GotoStmt)
0564: || (stmt instanceof JsrStmt)
0565: || (stmt instanceof RetStmt)
0566: || (stmt instanceof LabelStmt)) {
0567: continue;
0568: }
0569:
0570: // The block contains something other than the above, it is
0571: // not empty.
0572: continue BLOCKS;
0573: }
0574:
0575: emptyBlocks.add(block);
0576: }
0577:
0578: // We want to keep the source, init, and sink blocks even if
0579: // they're empty
0580: emptyBlocks.remove(cfg.source());
0581: emptyBlocks.remove(cfg.init());
0582: emptyBlocks.remove(cfg.sink());
0583:
0584: // Did the CFG change?
0585: boolean changed = true;
0586:
0587: while (changed) {
0588: changed = false;
0589:
0590: // Exclude the blocks that are control dependent on other blocks.
0591: final Set empty = new HashSet(emptyBlocks);
0592: empty.removeAll(cfg.iteratedPdomFrontier(cfg.nodes()));
0593:
0594: e = empty.iterator();
0595:
0596: while (e.hasNext()) {
0597: final Block block = (Block) e.next();
0598:
0599: if (CodeGenerator.DEBUG) {
0600: System.out.println("removing empty " + block);
0601: }
0602:
0603: final Stmt last = block.tree().lastStmt();
0604:
0605: Assert.isTrue((last instanceof GotoStmt)
0606: || (last instanceof JsrStmt)
0607: || (last instanceof RetStmt));
0608:
0609: if (last instanceof GotoStmt) {
0610: // All a block does is jump to another block
0611: //
0612: // jmp ... L
0613: // L: goto M
0614: // =>
0615: // jmp ... M
0616: final Block target = ((GotoStmt) last).target();
0617:
0618: final Iterator preds = new ImmutableIterator(cfg
0619: .preds(block));
0620:
0621: while (preds.hasNext()) {
0622: final Block pred = (Block) preds.next();
0623: Assert.isTrue(pred != cfg.source());
0624:
0625: final Stmt predLast = pred.tree().lastStmt();
0626: predLast
0627: .visit(new ReplaceTarget(block, target));
0628:
0629: cfg.removeEdge(pred, block);
0630: cfg.addEdge(pred, target);
0631:
0632: changed = true;
0633: }
0634:
0635: } else if (last instanceof RetStmt) {
0636: // All a subroutine does is return
0637:
0638: final Iterator preds = new ImmutableIterator(cfg
0639: .preds(block));
0640:
0641: while (preds.hasNext()) {
0642: final Block pred = (Block) preds.next();
0643: Assert.isTrue(pred != cfg.source());
0644:
0645: final Stmt predLast = pred.tree().lastStmt();
0646:
0647: if (predLast instanceof JsrStmt) {
0648: // The previous block is the jsr...
0649: //
0650: // jsr L ret to M
0651: // M: ...
0652: // L: ret // The body of the subroutine is empty
0653: // =>
0654: // goto M
0655: // M: ...
0656:
0657: final JsrStmt stmt = (JsrStmt) predLast;
0658:
0659: final JumpStmt jump = new GotoStmt(stmt
0660: .follow());
0661: jump.catchTargets().addAll(
0662: stmt.catchTargets());
0663: stmt.replaceWith(jump);
0664:
0665: stmt.sub().removePathsContaining(pred);
0666:
0667: } else if (predLast instanceof GotoStmt) {
0668: // The previous block ends in a goto. Move the ret
0669: // up
0670: // into the previous block, update catch targets of
0671: // any
0672: // exceptions thrown by the block terminated by the
0673: // jump, and update the subroutine's exit block to
0674: // be
0675: // the previous block (in which the ret now
0676: // resides).
0677:
0678: final JumpStmt jump = (RetStmt) last
0679: .clone();
0680: jump.catchTargets().addAll(
0681: ((JumpStmt) predLast)
0682: .catchTargets());
0683: predLast.replaceWith(jump);
0684: ((RetStmt) last).sub().setExit(pred);
0685: }
0686:
0687: // Remove the block from the CFG
0688: cfg.succs(pred).remove(block);
0689: cfg.succs(pred).addAll(cfg.succs(block));
0690:
0691: changed = true;
0692: }
0693:
0694: } else if (last instanceof JsrStmt) {
0695: // All the block does is a jsr
0696: //
0697: // goto L
0698: // L: jsr M
0699: // =>
0700: // jsr M
0701: // L: jsr M
0702: final Iterator preds = new ImmutableIterator(cfg
0703: .preds(block));
0704:
0705: while (preds.hasNext()) {
0706: final Block pred = (Block) preds.next();
0707: Assert.isTrue(pred != cfg.source());
0708:
0709: final Stmt predLast = pred.tree().lastStmt();
0710:
0711: if (predLast instanceof GotoStmt) {
0712: final JsrStmt stmt = (JsrStmt) last;
0713:
0714: final JumpStmt jump = new JsrStmt(stmt
0715: .sub(), stmt.follow());
0716: jump.catchTargets().addAll(
0717: ((JumpStmt) predLast)
0718: .catchTargets());
0719: predLast.replaceWith(jump);
0720:
0721: // The block is no longer a viable caller of the
0722: // subroutine
0723: stmt.sub().removePathsContaining(block);
0724: stmt.sub().addPath(pred, stmt.follow());
0725:
0726: cfg.addEdge(pred, stmt.sub().entry());
0727: cfg.removeEdge(pred, block);
0728:
0729: changed = true;
0730: }
0731: }
0732:
0733: } else {
0734: throw new RuntimeException();
0735: }
0736: }
0737:
0738: if (changed) {
0739: cfg.removeUnreachable();
0740:
0741: // Remove any empty blocks that we've already deleted.
0742: emptyBlocks.retainAll(cfg.nodes());
0743: }
0744: }
0745: }
0746:
0747: /**
0748: * Allocate "registers" (LocalVariables) for the return addresses for each
0749: * subroutine in the method.
0750: *
0751: * @param cfg
0752: * Control flow graph for the method
0753: * @param alloc
0754: * Allocation (and information about) the local variables in the
0755: * method.
0756: *
0757: * @see LocalVariable
0758: * @see LocalExpr
0759: */
0760: public void allocReturnAddresses(final FlowGraph cfg,
0761: final RegisterAllocator alloc) {
0762: // Allocate registers for the returnAddresses. Don't bother trying
0763: // to minimize the number of locals, just get a new one.
0764: final Iterator e = cfg.subroutines().iterator();
0765:
0766: while (e.hasNext()) {
0767: final Subroutine sub = (Subroutine) e.next();
0768: final LocalVariable var = alloc.newLocal(Type.ADDRESS);
0769: sub.setReturnAddress(var);
0770: }
0771: }
0772:
0773: /**
0774: * Create a ExprStmt that initializes a target variable to a default value
0775: * based on the type of the target.
0776: */
0777: protected Stmt createUndefinedStore(final VarExpr target) {
0778: if (target.type().isReference()) {
0779: return new ExprStmt(new StoreExpr(target, new ConstantExpr(
0780: null, Type.OBJECT), target.type()));
0781: }
0782:
0783: if (target.type().isIntegral()) {
0784: return new ExprStmt(new StoreExpr(target, new ConstantExpr(
0785: new Integer(0), Type.INTEGER), target.type()));
0786: }
0787:
0788: if (target.type().equals(Type.LONG)) {
0789: return new ExprStmt(new StoreExpr(target, new ConstantExpr(
0790: new Long(0), Type.LONG), target.type()));
0791: }
0792:
0793: if (target.type().equals(Type.FLOAT)) {
0794: return new ExprStmt(new StoreExpr(target, new ConstantExpr(
0795: new Float(0.0F), Type.FLOAT), target.type()));
0796: }
0797:
0798: if (target.type().equals(Type.DOUBLE)) {
0799: return new ExprStmt(new StoreExpr(target, new ConstantExpr(
0800: new Double(0.0), Type.DOUBLE), target.type()));
0801: }
0802:
0803: throw new RuntimeException("Illegal type: " + target.type());
0804: }
0805:
0806: /**
0807: * Returns an ExprStmt that contains a store of the source into the target.
0808: */
0809: protected Stmt createStore(VarExpr target, final Expr source) {
0810: target = (VarExpr) target.clone();
0811:
0812: // Source is an undefined variable, initialize it
0813: if ((source instanceof VarExpr) && (source.def() == null)) {
0814: return createUndefinedStore(target);
0815: }
0816:
0817: return new ExprStmt(new StoreExpr(target,
0818: (Expr) source.clone(), target.type()));
0819: }
0820:
0821: /*
0822: * Using an InstructionVisitor generate the code...
0823: */
0824:
0825: // Several of the visit methods contain code for stack
0826: // optimization (place dups and swaps and eliminate temporary
0827: // variables). Nodes where swaps are to be placed are so
0828: // marked. The markings may appear at IfCmpStmt, InitStmt,
0829: // StoreExpr, ArithExpr, ArrayRefExpr, CallMethodExpr,
0830: // CallStaticExpr, NewMultiArrayExpr, ShiftExpr.
0831: public void visitExpr(final Expr expr) {
0832: throw new RuntimeException("Unhandled expression type: "
0833: + expr.getClass().getName());
0834: }
0835:
0836: public void visitExprStmt(final ExprStmt stmt) {
0837: if (CodeGenerator.DEBUG) {
0838: System.out.println("code for " + stmt);
0839: }
0840:
0841: stmt.visitChildren(this );
0842:
0843: genPostponed(stmt);
0844:
0845: if (!(stmt.expr() instanceof StoreExpr)) {
0846: if (!stmt.expr().type().isVoid()) {
0847: if (stmt.expr().type().isWide()) {
0848: method.addInstruction(Opcode.opcx_pop2);
0849: stackHeight -= 2;
0850:
0851: } else {
0852: method.addInstruction(Opcode.opcx_pop);
0853: stackHeight -= 1;
0854: }
0855: }
0856: }
0857: }
0858:
0859: public void visitInitStmt(final InitStmt stmt) {
0860: if (CodeGenerator.DEBUG) {
0861: System.out.println("code for " + stmt);
0862: }
0863: }
0864:
0865: public void visitGotoStmt(final GotoStmt stmt) {
0866: if (CodeGenerator.DEBUG) {
0867: System.out.println("code for " + stmt);
0868: }
0869:
0870: genPostponed(stmt);
0871:
0872: final Block target = stmt.target();
0873:
0874: if (target != next) {
0875: method.addInstruction(Opcode.opcx_goto, stmt.target()
0876: .label());
0877: }
0878: }
0879:
0880: public void visitIfCmpStmt(final IfCmpStmt stmt) {
0881: if (CodeGenerator.DEBUG) {
0882: System.out.println("code for " + stmt);
0883: }
0884:
0885: final Block t = stmt.trueTarget();
0886: final Block f = stmt.falseTarget();
0887:
0888: if (f == next) {
0889: // Fall through to the false branch.
0890: genIfCmpStmt(stmt);
0891:
0892: } else if (t == next) {
0893: // Fall through to the true branch.
0894: stmt.negate();
0895: genIfCmpStmt(stmt);
0896:
0897: } else {
0898: // Generate a goto to the false branch after the if statement.
0899: genIfCmpStmt(stmt);
0900:
0901: method.addLabel(method.newLabelTrue()); // Tom changed to say "True"
0902: method.addInstruction(Opcode.opcx_goto, f.label());
0903: }
0904: }
0905:
0906: private void genIfCmpStmt(final IfCmpStmt stmt) {
0907: int opcode;
0908:
0909: stmt.visitChildren(this );
0910:
0911: genPostponed(stmt);
0912:
0913: final int cmp = stmt.comparison();
0914:
0915: if (stmt.left().type().isReference()) {
0916: Assert.isTrue(stmt.right().type().isReference(),
0917: "Illegal statement: " + stmt);
0918:
0919: switch (cmp) {
0920: case IfStmt.EQ:
0921: opcode = Opcode.opcx_if_acmpeq;
0922: break;
0923: case IfStmt.NE:
0924: opcode = Opcode.opcx_if_acmpne;
0925: break;
0926: default:
0927: throw new RuntimeException();
0928: }
0929:
0930: } else {
0931: Assert.isTrue(stmt.left().type().isIntegral(),
0932: "Illegal statement: " + stmt);
0933: Assert.isTrue(stmt.right().type().isIntegral(),
0934: "Illegal statement: " + stmt);
0935:
0936: switch (cmp) {
0937: case IfStmt.EQ:
0938: opcode = Opcode.opcx_if_icmpeq;
0939: break;
0940: case IfStmt.NE:
0941: opcode = Opcode.opcx_if_icmpne;
0942: break;
0943: case IfStmt.GT:
0944: opcode = Opcode.opcx_if_icmpgt;
0945: break;
0946: case IfStmt.GE:
0947: opcode = Opcode.opcx_if_icmpge;
0948: break;
0949: case IfStmt.LT:
0950: opcode = Opcode.opcx_if_icmplt;
0951: break;
0952: case IfStmt.LE:
0953: opcode = Opcode.opcx_if_icmple;
0954: break;
0955: default:
0956: throw new RuntimeException();
0957: }
0958: }
0959:
0960: method.addInstruction(opcode, stmt.trueTarget().label());
0961: stackHeight -= 2;
0962: }
0963:
0964: public void visitIfZeroStmt(final IfZeroStmt stmt) {
0965: if (CodeGenerator.DEBUG) {
0966: System.out.println("code for " + stmt);
0967: }
0968:
0969: final Block t = stmt.trueTarget();
0970: final Block f = stmt.falseTarget();
0971:
0972: if (f == next) {
0973: // Fall through to the false branch.
0974: genIfZeroStmt(stmt);
0975: } else if (t == next) {
0976: // Fall through to the true branch.
0977: stmt.negate();
0978: genIfZeroStmt(stmt);
0979: } else {
0980: // Generate a goto to the false branch after the if statement.
0981: genIfZeroStmt(stmt);
0982: method.addLabel(method.newLabelTrue()); // Tom added "True"
0983: method.addInstruction(Opcode.opcx_goto, f.label());
0984: }
0985: }
0986:
0987: private void genIfZeroStmt(final IfZeroStmt stmt) {
0988: int opcode;
0989:
0990: stmt.expr().visit(this );
0991:
0992: genPostponed(stmt);
0993:
0994: final int cmp = stmt.comparison();
0995:
0996: if (stmt.expr().type().isReference()) {
0997: switch (cmp) {
0998: case IfStmt.EQ:
0999: opcode = Opcode.opcx_ifnull;
1000: break;
1001: case IfStmt.NE:
1002: opcode = Opcode.opcx_ifnonnull;
1003: break;
1004: default:
1005: throw new RuntimeException();
1006: }
1007:
1008: } else {
1009: Assert.isTrue(stmt.expr().type().isIntegral(),
1010: "Illegal statement: " + stmt);
1011:
1012: switch (cmp) {
1013: case IfStmt.EQ:
1014: opcode = Opcode.opcx_ifeq;
1015: break;
1016: case IfStmt.NE:
1017: opcode = Opcode.opcx_ifne;
1018: break;
1019: case IfStmt.GT:
1020: opcode = Opcode.opcx_ifgt;
1021: break;
1022: case IfStmt.GE:
1023: opcode = Opcode.opcx_ifge;
1024: break;
1025: case IfStmt.LT:
1026: opcode = Opcode.opcx_iflt;
1027: break;
1028: case IfStmt.LE:
1029: opcode = Opcode.opcx_ifle;
1030: break;
1031: default:
1032: throw new RuntimeException();
1033: }
1034: }
1035: method.addInstruction(opcode, stmt.trueTarget().label());
1036: stackHeight -= 1;
1037: }
1038:
1039: public void visitLabelStmt(final LabelStmt stmt) {
1040: if (CodeGenerator.DEBUG) {
1041: System.out.println("code for " + stmt);
1042: }
1043:
1044: stmt.visitChildren(this );
1045:
1046: genPostponed(stmt);
1047:
1048: method.addLabel(stmt.label());
1049: }
1050:
1051: public void visitMonitorStmt(final MonitorStmt stmt) {
1052: if (CodeGenerator.DEBUG) {
1053: System.out.println("code for " + stmt);
1054: }
1055:
1056: stmt.visitChildren(this );
1057:
1058: genPostponed(stmt);
1059:
1060: if (stmt.kind() == MonitorStmt.ENTER) {
1061: method.addInstruction(Opcode.opcx_monitorenter);
1062: stackHeight -= 1;
1063:
1064: } else if (stmt.kind() == MonitorStmt.EXIT) {
1065: method.addInstruction(Opcode.opcx_monitorexit);
1066: stackHeight -= 1;
1067:
1068: } else {
1069: throw new IllegalArgumentException();
1070: }
1071: }
1072:
1073: public void visitPhiStmt(final PhiStmt stmt) {
1074: throw new RuntimeException("Cannot generate code for " + stmt);
1075: }
1076:
1077: public void visitRCExpr(final RCExpr expr) {
1078: expr.visitChildren(this );
1079:
1080: genPostponed(expr);
1081:
1082: // Move the rc forward as far as possible.
1083: //
1084: // For example, for the expression:
1085: //
1086: // rc(x).m(rc(a).b)
1087: //
1088: // we want to generate:
1089: //
1090: // aload x
1091: // aload a
1092: // rc 0
1093: // getfield <A.b>
1094: // rc 1
1095: // invoke <X.m>
1096: //
1097: // rather than:
1098: //
1099: // aload x
1100: // rc 0
1101: // aload a
1102: // rc 0
1103: // getfield <A.b>
1104: // invoke <X.m>
1105: //
1106: Instruction postpone = null;
1107:
1108: Node parent = expr.parent();
1109:
1110: // If the parent is wrapped in a ZeroCheckExpr, then look at the
1111: // parent's parent.
1112:
1113: if (parent instanceof ZeroCheckExpr) {
1114: parent = parent.parent();
1115: }
1116:
1117: // If the depth is going to be > 0, postpone the rc instruction
1118: // to just before the getfield, putfield, invoke, xaload, xastore, etc.
1119: // If the stack depth for the rc is going to be 0, the rc will (be)
1120: // the next instruction generated anyway, so don't postpone.
1121:
1122: if (parent instanceof ArrayRefExpr) {
1123: final ArrayRefExpr p = (ArrayRefExpr) parent;
1124:
1125: if (expr == p.array()) {
1126: if (p.isDef()) {
1127: // a[i] := r
1128: // Stack at the xastore: ... a i r
1129: postpone = new Instruction(Opcode.opcx_rc,
1130: new Integer(p.type().stackHeight() + 1));
1131: } else {
1132: // use a[i]
1133: // Stack at the xaload: ... a i
1134: postpone = new Instruction(Opcode.opcx_rc,
1135: new Integer(1));
1136: }
1137: }
1138:
1139: } else if (parent instanceof CallMethodExpr) {
1140: final CallMethodExpr p = (CallMethodExpr) parent;
1141:
1142: if (expr == p.receiver()) {
1143: // a.m(b, c)
1144: // Stack at the invoke: ... a b c
1145: final MemberRef method = p.method();
1146: final int depth = method.nameAndType().type()
1147: .stackHeight();
1148: postpone = new Instruction(Opcode.opcx_rc, new Integer(
1149: depth));
1150: }
1151:
1152: } else if (parent instanceof FieldExpr) {
1153: final FieldExpr p = (FieldExpr) parent;
1154:
1155: if (expr == p.object()) {
1156: if (p.isDef()) {
1157: // a.b := r
1158: // Stack at the putfield: ... a r
1159: postpone = new Instruction(Opcode.opcx_rc,
1160: new Integer(p.type().stackHeight()));
1161: }
1162: }
1163: }
1164:
1165: if (postpone == null) {
1166: int depth = 0;
1167:
1168: if (expr.expr() instanceof StackExpr) {
1169: // If the rc works on a StackExpr, calculate its depth in the
1170: // stack. In all other cases, the rc will operate on whatever
1171: // is on top of the stack.
1172: final StackExpr stackVar = (StackExpr) expr.expr();
1173: depth = stackHeight - stackVar.index() - 1;
1174: }
1175:
1176: method.addInstruction(Opcode.opcx_rc, new Integer(depth));
1177:
1178: } else {
1179: postponedInstructions.put(parent, postpone);
1180: }
1181: }
1182:
1183: public void visitUCExpr(final UCExpr expr) {
1184: expr.visitChildren(this );
1185:
1186: if (true) {
1187: return;
1188: }
1189:
1190: genPostponed(expr);
1191:
1192: // Move the uc forward as far as possible.
1193: Instruction postpone = null;
1194:
1195: final Node parent = expr.parent();
1196:
1197: // If the depth is going to be > 0, postpone the uc instruction
1198: // to just before the putfield. If the stack depth for the
1199: // uc is going to be 0, the uc will the next instruction
1200: // generated anyway, so don't postpone.
1201:
1202: if (parent instanceof FieldExpr) {
1203: final FieldExpr p = (FieldExpr) parent;
1204:
1205: if (expr == p.object()) {
1206: if (p.isDef()) {
1207: // a.b := r
1208: // Stack at the putfield: ... a r
1209: if (expr.kind() == UCExpr.POINTER) {
1210: postpone = new Instruction(Opcode.opcx_aupdate,
1211: new Integer(p.type().stackHeight()));
1212:
1213: } else if (expr.kind() == UCExpr.SCALAR) {
1214: postpone = new Instruction(Opcode.opcx_supdate,
1215: new Integer(p.type().stackHeight()));
1216:
1217: } else {
1218: throw new RuntimeException();
1219: }
1220: }
1221: }
1222: }
1223:
1224: if (postpone == null) {
1225: int depth = 0;
1226:
1227: if (expr.expr() instanceof StackExpr) {
1228: // If the UCExpr operates on a stack variable, use that to
1229: // determine the depth. In all other cases, use 0.
1230: final StackExpr stackVar = (StackExpr) expr.expr();
1231: depth = stackHeight - stackVar.index() - 1;
1232: }
1233:
1234: if (expr.kind() == UCExpr.POINTER) {
1235: method.addInstruction(Opcode.opcx_aupdate, new Integer(
1236: depth));
1237: } else if (expr.kind() == UCExpr.SCALAR) {
1238: method.addInstruction(Opcode.opcx_supdate, new Integer(
1239: depth));
1240: } else {
1241: throw new RuntimeException();
1242: }
1243:
1244: } else {
1245: postponedInstructions.put(parent, postpone);
1246: }
1247: }
1248:
1249: public void visitRetStmt(final RetStmt stmt) {
1250: if (CodeGenerator.DEBUG) {
1251: System.out.println("code for " + stmt);
1252: }
1253:
1254: genPostponed(stmt);
1255:
1256: final Subroutine sub = stmt.sub();
1257: Assert.isTrue(sub.returnAddress() != null);
1258: method.addInstruction(Opcode.opcx_ret, sub.returnAddress());
1259: }
1260:
1261: public void visitReturnExprStmt(final ReturnExprStmt stmt) {
1262: if (CodeGenerator.DEBUG) {
1263: System.out.println("code for " + stmt);
1264: }
1265:
1266: stmt.visitChildren(this );
1267:
1268: genPostponed(stmt);
1269:
1270: final Type type = stmt.expr().type();
1271:
1272: // Stack should be empty after return
1273:
1274: if (type.isReference()) {
1275: method.addInstruction(Opcode.opcx_areturn);
1276: stackHeight = 0;
1277: } else if (type.isIntegral()) {
1278: method.addInstruction(Opcode.opcx_ireturn);
1279: stackHeight = 0;
1280: } else if (type.equals(Type.LONG)) {
1281: method.addInstruction(Opcode.opcx_lreturn);
1282: stackHeight = 0;
1283: } else if (type.equals(Type.FLOAT)) {
1284: method.addInstruction(Opcode.opcx_freturn);
1285: stackHeight = 0;
1286: } else if (type.equals(Type.DOUBLE)) {
1287: method.addInstruction(Opcode.opcx_dreturn);
1288: stackHeight = 0;
1289: }
1290: }
1291:
1292: public void visitReturnStmt(final ReturnStmt stmt) {
1293: if (CodeGenerator.DEBUG) {
1294: System.out.println("code for " + stmt);
1295: }
1296:
1297: genPostponed(stmt);
1298:
1299: stmt.visitChildren(this );
1300: method.addInstruction(Opcode.opcx_return);
1301:
1302: // Stack height is zero after return
1303: stackHeight = 0;
1304: }
1305:
1306: public void visitStoreExpr(final StoreExpr expr) {
1307: if (CodeGenerator.DEBUG) {
1308: System.out.println("code for " + expr);
1309: }
1310:
1311: final MemExpr lhs = expr.target();
1312: final Expr rhs = expr.expr();
1313:
1314: boolean returnsValue = !(expr.parent() instanceof ExprStmt);
1315:
1316: // eliminate the store if the both sides have the same target
1317:
1318: if (!returnsValue) {
1319: if ((lhs instanceof LocalExpr)
1320: && (rhs instanceof LocalExpr)) {
1321:
1322: // The second condition checks that the right sides have indeed
1323: // been stored-- otherwise (ie, if we're just keeping it on the
1324: // stack), we should not eliminate this store
1325:
1326: if ((((LocalExpr) lhs).index() == ((LocalExpr) rhs)
1327: .index())
1328:
1329: && (!CodeGenerator.OPT_STACK || currentSO
1330: .shouldStore(((LocalExpr) ((LocalExpr) rhs)
1331: .def())))) {
1332: return;
1333: }
1334: }
1335:
1336: // Special case to handle L := L + k.
1337: // Generate "iinc L, k" instead of "iload L; ldc k; iadd; istore L".
1338: //
1339: // TODO: for L := M + k, generate "iload M; istore L; iinc L, k".
1340: //
1341:
1342: /*
1343: * This next special case was modified for stack optimization. If L
1344: * is marked for a dup, the fact that its value is never on the
1345: * stack means we don't have anything to dup-- we need to load
1346: * instead. (Things get more complicated if it was marked for a
1347: * dup_x2, but that's not likely to happen)
1348: */
1349:
1350: if ((lhs instanceof LocalExpr) && lhs.type().isIntegral()) {
1351: Integer value = null;
1352: // eliminate the store if the both sides have the same target
1353:
1354: final int index = ((LocalExpr) lhs).index();
1355:
1356: if (rhs instanceof ArithExpr) {
1357: final ArithExpr arith = (ArithExpr) rhs;
1358:
1359: final Expr left = arith.left();
1360: final Expr right = arith.right();
1361:
1362: if ((left instanceof LocalExpr)
1363: && (index == ((LocalExpr) left).index())
1364: && (right instanceof ConstantExpr)) {
1365:
1366: final ConstantExpr c = (ConstantExpr) right;
1367:
1368: if (c.value() instanceof Integer) {
1369: value = (Integer) c.value();
1370: }
1371:
1372: } else if ((right instanceof LocalExpr)
1373: && (index == ((LocalExpr) right).index())
1374: && (left instanceof ConstantExpr)
1375: && (arith.operation() == ArithExpr.ADD)) {
1376:
1377: // This will not work for x = c - x because it is not
1378: // the
1379: // same as x = x - c.
1380:
1381: final ConstantExpr c = (ConstantExpr) left;
1382:
1383: if (c.value() instanceof Integer) {
1384: value = (Integer) c.value();
1385: }
1386: }
1387:
1388: if ((value != null)
1389: && (arith.operation() == ArithExpr.SUB)) {
1390: value = new Integer(-value.intValue());
1391: } else if (arith.operation() != ArithExpr.ADD) {
1392: value = null;
1393: }
1394: }
1395:
1396: if (value != null) {
1397: final int incr = value.intValue();
1398:
1399: if (incr == 0) {
1400: // No need to increment by 0.
1401:
1402: // for a better understanding of what's going on in
1403: // these
1404: // additions, see VisitLocalExpr, where we do basically
1405: // the
1406: // same thing.
1407:
1408: if (CodeGenerator.OPT_STACK) {
1409: int dups, dup_x1s, dup_x2s;
1410: dups = currentSO.dups((LocalExpr) lhs);
1411: dup_x1s = currentSO
1412: .dup_x1s((LocalExpr) lhs);
1413: dup_x2s = currentSO
1414: .dup_x2s((LocalExpr) lhs);
1415: for (int i = 0; i < dup_x2s; i++) {
1416: // This is really awful, but be consoled in that
1417: // it is
1418: // highly improbable to happen... this is just
1419: // to make correct code in the chance that we
1420: // have something like this.
1421: method.addInstruction(Opcode.opcx_ldc,
1422: new Integer(0));
1423: method
1424: .addInstruction(Opcode.opc_dup_x2);
1425: method.addInstruction(Opcode.opc_pop);
1426: stackHeight += 1;
1427: }
1428: for (int i = 0; i < dup_x1s; i++) {
1429: method.addInstruction(Opcode.opcx_ldc,
1430: new Integer(0));
1431: method.addInstruction(Opcode.opc_swap);
1432: stackHeight += 1;
1433: }
1434: for (int i = 0; i < dups; i++) {
1435: method.addInstruction(Opcode.opcx_ldc,
1436: new Integer(0));
1437: stackHeight += 1;
1438: }
1439: }
1440:
1441: return;
1442:
1443: } else if ((short) incr == incr) {
1444: // Only generate an iinc if the increment fits in
1445: // a short.
1446: method
1447: .addInstruction(
1448: Opcode.opcx_iinc,
1449: new IncOperand(
1450: new LocalVariable(index),
1451: incr));
1452:
1453: if (CodeGenerator.OPT_STACK) {
1454: int dups, dup_x1s, dup_x2s;
1455: dups = currentSO.dups((LocalExpr) lhs);
1456: dup_x1s = currentSO
1457: .dup_x1s((LocalExpr) lhs);
1458: dup_x2s = currentSO
1459: .dup_x2s((LocalExpr) lhs);
1460: for (int i = 0; i < dup_x2s; i++) {
1461: method.addInstruction(
1462: Opcode.opcx_istore,
1463: new LocalVariable(
1464: ((LocalExpr) lhs)
1465: .index()));
1466: method
1467: .addInstruction(Opcode.opc_dup_x2);
1468: method.addInstruction(Opcode.opc_pop);
1469: stackHeight += 1;
1470: }
1471: for (int i = 0; i < dup_x1s; i++) {
1472: method.addInstruction(
1473: Opcode.opcx_iload,
1474: new LocalVariable(
1475: ((LocalExpr) lhs)
1476: .index()));
1477: method.addInstruction(Opcode.opc_swap);
1478: stackHeight += 1;
1479: }
1480: for (int i = 0; i < dups; i++) {
1481: method.addInstruction(
1482: Opcode.opcx_iload,
1483: new LocalVariable(
1484: ((LocalExpr) lhs)
1485: .index()));
1486: stackHeight += 1;
1487: }
1488: }
1489:
1490: return;
1491: }
1492: }
1493: }
1494: }
1495:
1496: // Generate, and return the value.
1497: lhs.visitChildren(this );
1498: rhs.visit(this );
1499:
1500: if (returnsValue) {
1501: if (lhs instanceof ArrayRefExpr) {
1502: // array index rhs --> rhs array index rhs
1503: if (rhs.type().isWide()) {
1504: method.addInstruction(Opcode.opcx_dup2_x2);
1505: stackHeight += 2;
1506: } else {
1507: method.addInstruction(Opcode.opcx_dup_x2);
1508: stackHeight += 1;
1509: }
1510:
1511: } else if (lhs instanceof FieldExpr) {
1512: // object rhs --> rhs object rhs
1513: if (rhs.type().isWide()) {
1514: method.addInstruction(Opcode.opcx_dup2_x1);
1515: stackHeight += 2;
1516: } else {
1517: method.addInstruction(Opcode.opcx_dup_x1);
1518: stackHeight += 1;
1519: }
1520:
1521: } else {
1522: // rhs --> rhs rhs
1523: if (rhs.type().isWide()) {
1524: method.addInstruction(Opcode.opcx_dup2);
1525: stackHeight += 2;
1526: } else {
1527: method.addInstruction(Opcode.opcx_dup);
1528: stackHeight += 1;
1529: }
1530: }
1531: }
1532:
1533: genPostponed(expr);
1534: lhs.visitOnly(this );
1535: }
1536:
1537: public void visitAddressStoreStmt(final AddressStoreStmt stmt) {
1538: if (CodeGenerator.DEBUG) {
1539: System.out.println("code for " + stmt);
1540: }
1541:
1542: genPostponed(stmt);
1543:
1544: final Subroutine sub = stmt.sub();
1545: Assert.isTrue(sub.returnAddress() != null);
1546: method.addInstruction(Opcode.opcx_astore, sub.returnAddress());
1547: stackHeight -= 1;
1548: }
1549:
1550: public void visitJsrStmt(final JsrStmt stmt) {
1551: if (CodeGenerator.DEBUG) {
1552: System.out.println("code for " + stmt);
1553: }
1554:
1555: genPostponed(stmt);
1556:
1557: final Block entry = stmt.sub().entry();
1558: method.addInstruction(Opcode.opcx_jsr, entry.label());
1559: stackHeight += 1;
1560:
1561: if (stmt.follow() != next) {
1562: method.addLabel(method.newLabelTrue());
1563: method.addInstruction(Opcode.opcx_goto, stmt.follow()
1564: .label());
1565: }
1566: }
1567:
1568: public void visitSwitchStmt(final SwitchStmt stmt) {
1569: if (CodeGenerator.DEBUG) {
1570: System.out.println("code for " + stmt);
1571: }
1572:
1573: stmt.visitChildren(this );
1574:
1575: genPostponed(stmt);
1576:
1577: final Label[] targets = new Label[stmt.targets().length];
1578:
1579: for (int i = 0; i < targets.length; i++) {
1580: targets[i] = stmt.targets()[i].label();
1581: }
1582:
1583: method.addInstruction(Opcode.opcx_switch, new Switch(stmt
1584: .defaultTarget().label(), targets, stmt.values()));
1585: stackHeight -= 1;
1586: }
1587:
1588: public void visitStackManipStmt(final StackManipStmt stmt) {
1589: if (CodeGenerator.DEBUG) {
1590: System.out.println("code for " + stmt);
1591: }
1592:
1593: genPostponed(stmt);
1594:
1595: // All the children are stack variables, so don't so anything.
1596:
1597: switch (stmt.kind()) {
1598: case StackManipStmt.SWAP:
1599: method.addInstruction(Opcode.opcx_swap);
1600: break;
1601: case StackManipStmt.DUP:
1602: method.addInstruction(Opcode.opcx_dup);
1603: stackHeight += 1;
1604: break;
1605: case StackManipStmt.DUP_X1:
1606: method.addInstruction(Opcode.opcx_dup_x1);
1607: stackHeight += 1;
1608: break;
1609: case StackManipStmt.DUP_X2:
1610: method.addInstruction(Opcode.opcx_dup_x2);
1611: stackHeight += 1;
1612: break;
1613: case StackManipStmt.DUP2:
1614: method.addInstruction(Opcode.opcx_dup2);
1615: stackHeight += 2;
1616: break;
1617: case StackManipStmt.DUP2_X1:
1618: method.addInstruction(Opcode.opcx_dup2_x1);
1619: stackHeight += 2;
1620: break;
1621: case StackManipStmt.DUP2_X2:
1622: method.addInstruction(Opcode.opcx_dup2_x2);
1623: stackHeight += 2;
1624: break;
1625: }
1626: }
1627:
1628: public void visitThrowStmt(final ThrowStmt stmt) {
1629: if (CodeGenerator.DEBUG) {
1630: System.out.println("code for " + stmt);
1631: }
1632:
1633: stmt.visitChildren(this );
1634:
1635: genPostponed(stmt);
1636:
1637: method.addInstruction(Opcode.opcx_athrow);
1638: }
1639:
1640: public void visitSCStmt(final SCStmt stmt) {
1641: stmt.visitChildren(this );
1642: genPostponed(stmt);
1643: method.addInstruction(Opcode.opcx_aswizzle);
1644: stackHeight -= 2;
1645: }
1646:
1647: public void visitSRStmt(final SRStmt stmt) {
1648: stmt.visitChildren(this );
1649: genPostponed(stmt);
1650: method.addInstruction(Opcode.opcx_aswrange);
1651: stackHeight -= 3;
1652: }
1653:
1654: public void visitArithExpr(final ArithExpr expr) {
1655: expr.visitChildren(this );
1656:
1657: genPostponed(expr);
1658:
1659: final int[][] opcode = new int[][] {
1660: { Opcode.opcx_iadd, Opcode.opcx_ladd, Opcode.opcx_fadd,
1661: Opcode.opcx_dadd },
1662: { Opcode.opcx_iand, Opcode.opcx_land, Opcode.opcx_nop,
1663: Opcode.opcx_nop },
1664: { Opcode.opcx_idiv, Opcode.opcx_ldiv, Opcode.opcx_fdiv,
1665: Opcode.opcx_ddiv },
1666: { Opcode.opcx_imul, Opcode.opcx_lmul, Opcode.opcx_fmul,
1667: Opcode.opcx_dmul },
1668: { Opcode.opcx_ior, Opcode.opcx_lor, Opcode.opcx_nop,
1669: Opcode.opcx_nop },
1670: { Opcode.opcx_irem, Opcode.opcx_lrem, Opcode.opcx_frem,
1671: Opcode.opcx_drem },
1672: { Opcode.opcx_isub, Opcode.opcx_lsub, Opcode.opcx_fsub,
1673: Opcode.opcx_dsub },
1674: { Opcode.opcx_ixor, Opcode.opcx_lxor, Opcode.opcx_nop,
1675: Opcode.opcx_nop },
1676: { Opcode.opcx_nop, Opcode.opcx_lcmp, Opcode.opcx_nop,
1677: Opcode.opcx_nop },
1678: { Opcode.opcx_nop, Opcode.opcx_nop, Opcode.opcx_fcmpl,
1679: Opcode.opcx_dcmpl },
1680: { Opcode.opcx_nop, Opcode.opcx_nop, Opcode.opcx_fcmpg,
1681: Opcode.opcx_dcmpg } };
1682:
1683: final int[][] stackChange = new int[][] { { -1, -2, -1, -2 },
1684: { -1, -2, 0, 0 }, { -1, -2, -1, -2 },
1685: { -1, -2, -1, -2 }, { -1, -2, 0, 0 },
1686: { -1, -2, -1, -2 }, { -1, -2, -1, -2 },
1687: { -1, -2, 0, 0 }, { 0, -3, 0, 0 }, { 0, 0, -1, -3 },
1688: { 0, 0, -1, -3 } };
1689:
1690: int type;
1691:
1692: if (expr.left().type().isIntegral()) {
1693: type = 0;
1694:
1695: } else if (expr.left().type().equals(Type.LONG)) {
1696: type = 1;
1697:
1698: } else if (expr.left().type().equals(Type.FLOAT)) {
1699: type = 2;
1700:
1701: } else if (expr.left().type().equals(Type.DOUBLE)) {
1702: type = 3;
1703:
1704: } else {
1705: throw new IllegalArgumentException(
1706: "Can't generate code for type: "
1707: + expr.left().type() + " (expr " + expr
1708: + ")");
1709: }
1710:
1711: switch (expr.operation()) {
1712: case ArithExpr.ADD:
1713: method.addInstruction(opcode[0][type]);
1714: stackHeight += stackChange[0][type];
1715: break;
1716: case ArithExpr.AND:
1717: method.addInstruction(opcode[1][type]);
1718: stackHeight += stackChange[1][type];
1719: break;
1720: case ArithExpr.DIV:
1721: method.addInstruction(opcode[2][type]);
1722: stackHeight += stackChange[2][type];
1723: break;
1724: case ArithExpr.MUL:
1725: method.addInstruction(opcode[3][type]);
1726: stackHeight += stackChange[3][type];
1727: break;
1728: case ArithExpr.IOR:
1729: method.addInstruction(opcode[4][type]);
1730: stackHeight += stackChange[4][type];
1731: break;
1732: case ArithExpr.REM:
1733: method.addInstruction(opcode[5][type]);
1734: stackHeight += stackChange[5][type];
1735: break;
1736: case ArithExpr.SUB:
1737: method.addInstruction(opcode[6][type]);
1738: stackHeight += stackChange[6][type];
1739: break;
1740: case ArithExpr.XOR:
1741: method.addInstruction(opcode[7][type]);
1742: stackHeight += stackChange[7][type];
1743: break;
1744: case ArithExpr.CMP:
1745: method.addInstruction(opcode[8][type]);
1746: stackHeight += stackChange[8][type];
1747: break;
1748: case ArithExpr.CMPL:
1749: method.addInstruction(opcode[9][type]);
1750: stackHeight += stackChange[9][type];
1751: break;
1752: case ArithExpr.CMPG:
1753: method.addInstruction(opcode[10][type]);
1754: stackHeight += stackChange[10][type];
1755: break;
1756: }
1757: }
1758:
1759: public void visitArrayLengthExpr(final ArrayLengthExpr expr) {
1760: expr.visitChildren(this );
1761: method.addInstruction(Opcode.opcx_arraylength);
1762: }
1763:
1764: public void visitArrayRefExpr(final ArrayRefExpr expr) {
1765: expr.visitChildren(this );
1766:
1767: genPostponed(expr);
1768:
1769: int opcode;
1770:
1771: if (expr.isDef()) {
1772: if (expr.elementType().isReference()) {
1773: opcode = Opcode.opcx_aastore;
1774: stackHeight -= 3;
1775: } else if (expr.elementType().equals(Type.BYTE)) {
1776: opcode = Opcode.opcx_bastore;
1777: stackHeight -= 3;
1778: } else if (expr.elementType().equals(Type.CHARACTER)) {
1779: opcode = Opcode.opcx_castore;
1780: stackHeight -= 3;
1781: } else if (expr.elementType().equals(Type.SHORT)) {
1782: opcode = Opcode.opcx_sastore;
1783: stackHeight -= 3;
1784: } else if (expr.elementType().equals(Type.INTEGER)) {
1785: opcode = Opcode.opcx_iastore;
1786: stackHeight -= 3;
1787: } else if (expr.elementType().equals(Type.LONG)) {
1788: opcode = Opcode.opcx_lastore;
1789: stackHeight -= 4;
1790: } else if (expr.elementType().equals(Type.FLOAT)) {
1791: opcode = Opcode.opcx_fastore;
1792: stackHeight -= 3;
1793: } else if (expr.elementType().equals(Type.DOUBLE)) {
1794: opcode = Opcode.opcx_dastore;
1795: stackHeight -= 4;
1796: } else {
1797: throw new IllegalArgumentException(
1798: "Can't generate code for type: " + expr.type()
1799: + " (expr " + expr + ")");
1800: }
1801: } else {
1802: if (expr.elementType().isReference()) {
1803: opcode = Opcode.opcx_aaload;
1804: stackHeight -= 1;
1805: } else if (expr.elementType().equals(Type.BYTE)) {
1806: opcode = Opcode.opcx_baload;
1807: stackHeight -= 1;
1808: } else if (expr.elementType().equals(Type.CHARACTER)) {
1809: opcode = Opcode.opcx_caload;
1810: stackHeight -= 1;
1811: } else if (expr.elementType().equals(Type.SHORT)) {
1812: opcode = Opcode.opcx_saload;
1813: stackHeight -= 1;
1814: } else if (expr.elementType().equals(Type.INTEGER)) {
1815: opcode = Opcode.opcx_iaload;
1816: stackHeight -= 1;
1817: } else if (expr.elementType().equals(Type.LONG)) {
1818: opcode = Opcode.opcx_laload;
1819: stackHeight -= 0;
1820: } else if (expr.elementType().equals(Type.FLOAT)) {
1821: opcode = Opcode.opcx_faload;
1822: stackHeight -= 1;
1823: } else if (expr.elementType().equals(Type.DOUBLE)) {
1824: opcode = Opcode.opcx_daload;
1825: stackHeight -= 0;
1826: } else {
1827: throw new IllegalArgumentException(
1828: "Can't generate code for type: " + expr.type()
1829: + " (expr " + expr + ")");
1830: }
1831: }
1832:
1833: method.addInstruction(opcode);
1834: }
1835:
1836: public void visitCallMethodExpr(final CallMethodExpr expr) {
1837: expr.visitChildren(this );
1838:
1839: genPostponed(expr);
1840:
1841: int opcode;
1842:
1843: if (expr.kind() == CallMethodExpr.VIRTUAL) {
1844: opcode = Opcode.opcx_invokevirtual;
1845: } else if (expr.kind() == CallMethodExpr.NONVIRTUAL) {
1846: opcode = Opcode.opcx_invokespecial;
1847: } else if (expr.kind() == CallMethodExpr.INTERFACE) {
1848: opcode = Opcode.opcx_invokeinterface;
1849: } else {
1850: throw new IllegalArgumentException();
1851: }
1852:
1853: method.addInstruction(opcode, expr.method());
1854:
1855: // Pop reciever object off stack
1856: stackHeight -= 1;
1857:
1858: // Pop each parameter off stack
1859: final Expr[] params = expr.params();
1860: for (int i = 0; i < params.length; i++) {
1861: stackHeight -= params[i].type().stackHeight();
1862: }
1863: }
1864:
1865: public void visitCallStaticExpr(final CallStaticExpr expr) {
1866: expr.visitChildren(this );
1867:
1868: genPostponed(expr);
1869:
1870: method.addInstruction(Opcode.opcx_invokestatic, expr.method());
1871:
1872: // Pop each parameter off stack
1873: final Expr[] params = expr.params();
1874: for (int i = 0; i < params.length; i++) {
1875: stackHeight -= params[i].type().stackHeight();
1876: }
1877: }
1878:
1879: public void visitCastExpr(final CastExpr expr) {
1880: expr.visitChildren(this );
1881:
1882: genPostponed(expr);
1883:
1884: if (expr.castType().isReference()) {
1885: method.addInstruction(Opcode.opcx_checkcast, expr
1886: .castType());
1887: return;
1888: }
1889:
1890: final int opType = expr.expr().type().typeCode();
1891: final int castType = expr.castType().typeCode();
1892:
1893: switch (opType) {
1894: case Type.BYTE_CODE:
1895: case Type.SHORT_CODE:
1896: case Type.CHARACTER_CODE:
1897: case Type.INTEGER_CODE:
1898: switch (castType) {
1899: case Type.BYTE_CODE:
1900: method.addInstruction(Opcode.opcx_i2b);
1901: return;
1902: case Type.SHORT_CODE:
1903: method.addInstruction(Opcode.opcx_i2s);
1904: return;
1905: case Type.CHARACTER_CODE:
1906: method.addInstruction(Opcode.opcx_i2c);
1907: return;
1908: case Type.INTEGER_CODE:
1909: return;
1910: case Type.LONG_CODE:
1911: method.addInstruction(Opcode.opcx_i2l);
1912: stackHeight += 1;
1913: return;
1914: case Type.FLOAT_CODE:
1915: method.addInstruction(Opcode.opcx_i2f);
1916: return;
1917: case Type.DOUBLE_CODE:
1918: method.addInstruction(Opcode.opcx_i2d);
1919: stackHeight += 1;
1920: return;
1921: }
1922: throw new IllegalArgumentException(
1923: "Can't generate cast for type "
1924: + Type.getType(castType));
1925: // new Type(castType));
1926:
1927: case Type.LONG_CODE:
1928: switch (castType) {
1929: case Type.BYTE_CODE:
1930: method.addInstruction(Opcode.opcx_l2i);
1931: stackHeight -= 1;
1932: method.addInstruction(Opcode.opcx_i2b);
1933: return;
1934: case Type.SHORT_CODE:
1935: method.addInstruction(Opcode.opcx_l2i);
1936: stackHeight -= 1;
1937: method.addInstruction(Opcode.opcx_i2s);
1938: return;
1939: case Type.CHARACTER_CODE:
1940: method.addInstruction(Opcode.opcx_l2i);
1941: stackHeight -= 1;
1942: method.addInstruction(Opcode.opcx_i2c);
1943: return;
1944: case Type.INTEGER_CODE:
1945: method.addInstruction(Opcode.opcx_l2i);
1946: stackHeight -= 1;
1947: return;
1948: case Type.LONG_CODE:
1949: return;
1950: case Type.FLOAT_CODE:
1951: method.addInstruction(Opcode.opcx_l2f);
1952: stackHeight -= 1;
1953: return;
1954: case Type.DOUBLE_CODE:
1955: method.addInstruction(Opcode.opcx_l2d);
1956: return;
1957: }
1958:
1959: throw new IllegalArgumentException(
1960: "Can't generate cast for type "
1961: + Type.getType(castType));
1962: // new Type(castType));
1963:
1964: case Type.FLOAT_CODE:
1965: switch (castType) {
1966: case Type.BYTE_CODE:
1967: method.addInstruction(Opcode.opcx_f2i);
1968: method.addInstruction(Opcode.opcx_i2b);
1969: return;
1970: case Type.SHORT_CODE:
1971: method.addInstruction(Opcode.opcx_f2i);
1972: method.addInstruction(Opcode.opcx_i2s);
1973: return;
1974: case Type.CHARACTER_CODE:
1975: method.addInstruction(Opcode.opcx_f2i);
1976: method.addInstruction(Opcode.opcx_i2c);
1977: return;
1978: case Type.INTEGER_CODE:
1979: method.addInstruction(Opcode.opcx_f2i);
1980: return;
1981: case Type.LONG_CODE:
1982: method.addInstruction(Opcode.opcx_f2l);
1983: stackHeight += 1;
1984: return;
1985: case Type.FLOAT_CODE:
1986: return;
1987: case Type.DOUBLE_CODE:
1988: method.addInstruction(Opcode.opcx_f2d);
1989: stackHeight += 1;
1990: return;
1991: }
1992:
1993: throw new IllegalArgumentException(
1994: "Can't generate cast for type "
1995: + Type.getType(castType));
1996: // new Type(castType));
1997:
1998: case Type.DOUBLE_CODE:
1999: switch (castType) {
2000: case Type.BYTE_CODE:
2001: method.addInstruction(Opcode.opcx_d2i);
2002: stackHeight -= 1;
2003: method.addInstruction(Opcode.opcx_i2b);
2004: return;
2005: case Type.SHORT_CODE:
2006: method.addInstruction(Opcode.opcx_d2i);
2007: stackHeight -= 1;
2008: method.addInstruction(Opcode.opcx_i2s);
2009: return;
2010: case Type.CHARACTER_CODE:
2011: method.addInstruction(Opcode.opcx_d2i);
2012: stackHeight -= 1;
2013: method.addInstruction(Opcode.opcx_i2c);
2014: return;
2015: case Type.INTEGER_CODE:
2016: method.addInstruction(Opcode.opcx_d2i);
2017: stackHeight -= 1;
2018: return;
2019: case Type.LONG_CODE:
2020: method.addInstruction(Opcode.opcx_d2l);
2021: return;
2022: case Type.FLOAT_CODE:
2023: method.addInstruction(Opcode.opcx_d2f);
2024: return;
2025: case Type.DOUBLE_CODE:
2026: return;
2027: }
2028:
2029: throw new IllegalArgumentException(
2030: "Can't generate cast for type "
2031: + Type.getType(castType));
2032: // new Type(castType));
2033: default:
2034: throw new IllegalArgumentException(
2035: "Can't generate cast from type "
2036: + Type.getType(opType));
2037: // new Type(castType));
2038: }
2039: }
2040:
2041: public void visitConstantExpr(final ConstantExpr expr) {
2042: expr.visitChildren(this );
2043:
2044: genPostponed(expr);
2045:
2046: method.addInstruction(Opcode.opcx_ldc, expr.value());
2047: stackHeight += expr.type().stackHeight();
2048: }
2049:
2050: public boolean nowb = false;
2051:
2052: public void visitFieldExpr(final FieldExpr expr) {
2053: expr.visitChildren(this );
2054: genPostponed(expr);
2055:
2056: if (expr.isDef()) {
2057:
2058: boolean UC = false; // Do we need an UC?
2059:
2060: // Look at the FieldExpr's object for a UCExpr
2061: Node check = expr.object();
2062: while (check instanceof CheckExpr) {
2063: if (check instanceof UCExpr) {
2064: UC = true;
2065: break;
2066: }
2067:
2068: final CheckExpr c = (CheckExpr) check;
2069: check = c.expr();
2070: }
2071:
2072: // Do we need to perform the write barrier?
2073: if (!UC && CodeGenerator.USE_PERSISTENT) {
2074: /*
2075: * System.out.println("Emitting a putfield_nowb in " +
2076: * this.method.declaringClass().classInfo().name() + "." +
2077: * this.method.name());
2078: */
2079: nowb = true;
2080:
2081: // I commented out the next line because it generated a compiler
2082: // error, and I figured it was just about some unimportant
2083: // persistance stuff --Tom
2084: // method.addInstruction(opcx_putfield_nowb, expr.field());
2085:
2086: } else {
2087: method.addInstruction(Opcode.opcx_putfield, expr
2088: .field());
2089:
2090: }
2091:
2092: stackHeight -= 1; // object
2093: stackHeight -= expr.type().stackHeight();
2094:
2095: } else {
2096: method.addInstruction(Opcode.opcx_getfield, expr.field());
2097: stackHeight -= 1; // pop object
2098: stackHeight += expr.type().stackHeight();
2099: }
2100: }
2101:
2102: public void visitInstanceOfExpr(final InstanceOfExpr expr) {
2103: expr.visitChildren(this );
2104: genPostponed(expr);
2105: method.addInstruction(Opcode.opcx_instanceof , expr.checkType());
2106: }
2107:
2108: public void visitLocalExpr(final LocalExpr expr) {
2109:
2110: genPostponed(expr);
2111:
2112: final boolean cat2 = expr.type().isWide(); // how many stack positions
2113: // does
2114: // this take up?
2115:
2116: int opcode = -1; // -1 is the flag that it hasn't yet been assigned
2117: // a real value
2118:
2119: if (CodeGenerator.DB_OPT_STACK) {
2120: currentSO.infoDisplay(expr);
2121: }
2122:
2123: if (expr.isDef()) {
2124:
2125: if (!CodeGenerator.OPT_STACK || currentSO.shouldStore(expr)) {
2126:
2127: if (expr.type().isAddress()) {
2128: opcode = Opcode.opcx_astore;
2129: stackHeight -= 1;
2130: } else if (expr.type().isReference()) {
2131: opcode = Opcode.opcx_astore;
2132: stackHeight -= 1;
2133: } else if (expr.type().isIntegral()) {
2134: opcode = Opcode.opcx_istore;
2135: stackHeight -= 1;
2136: } else if (expr.type().equals(Type.LONG)) {
2137: opcode = Opcode.opcx_lstore;
2138: stackHeight -= 2;
2139: } else if (expr.type().equals(Type.FLOAT)) {
2140: opcode = Opcode.opcx_fstore;
2141: stackHeight -= 1;
2142: } else if (expr.type().equals(Type.DOUBLE)) {
2143: opcode = Opcode.opcx_dstore;
2144: stackHeight -= 2;
2145: } else {
2146: throw new IllegalArgumentException(
2147: "Can't generate code for type: "
2148: + expr.type() + " (expr " + expr
2149: + ")");
2150: }
2151: }
2152: }
2153:
2154: else {
2155:
2156: if (CodeGenerator.OPT_STACK && currentSO.onStack(expr)) { // don't
2157: // load
2158: // if
2159: // it's
2160: // already
2161: // on
2162: // the stack
2163: if (currentSO.shouldSwap(expr)) {
2164: if (cat2) {
2165: throw new IllegalArgumentException(
2166: "Can't swap for wide expression "
2167: + expr.toString() + " of type "
2168: + expr.type().toString());
2169: } else {
2170: opcode = Opcode.opc_swap;
2171: stackHeight -= 1;
2172: }
2173: }
2174: } else {
2175:
2176: if (expr.type().isReference()) {
2177: opcode = Opcode.opcx_aload;
2178: stackHeight += 1;
2179: } else if (expr.type().isIntegral()) {
2180: opcode = Opcode.opcx_iload;
2181: stackHeight += 1;
2182: } else if (expr.type().equals(Type.LONG)) {
2183: opcode = Opcode.opcx_lload;
2184: stackHeight += 2;
2185: } else if (expr.type().equals(Type.FLOAT)) {
2186: opcode = Opcode.opcx_fload;
2187: stackHeight += 1;
2188: } else if (expr.type().equals(Type.DOUBLE)) {
2189: opcode = Opcode.opcx_dload;
2190: stackHeight += 2;
2191: } else {
2192: throw new IllegalArgumentException(
2193: "Can't generate code for type: "
2194: + expr.type() + " (expr " + expr
2195: + ")");
2196: }
2197: }
2198: }
2199:
2200: if (opcode == Opcode.opc_swap) {
2201: method.addInstruction(opcode); // don't give
2202: } else if ((opcode != -1) && !(expr.isDef())) { // if this is a load, we
2203: // want
2204: // the load before any dups.
2205: method.addInstruction(opcode, new LocalVariable(expr
2206: .index()));
2207:
2208: if (MethodEditor.OPT_STACK_2) {
2209: method.rememberDef(expr);
2210: }
2211:
2212: }
2213:
2214: if (CodeGenerator.OPT_STACK) {
2215: // generate dups for this value on top of the stack
2216: int dups, dup_x1s, dup_x2s;
2217: dups = currentSO.dups(expr);
2218: dup_x1s = currentSO.dup_x1s(expr);
2219: dup_x2s = currentSO.dup_x2s(expr);
2220:
2221: for (int i = 0; i < dup_x2s; i++) {
2222: if (cat2) { // (cat2 is for wide types)
2223: method.addInstruction(Opcode.opc_dup2_x2);
2224: stackHeight += 2;
2225: } else {
2226: method.addInstruction(Opcode.opc_dup_x2);
2227: stackHeight += 1;
2228: }
2229: }
2230: for (int i = 0; i < dup_x1s; i++) {
2231: if (cat2) {
2232: method.addInstruction(Opcode.opc_dup2_x1);
2233: stackHeight += 2;
2234: } else {
2235: method.addInstruction(Opcode.opc_dup_x1);
2236: stackHeight += 1;
2237: }
2238: }
2239: for (int i = 0; i < dups; i++) {
2240: if (cat2) {
2241: method.addInstruction(Opcode.opc_dup2);
2242: stackHeight += 2;
2243: } else {
2244: method.addInstruction(Opcode.opc_dup);
2245: stackHeight += 1;
2246: }
2247: }
2248: }
2249:
2250: // if we have an opcode for a def (i.e., a store), generate it
2251: if ((opcode != -1) && expr.isDef()) {
2252: method.addInstruction(opcode, new LocalVariable(expr
2253: .index()));
2254:
2255: if (MethodEditor.OPT_STACK_2) {
2256: method.rememberDef(expr);
2257: }
2258:
2259: }
2260:
2261: if (CodeGenerator.OPT_STACK // if we shouldn't store,
2262: && !currentSO.shouldStore(expr)) { // an extra thing will be
2263: if (cat2) { // on the stack. pop it
2264: method.addInstruction(Opcode.opc_pop2);
2265: stackHeight -= 2;
2266: } else {
2267: method.addInstruction(Opcode.opc_pop);
2268: stackHeight -= 1;
2269: }
2270: }
2271: // (if this leaves a useless dup/pop combination, let peephole fix it)
2272:
2273: // method.addInstruction(opcode, new LocalVariable(expr.index()));
2274: }
2275:
2276: public void visitNegExpr(final NegExpr expr) {
2277: expr.visitChildren(this );
2278:
2279: genPostponed(expr);
2280:
2281: if (expr.type().isIntegral()) {
2282: method.addInstruction(Opcode.opcx_ineg);
2283: } else if (expr.type().equals(Type.FLOAT)) {
2284: method.addInstruction(Opcode.opcx_fneg);
2285: } else if (expr.type().equals(Type.LONG)) {
2286: method.addInstruction(Opcode.opcx_lneg);
2287: } else if (expr.type().equals(Type.DOUBLE)) {
2288: method.addInstruction(Opcode.opcx_dneg);
2289: } else {
2290: throw new IllegalArgumentException(
2291: "Can't generate code for type: " + expr.type()
2292: + " (expr " + expr + ")");
2293: }
2294: }
2295:
2296: public void visitNewArrayExpr(final NewArrayExpr expr) {
2297: expr.visitChildren(this );
2298:
2299: genPostponed(expr);
2300:
2301: method.addInstruction(Opcode.opcx_newarray, expr.elementType());
2302: }
2303:
2304: public void visitNewExpr(final NewExpr expr) {
2305: expr.visitChildren(this );
2306:
2307: genPostponed(expr);
2308:
2309: method.addInstruction(Opcode.opcx_new, expr.objectType());
2310: stackHeight += 1;
2311: }
2312:
2313: public void visitNewMultiArrayExpr(final NewMultiArrayExpr expr) {
2314: expr.visitChildren(this );
2315:
2316: genPostponed(expr);
2317:
2318: method.addInstruction(Opcode.opcx_multianewarray,
2319: new MultiArrayOperand(expr.elementType().arrayType(
2320: expr.dimensions().length),
2321: expr.dimensions().length));
2322: stackHeight -= expr.dimensions().length;
2323: stackHeight += 1;
2324: }
2325:
2326: public void visitReturnAddressExpr(final ReturnAddressExpr expr) {
2327: genPostponed(expr);
2328: }
2329:
2330: public void visitShiftExpr(final ShiftExpr expr) {
2331: expr.visitChildren(this );
2332:
2333: genPostponed(expr);
2334:
2335: if (expr.type().isIntegral()) {
2336: if (expr.dir() == ShiftExpr.LEFT) {
2337: method.addInstruction(Opcode.opcx_ishl);
2338: stackHeight -= 1;
2339: } else if (expr.dir() == ShiftExpr.RIGHT) {
2340: method.addInstruction(Opcode.opcx_ishr);
2341: stackHeight -= 1;
2342: } else {
2343: method.addInstruction(Opcode.opcx_iushr);
2344: stackHeight -= 1;
2345: }
2346: } else if (expr.type().equals(Type.LONG)) {
2347: if (expr.dir() == ShiftExpr.LEFT) {
2348: method.addInstruction(Opcode.opcx_lshl);
2349: stackHeight -= 1;
2350: } else if (expr.dir() == ShiftExpr.RIGHT) {
2351: method.addInstruction(Opcode.opcx_lshr);
2352: stackHeight -= 1;
2353: } else {
2354: method.addInstruction(Opcode.opcx_lushr);
2355: stackHeight -= 1;
2356: }
2357: } else {
2358: throw new IllegalArgumentException(
2359: "Can't generate code for type: " + expr.type()
2360: + " (expr " + expr + ")");
2361: }
2362: }
2363:
2364: public void visitDefExpr(final DefExpr expr) {
2365: expr.visitChildren(this );
2366: genPostponed(expr);
2367: }
2368:
2369: public void visitCatchExpr(final CatchExpr expr) {
2370: expr.visitChildren(this );
2371: genPostponed(expr);
2372: }
2373:
2374: public void visitStackExpr(final StackExpr expr) {
2375: expr.visitChildren(this );
2376: genPostponed(expr);
2377: }
2378:
2379: public void visitStaticFieldExpr(final StaticFieldExpr expr) {
2380: expr.visitChildren(this );
2381: genPostponed(expr);
2382:
2383: if (expr.isDef()) {
2384: method.addInstruction(Opcode.opcx_putstatic, expr.field());
2385: stackHeight -= expr.type().stackHeight();
2386: } else {
2387: method.addInstruction(Opcode.opcx_getstatic, expr.field());
2388: stackHeight += expr.type().stackHeight();
2389: }
2390: }
2391:
2392: public void visitZeroCheckExpr(final ZeroCheckExpr expr) {
2393: expr.visitChildren(this );
2394: genPostponed(expr);
2395: }
2396:
2397: private void genPostponed(final Node node) {
2398: final Instruction inst = (Instruction) postponedInstructions
2399: .get(node);
2400:
2401: if (inst != null) {
2402: method.addInstruction(inst);
2403: // Luckily, the rc and aupdate don't change the stack!
2404: postponedInstructions.remove(node);
2405: }
2406: }
2407: }
|