/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ package EDU.purdue.cs.bloat.tree; import java.util.*; /** * DecsendVisitor is the superclass of a few private classes of Type0Visitor and * Type1Visitor. It descends the tree, keeping track of the number of right * links that have been taken. */ public abstract class DescendVisitor extends TreeVisitor { Hashtable useInfoMap; Hashtable defInfoMap; boolean found; Node beginNode; // where this visitor starts its search from LocalExpr start; // where the original search began int exchangeFactor; public DescendVisitor(final Hashtable useInfoMap, final Hashtable defInfoMap) { this.useInfoMap = useInfoMap; this.defInfoMap = defInfoMap; } public boolean search(final Node beginNode, final LocalExpr start) { this.beginNode = beginNode; this.start = start; exchangeFactor = 0; found = false; beginNode.visit(this); return found; } public void visitExprStmt(final ExprStmt stmt) { stmt.expr().visit(this); } public void visitIfStmt(final IfStmt stmt) { if (stmt instanceof IfCmpStmt) { visitIfCmpStmt((IfCmpStmt) stmt); } else if (stmt instanceof IfZeroStmt) { visitIfZeroStmt((IfZeroStmt) stmt); } } public void visitIfCmpStmt(final IfCmpStmt stmt) { stmt.left().visit(this); // search the left branch if (!found) { // if nothing has been found exchangeFactor++; // increase the exchange factor, if (stmt.left().type().isWide()) { exchangeFactor++; // twice to get } // around wides if (exchangeFactor < 3) { stmt.right().visit(this); // search the right branch. } } } public void visitIfZeroStmt(final IfZeroStmt stmt) { stmt.expr().visit(this); } public void visitInitStmt(final InitStmt stmt) { // would have been checked by the Type0Visitor } public void visitGotoStmt(final GotoStmt stmt) { } public void visitLabelStmt(final LabelStmt stmt) { } public void visitMonitorStmt(final MonitorStmt stmt) { } public void visitPhiStmt(final PhiStmt stmt) { if (stmt instanceof PhiCatchStmt) { visitPhiCatchStmt((PhiCatchStmt) stmt); } else if (stmt instanceof PhiJoinStmt) { visitPhiJoinStmt((PhiJoinStmt) stmt); /* * else if (stmt instanceof PhiReturnStmt) * visitPhiReturnStmt((PhiReturnStmt) stmt); */ } } public void visitCatchExpr(final CatchExpr expr) { } public void visitDefExpr(final DefExpr expr) { if (expr instanceof MemExpr) { visitMemExpr((MemExpr) expr); } } public void visitStackManipStmt(final StackManipStmt stmt) { } public void visitPhiCatchStmt(final PhiCatchStmt stmt) { } public void visitPhiJoinStmt(final PhiJoinStmt stmt) { } public void visitRetStmt(final RetStmt stmt) { } public void visitReturnExprStmt(final ReturnExprStmt stmt) { } public void visitReturnStmt(final ReturnStmt stmt) { } public void visitAddressStoreStmt(final AddressStoreStmt stmt) { } // StoreExprs are very difficult because they represent several // types of expressions. What we do will depend on what the target // of the store is: ArrayRefExpr, FieldExpr, StaticFieldExpr, // or LocalExpr public void visitStoreExpr(final StoreExpr expr) { final MemExpr target = expr.target(); if (target instanceof ArrayRefExpr) { // ArrayRefExpr: the store will be something like an astore // which manipulates the stack like // arrayref, index, val => ... // so, think of the tree like // (StoreExpr) // / \ // Array Ref . // / \ // index value // This is unlike the structure of the tree BLOAT uses for // intermediate representation, but it better relates to what's // on the stack at what time ((ArrayRefExpr) target).array().visit(this); // visit the // left child if (!found) { // if match wasn't found exchangeFactor++; // take the right branch if (exchangeFactor < 3) { // (an array ref isn't wide) // visit next left child ((ArrayRefExpr) target).index().visit(this); if (!found) { // if match wasn't found exchangeFactor++; if (exchangeFactor < 3) { expr.expr().visit(this); // search the right // branch } } // end seaching RR } } // end searching R } // end case where target is ArrayRefExpr else if (target instanceof FieldExpr) { // FieldExpr: the store will be like a putfield // which manipulates the stack like // objref, val => ... // so, think of the tree like // (StoreExpr) // / \ // Object Ref value ((FieldExpr) target).object().visit(this); // visit the left child if (!found) { exchangeFactor++; // (an object ref isn't wide) if (exchangeFactor < 3) { expr.expr().visit(this); } } } // end case where target is FieldRef else if (target instanceof StaticFieldExpr) { // StaticFieldExpr: the store will be like a putstatic // which manipulates the stack like // val => ... // so, think of the tree like // (StoreExpr) // / // value expr.expr.visit(this); } else if (target instanceof LocalExpr) { // LocalExpr: the store will be like istore/astore/etc. // which manipulates the stack like // val => ... // so, think of the tree like // (StoreExpr) // / // value expr.expr.visit(this); } } public void visitJsrStmt(final JsrStmt stmt) { } public void visitSwitchStmt(final SwitchStmt stmt) { } public void visitThrowStmt(final ThrowStmt stmt) { } public void visitStmt(final Stmt stmt) { } public void visitSCStmt(final SCStmt stmt) { } public void visitSRStmt(final SRStmt stmt) { } public void visitArithExpr(final ArithExpr expr) { // important one expr.left().visit(this); // visit the left branch if (!found) { // if a match isn't found yet exchangeFactor++; // increase the exchange factor if (expr.left().type().isWide()) { exchangeFactor++; // twice if wide } if (exchangeFactor < 3) { expr.right().visit(this); // visit right branch } } } public void visitArrayLengthExpr(final ArrayLengthExpr expr) { expr.array().visit(this); } public void visitMemExpr(final MemExpr expr) { if (expr instanceof LocalExpr) { visitLocalExpr((LocalExpr) expr); } } public void visitMemRefExpr(final MemRefExpr expr) { } public void visitArrayRefExpr(final ArrayRefExpr expr) { } public void visitCallExpr(final CallExpr expr) { if (expr instanceof CallMethodExpr) { visitCallMethodExpr((CallMethodExpr) expr); } else if (expr instanceof CallStaticExpr) { visitCallStaticExpr((CallStaticExpr) expr); } } public void visitCallMethodExpr(final CallMethodExpr expr) { // Method invocations are to be thought of, in terms of // binary expression trees, as // (CallMethodExpr) // / \ // receiver . // / \ // arg1 . // / \ // arg2 . // / \ // arg3 ... // This might be the opposite of what one would think in terms // of currying (ie, one might think of currying in terms of // left associativity), but this gives a better picture of what // happens to the stack when invokestatic or invokevirtual is called: // objectref, [arg1, [arg2 ...]] => ... expr.receiver().visit(this); final Expr[] params = expr.params(); if (!found && (exchangeFactor < 2) && (params.length > 0)) { exchangeFactor++; // (reciever won't be wide) params[0].visit(this); } } public void visitCallStaticExpr(final CallStaticExpr expr) { final Expr[] params = expr.params(); if (params.length > 0) { params[0].visit(this); } if (!found && (exchangeFactor < 2) && (params.length > 1)) { exchangeFactor++; params[1].visit(this); } } public void visitCastExpr(final CastExpr expr) { expr.expr().visit(this); } public void visitConstantExpr(final ConstantExpr expr) { } public void visitFieldExpr(final FieldExpr expr) { expr.object.visit(this); } public void visitInstanceOfExpr(final InstanceOfExpr expr) { expr.expr().visit(this); } /* needs to be different for Type0 and Type1 */ public abstract void visitLocalExpr(LocalExpr expr); public void visitNegExpr(final NegExpr expr) { expr.expr().visit(this); } public void visitNewArrayExpr(final NewArrayExpr expr) { expr.size().visit(this); } public void visitNewExpr(final NewExpr expr) { } public void visitNewMultiArrayExpr(final NewMultiArrayExpr expr) { // Think of the tree like // (NewMultiArrayExpr) // / \ // count1 . // / \ // count2 etc. // since multianewarray manipulates the stack like // count1, [count1 ...] => ... final Expr[] dims = expr.dimensions(); if (dims.length > 0) { dims[0].visit(this); } if (!found && (exchangeFactor < 2) && (dims.length > 1)) { exchangeFactor++; // (count1 won't be wide) dims[1].visit(this); } } public void visitCheckExpr(final CheckExpr expr) { if (expr instanceof ZeroCheckExpr) { visitZeroCheckExpr((ZeroCheckExpr) expr); } else if (expr instanceof RCExpr) { visitRCExpr((RCExpr) expr); } else if (expr instanceof UCExpr) { visitUCExpr((UCExpr) expr); } } public void visitZeroCheckExpr(final ZeroCheckExpr expr) { // perhaps add something here } public void visitRCExpr(final RCExpr expr) { } public void visitUCExpr(final UCExpr expr) { } public void visitReturnAddressExpr(final ReturnAddressExpr expr) { } public void visitShiftExpr(final ShiftExpr expr) { } public void visitVarExpr(final VarExpr expr) { if (expr instanceof LocalExpr) { visitLocalExpr((LocalExpr) expr); } } public void visitStaticFieldExpr(final StaticFieldExpr expr) { } public void visitExpr(final Expr expr) { } }