Mirror of the BLOAT repository https://www.cs.purdue.edu/homes/hosking/bloat/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
bloat/src/edu/purdue/cs/bloat/trans/SideEffectChecker.java

359 lines
11 KiB

/*
* Class: SideEffectChecker
* Version:
* Date:
*
* All files in the distribution of BLOAT (Bytecode Level Optimization and
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
* Research Foundation of Purdue University. All rights reserved.
*
* <p>
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all
* such copies, and that any documentation, announcements, and other
* materials related to such distribution and use acknowledge that the
* software was developed at Purdue University, West Lafayette, IN by
* @author Antony Hosking
* @author David Whitlock
* @author Nathaniel Nystrom
* No charge may be made for copies, derivations, or distributions of
* this material without the express written consent of the copyright
* holder. Neither the name of the University nor the name of the
* author may be used to endorse or promote products derived from this
* material without specific prior written permission. THIS SOFTWARE
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
*
* <p>
*
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
* contributed by The Australian National University by
* @author Arrin Daley
* @author John N Zigman
*
* <p>
* Java is a trademark of Sun Microsystems, Inc.
*/
package edu.purdue.cs.bloat.trans;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
import edu.purdue.cs.bloat.editor.EditorContext;
import edu.purdue.cs.bloat.editor.MemberRef;
import edu.purdue.cs.bloat.tree.ArithExpr;
import edu.purdue.cs.bloat.tree.ArrayLengthExpr;
import edu.purdue.cs.bloat.tree.ArrayRefExpr;
import edu.purdue.cs.bloat.tree.CallMethodExpr;
import edu.purdue.cs.bloat.tree.CallStaticExpr;
import edu.purdue.cs.bloat.tree.CastExpr;
import edu.purdue.cs.bloat.tree.CatchExpr;
import edu.purdue.cs.bloat.tree.FieldExpr;
import edu.purdue.cs.bloat.tree.LocalExpr;
import edu.purdue.cs.bloat.tree.MonitorStmt;
import edu.purdue.cs.bloat.tree.NewArrayExpr;
import edu.purdue.cs.bloat.tree.NewExpr;
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr;
import edu.purdue.cs.bloat.tree.RCExpr;
import edu.purdue.cs.bloat.tree.StackExpr;
import edu.purdue.cs.bloat.tree.StackManipStmt;
import edu.purdue.cs.bloat.tree.StaticFieldExpr;
import edu.purdue.cs.bloat.tree.StoreExpr;
import edu.purdue.cs.bloat.tree.TreeVisitor;
import edu.purdue.cs.bloat.tree.UCExpr;
import edu.purdue.cs.bloat.tree.ZeroCheckExpr;
/**
* <tt>SideEffectChecker</tt> traverses a tree and determines if 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(EditorContext context) {
this.context = context;
}
public int sideEffects() {
return sideEffects;
}
public boolean hasSideEffects() {
return sideEffects != 0;
}
public void reset() {
sideEffects = 0;
}
public void visitStoreExpr(StoreExpr expr) {
sideEffects |= STORE;
expr.visitChildren(this);
}
public void visitLocalExpr(LocalExpr expr) {
if (expr.isDef()) {
sideEffects |= STORE;
}
expr.visitChildren(this);
}
public void visitZeroCheckExpr(ZeroCheckExpr expr) {
sideEffects |= THROW;
expr.visitChildren(this);
}
public void visitRCExpr(RCExpr expr) {
sideEffects |= RC;
expr.visitChildren(this);
}
public void visitUCExpr(UCExpr expr) {
sideEffects |= UC;
expr.visitChildren(this);
}
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) {
// Memory allocation
// NegativeArraySizeException
sideEffects |= THROW | ALLOC;
expr.visitChildren(this);
}
public void visitNewArrayExpr(NewArrayExpr expr) {
// Memory allocation
// NegativeArraySizeException
sideEffects |= THROW | ALLOC;
expr.visitChildren(this);
}
public void visitCatchExpr(CatchExpr expr) {
// Stack change
sideEffects |= STACK;
expr.visitChildren(this);
}
public void visitNewExpr(NewExpr expr) {
// Memory allocation
sideEffects |= ALLOC;
expr.visitChildren(this);
}
public void visitStackExpr(StackExpr expr) {
// Stack change
sideEffects |= STACK;
if (expr.isDef()) {
sideEffects |= STORE;
}
expr.visitChildren(this);
}
public void visitCastExpr(CastExpr expr) {
// ClassCastException
if (expr.castType() instanceof ReferenceType) {
sideEffects |= THROW;
}
expr.visitChildren(this);
}
public void visitArithExpr(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(ArrayLengthExpr expr) {
// NullPointerException
sideEffects |= THROW;
expr.visitChildren(this);
}
public void visitArrayRefExpr(ArrayRefExpr expr) {
// NullPointerException, ArrayIndexOutOfBoundsException,
// ArrayStoreException
sideEffects |= THROW;
if (expr.isDef()) {
sideEffects |= STORE;
}
sideEffects |= ALIAS;
expr.visitChildren(this);
}
public void visitFieldExpr(FieldExpr expr) {
// NullPointerException -- handled by ZeroCheckExpr
/*
* sideEffects |= THROW;
*/
if (expr.isDef()) {
sideEffects |= STORE;
}
MemberRef field = expr.field();
try {
try {
ReferenceType type = field.declaringClass();
if (type instanceof ArrayType) {// TODO
Type elementType = ((ArrayType) type).getElementType();
if (elementType instanceof BasicType) {
return; // Already loaded
}
type = (ObjectType) elementType;
}
JavaClass jc = context.loadClass(((ObjectType) type)
.getClassName());
Field[] fields = jc.getFields();
Field e = null;
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(field.name())
&& fields[i].getType().equals(field.type())) {
e = fields[i];
break;
}
}
if (e == null)
throw new NoSuchFieldException("field :" + field
+ "not found");
if (!e.isFinal()) {
sideEffects |= ALIAS;
}
if (e.isVolatile()) {
sideEffects |= VOLATILE;
}
// WE NEVER STARTED EDITING IT SO WE DON'T NEED TO RELEASE IT
// context.release(e.fieldInfo());
} catch (NoSuchFieldException e) {
// A field wasn't found. Silently assume it's not final and
// is volatile.
sideEffects |= ALIAS;
sideEffects |= VOLATILE;
}
} catch (ClassNotFoundException cnfe) {
System.out.println(cnfe.getMessage());
}
expr.visitChildren(this);
}
public void visitStaticFieldExpr(StaticFieldExpr expr) {
if (expr.isDef()) {
sideEffects |= STORE;
}
MemberRef field = expr.field();
try {
try {
ReferenceType type = field.declaringClass();
if (type instanceof ArrayType) {// TODO
Type elementType = ((ArrayType) type).getElementType();
if (elementType instanceof BasicType) {
return; // Already loaded
}
type = (ObjectType) elementType;
}
JavaClass jc = context.loadClass(((ObjectType) type)
.getClassName());
Field e = null;
Field[] fields = jc.getFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(field.name())
&& fields[i].getType().equals(field.type())) {
e = fields[i];
break;
}
}
if (e == null)
throw new NoSuchFieldException("field :" + field
+ "not found");
if (e.isVolatile()) {
sideEffects |= VOLATILE;
}
// WE NEVER STARTED EDITING IT SO WE DON'T NEED TO RELEASE IT
// context.release(e.fieldInfo());
} catch (NoSuchFieldException e) {
// A field wasn't found. Silently assume it's volatile.
sideEffects |= VOLATILE;
}
} catch (ClassNotFoundException cnfe) {
System.out.println(cnfe.getMessage());
}
expr.visitChildren(this);
}
public void visitCallStaticExpr(CallStaticExpr expr) {
// Call
sideEffects |= THROW | CALL;
expr.visitChildren(this);
}
public void visitCallMethodExpr(CallMethodExpr expr) {
// Call
sideEffects |= THROW | CALL;
expr.visitChildren(this);
}
public void visitMonitorStmt(MonitorStmt stmt) {
// Synchronization
sideEffects |= THROW | SYNC;
stmt.visitChildren(this);
}
public void visitStackManipStmt(StackManipStmt stmt) {
// Stack change
sideEffects |= STACK;
stmt.visitChildren(this);
}
}