001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.trans;
022:
023: import EDU.purdue.cs.bloat.editor.*;
024: import EDU.purdue.cs.bloat.tree.*;
025:
026: /**
027: * <tt>SideEffectChecker</tt> traverses a tree and determines is a node has
028: * any side effects such as changing the stack, calling a function, or
029: * performing a residency check. The side effects are represented by an integer
030: * whose bits represent a certain kind of side effect.
031: *
032: * <p>
033: *
034: * <Tt>SideEffectChecker</tt> is a <tt>TreeVisitor</tt>. The way it works
035: * is that after a <tt>SideEffectChecker</tt> is reset, an expression tree
036: * <tt>Node</tt> is visited to determine whether or not it has side effects.
037: * Neat.
038: */
039: public class SideEffectChecker extends TreeVisitor {
040: private int sideEffects = 0;
041:
042: public static final int STACK = (1 << 0);
043:
044: public static final int THROW = (1 << 1);
045:
046: public static final int CALL = (1 << 2);
047:
048: public static final int SYNC = (1 << 3);
049:
050: public static final int ALLOC = (1 << 4); // Allocates memory
051:
052: public static final int RC = (1 << 5);
053:
054: public static final int UC = (1 << 6);
055:
056: public static final int STORE = (1 << 7);
057:
058: public static final int ALIAS = (1 << 8);
059:
060: public static final int VOLATILE = (1 << 9);
061:
062: private EditorContext context;
063:
064: /**
065: * Constructor. The <tt>Context</tt> is needed to determine whether or not
066: * a field is VOLATILE, etc.
067: */
068: public SideEffectChecker(final EditorContext context) {
069: this .context = context;
070: }
071:
072: public int sideEffects() {
073: return sideEffects;
074: }
075:
076: public boolean hasSideEffects() {
077: return sideEffects != 0;
078: }
079:
080: public void reset() {
081: sideEffects = 0;
082: }
083:
084: public void visitStoreExpr(final StoreExpr expr) {
085: sideEffects |= SideEffectChecker.STORE;
086: expr.visitChildren(this );
087: }
088:
089: public void visitLocalExpr(final LocalExpr expr) {
090: if (expr.isDef()) {
091: sideEffects |= SideEffectChecker.STORE;
092: }
093: expr.visitChildren(this );
094: }
095:
096: public void visitZeroCheckExpr(final ZeroCheckExpr expr) {
097: sideEffects |= SideEffectChecker.THROW;
098: expr.visitChildren(this );
099: }
100:
101: public void visitRCExpr(final RCExpr expr) {
102: sideEffects |= SideEffectChecker.RC;
103: expr.visitChildren(this );
104: }
105:
106: public void visitUCExpr(final UCExpr expr) {
107: sideEffects |= SideEffectChecker.UC;
108: expr.visitChildren(this );
109: }
110:
111: public void visitNewMultiArrayExpr(final NewMultiArrayExpr expr) {
112: // Memory allocation
113: // NegativeArraySizeException
114: sideEffects |= SideEffectChecker.THROW
115: | SideEffectChecker.ALLOC;
116: expr.visitChildren(this );
117: }
118:
119: public void visitNewArrayExpr(final NewArrayExpr expr) {
120: // Memory allocation
121: // NegativeArraySizeException
122: sideEffects |= SideEffectChecker.THROW
123: | SideEffectChecker.ALLOC;
124: expr.visitChildren(this );
125: }
126:
127: public void visitCatchExpr(final CatchExpr expr) {
128: // Stack change
129: sideEffects |= SideEffectChecker.STACK;
130: expr.visitChildren(this );
131: }
132:
133: public void visitNewExpr(final NewExpr expr) {
134: // Memory allocation
135: sideEffects |= SideEffectChecker.ALLOC;
136: expr.visitChildren(this );
137: }
138:
139: public void visitStackExpr(final StackExpr expr) {
140: // Stack change
141: sideEffects |= SideEffectChecker.STACK;
142:
143: if (expr.isDef()) {
144: sideEffects |= SideEffectChecker.STORE;
145: }
146:
147: expr.visitChildren(this );
148: }
149:
150: public void visitCastExpr(final CastExpr expr) {
151: // ClassCastException
152: if (expr.castType().isReference()) {
153: sideEffects |= SideEffectChecker.THROW;
154: }
155: expr.visitChildren(this );
156: }
157:
158: public void visitArithExpr(final ArithExpr expr) {
159: // DivideByZeroException -- handled by ZeroCheckExpr
160: /*
161: * if (expr.operation() == ArithExpr.DIV || expr.operation() ==
162: * ArithExpr.REM) {
163: *
164: * if (expr.type().isIntegral() || expr.type().equals(Type.LONG)) {
165: * sideEffects |= THROW; } }
166: */
167:
168: expr.visitChildren(this );
169: }
170:
171: public void visitArrayLengthExpr(final ArrayLengthExpr expr) {
172: // NullPointerException
173: sideEffects |= SideEffectChecker.THROW;
174: expr.visitChildren(this );
175: }
176:
177: public void visitArrayRefExpr(final ArrayRefExpr expr) {
178: // NullPointerException, ArrayIndexOutOfBoundsException,
179: // ArrayStoreException
180: sideEffects |= SideEffectChecker.THROW;
181:
182: if (expr.isDef()) {
183: sideEffects |= SideEffectChecker.STORE;
184: }
185:
186: sideEffects |= SideEffectChecker.ALIAS;
187:
188: expr.visitChildren(this );
189: }
190:
191: public void visitFieldExpr(final FieldExpr expr) {
192: // NullPointerException -- handled by ZeroCheckExpr
193: /*
194: * sideEffects |= THROW;
195: */
196:
197: if (expr.isDef()) {
198: sideEffects |= SideEffectChecker.STORE;
199: }
200:
201: final MemberRef field = expr.field();
202:
203: try {
204: final FieldEditor e = context.editField(field);
205:
206: if (!e.isFinal()) {
207: sideEffects |= SideEffectChecker.ALIAS;
208: }
209:
210: if (e.isVolatile()) {
211: sideEffects |= SideEffectChecker.VOLATILE;
212: }
213:
214: context.release(e.fieldInfo());
215: } catch (final NoSuchFieldException e) {
216: // A field wasn't found. Silently assume it's not final and
217: // is volatile.
218: sideEffects |= SideEffectChecker.ALIAS;
219: sideEffects |= SideEffectChecker.VOLATILE;
220: }
221:
222: expr.visitChildren(this );
223: }
224:
225: public void visitStaticFieldExpr(final StaticFieldExpr expr) {
226: if (expr.isDef()) {
227: sideEffects |= SideEffectChecker.STORE;
228: }
229:
230: final MemberRef field = expr.field();
231:
232: try {
233: final FieldEditor e = context.editField(field);
234:
235: if (e.isVolatile()) {
236: sideEffects |= SideEffectChecker.VOLATILE;
237: }
238:
239: context.release(e.fieldInfo());
240: } catch (final NoSuchFieldException e) {
241: // A field wasn't found. Silently assume it's volatile.
242: sideEffects |= SideEffectChecker.VOLATILE;
243: }
244:
245: expr.visitChildren(this );
246: }
247:
248: public void visitCallStaticExpr(final CallStaticExpr expr) {
249: // Call
250: sideEffects |= SideEffectChecker.THROW | SideEffectChecker.CALL;
251: expr.visitChildren(this );
252: }
253:
254: public void visitCallMethodExpr(final CallMethodExpr expr) {
255: // Call
256: sideEffects |= SideEffectChecker.THROW | SideEffectChecker.CALL;
257: expr.visitChildren(this );
258: }
259:
260: public void visitMonitorStmt(final MonitorStmt stmt) {
261: // Synchronization
262: sideEffects |= SideEffectChecker.THROW | SideEffectChecker.SYNC;
263: stmt.visitChildren(this );
264: }
265:
266: public void visitStackManipStmt(final StackManipStmt stmt) {
267: // Stack change
268: sideEffects |= SideEffectChecker.STACK;
269: stmt.visitChildren(this);
270: }
271: }
|