/* 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.trans; import EDU.purdue.cs.bloat.editor.*; import EDU.purdue.cs.bloat.tree.*; /** * <tt>SideEffectChecker</tt> traverses a tree and determines is a node has * any side effects such as changing the stack, calling a function, or * performing a residency check. The side effects are represented by an integer * whose bits represent a certain kind of side effect. * * <p> * * <Tt>SideEffectChecker</tt> is a <tt>TreeVisitor</tt>. The way it works * is that after a <tt>SideEffectChecker</tt> is reset, an expression tree * <tt>Node</tt> is visited to determine whether or not it has side effects. * Neat. */ public class SideEffectChecker extends TreeVisitor { private int sideEffects = 0; public static final int STACK = (1 << 0); public static final int THROW = (1 << 1); public static final int CALL = (1 << 2); public static final int SYNC = (1 << 3); public static final int ALLOC = (1 << 4); // Allocates memory public static final int RC = (1 << 5); public static final int UC = (1 << 6); public static final int STORE = (1 << 7); public static final int ALIAS = (1 << 8); public static final int VOLATILE = (1 << 9); private EditorContext context; /** * Constructor. The <tt>Context</tt> is needed to determine whether or not * a field is VOLATILE, etc. */ public SideEffectChecker(final EditorContext context) { this.context = context; } public int sideEffects() { return sideEffects; } public boolean hasSideEffects() { return sideEffects != 0; } public void reset() { sideEffects = 0; } public void visitStoreExpr(final StoreExpr expr) { sideEffects |= SideEffectChecker.STORE; expr.visitChildren(this); } public void visitLocalExpr(final LocalExpr expr) { if (expr.isDef()) { sideEffects |= SideEffectChecker.STORE; } expr.visitChildren(this); } public void visitZeroCheckExpr(final ZeroCheckExpr expr) { sideEffects |= SideEffectChecker.THROW; expr.visitChildren(this); } public void visitRCExpr(final RCExpr expr) { sideEffects |= SideEffectChecker.RC; expr.visitChildren(this); } public void visitUCExpr(final UCExpr expr) { sideEffects |= SideEffectChecker.UC; expr.visitChildren(this); } public void visitNewMultiArrayExpr(final NewMultiArrayExpr expr) { // Memory allocation // NegativeArraySizeException sideEffects |= SideEffectChecker.THROW | SideEffectChecker.ALLOC; expr.visitChildren(this); } public void visitNewArrayExpr(final NewArrayExpr expr) { // Memory allocation // NegativeArraySizeException sideEffects |= SideEffectChecker.THROW | SideEffectChecker.ALLOC; expr.visitChildren(this); } public void visitCatchExpr(final CatchExpr expr) { // Stack change sideEffects |= SideEffectChecker.STACK; expr.visitChildren(this); } public void visitNewExpr(final NewExpr expr) { // Memory allocation sideEffects |= SideEffectChecker.ALLOC; expr.visitChildren(this); } public void visitStackExpr(final StackExpr expr) { // Stack change sideEffects |= SideEffectChecker.STACK; if (expr.isDef()) { sideEffects |= SideEffectChecker.STORE; } expr.visitChildren(this); } public void visitCastExpr(final CastExpr expr) { // ClassCastException if (expr.castType().isReference()) { sideEffects |= SideEffectChecker.THROW; } expr.visitChildren(this); } public void visitArithExpr(final ArithExpr expr) { // DivideByZeroException -- handled by ZeroCheckExpr /* * if (expr.operation() == ArithExpr.DIV || expr.operation() == * ArithExpr.REM) { * * if (expr.type().isIntegral() || expr.type().equals(Type.LONG)) { * sideEffects |= THROW; } } */ expr.visitChildren(this); } public void visitArrayLengthExpr(final ArrayLengthExpr expr) { // NullPointerException sideEffects |= SideEffectChecker.THROW; expr.visitChildren(this); } public void visitArrayRefExpr(final ArrayRefExpr expr) { // NullPointerException, ArrayIndexOutOfBoundsException, // ArrayStoreException sideEffects |= SideEffectChecker.THROW; if (expr.isDef()) { sideEffects |= SideEffectChecker.STORE; } sideEffects |= SideEffectChecker.ALIAS; expr.visitChildren(this); } public void visitFieldExpr(final FieldExpr expr) { // NullPointerException -- handled by ZeroCheckExpr /* * sideEffects |= THROW; */ if (expr.isDef()) { sideEffects |= SideEffectChecker.STORE; } final MemberRef field = expr.field(); try { final FieldEditor e = context.editField(field); if (!e.isFinal()) { sideEffects |= SideEffectChecker.ALIAS; } if (e.isVolatile()) { sideEffects |= SideEffectChecker.VOLATILE; } context.release(e.fieldInfo()); } catch (final NoSuchFieldException e) { // A field wasn't found. Silently assume it's not final and // is volatile. sideEffects |= SideEffectChecker.ALIAS; sideEffects |= SideEffectChecker.VOLATILE; } expr.visitChildren(this); } public void visitStaticFieldExpr(final StaticFieldExpr expr) { if (expr.isDef()) { sideEffects |= SideEffectChecker.STORE; } final MemberRef field = expr.field(); try { final FieldEditor e = context.editField(field); if (e.isVolatile()) { sideEffects |= SideEffectChecker.VOLATILE; } context.release(e.fieldInfo()); } catch (final NoSuchFieldException e) { // A field wasn't found. Silently assume it's volatile. sideEffects |= SideEffectChecker.VOLATILE; } expr.visitChildren(this); } public void visitCallStaticExpr(final CallStaticExpr expr) { // Call sideEffects |= SideEffectChecker.THROW | SideEffectChecker.CALL; expr.visitChildren(this); } public void visitCallMethodExpr(final CallMethodExpr expr) { // Call sideEffects |= SideEffectChecker.THROW | SideEffectChecker.CALL; expr.visitChildren(this); } public void visitMonitorStmt(final MonitorStmt stmt) { // Synchronization sideEffects |= SideEffectChecker.THROW | SideEffectChecker.SYNC; stmt.visitChildren(this); } public void visitStackManipStmt(final StackManipStmt stmt) { // Stack change sideEffects |= SideEffectChecker.STACK; stmt.visitChildren(this); } }