/* 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.tbaa;
import EDU.purdue.cs.bloat.editor.*;
import EDU.purdue.cs.bloat.tree.*;
import EDU.purdue.cs.bloat.util.*;
/**
* Performs Type-Based Alias Analysis (TBAA) to determine if one expression can
* alias another. An expression may alias another expression if there is the
* possibility that they refer to the same location in memory. BLOAT models
* expressions that may reference memory locations with <tt>MemRefExpr</tt>s.
* There are two kinds of "access expressions" in Java: field accesses (<tt>FieldExpr</tt>
* and <tt>StaticFieldExpr</tt>) and array references (<tt>ArrayRefExpr</tt>).
* Access paths consist of one or more access expressions. For instance,
* <tt>a.b[i].c</tt> is an access expression.
*
* <p>
*
* TBAA uses the FieldTypeDecl relation to determine whether or not two access
* paths may refer to the same memory location.
*
* <p>
*
* <table>
* <th>
* <td>AP1 </td>
* <td>AP2 </td>
* <td>FieldTypeDecl(AP1, Ap2)</td>
* </th>
* <tr>
* <Td>p </td>
* <Td>p </td>
* <td>true </td>
* </tr>
* <tr>
* <td>p.f </td>
* <td>q.g </td>
* <td>(f = g) && FieldTypeDecl(p, q)</td>
* </tr>
* <tr>
* <td>p.f </td>
* <Td>q[i]</td>
* <td>false </td>
* </tr>
* <tr>
* <td>p[i]</td>
* <td>q[j]</td>
* <td>FieldTypeDecl(p, q) </td>
* </tr>
* <tr>
* <td>p </td>
* <td>q </td>
* <td>TypeDecl(p, q) </td>
* </tr>
* </table>
*
* <p>
*
* The TypeDecl(AP1, AP2) relation is defined as:
* <p align=center>
* Subtypes(Type(AP1)) INTERSECT Subtypes(Type(AP2)) != EMPTY
* </p>
*
* The subtype relationships are determined by the <tt>ClassHierarchy</tt>.
*
* @see ClassHierarchy
* @see MemRefExpr
* @see FieldExpr
* @see StaticFieldExpr
* @see ArrayRefExpr
*/
public class TBAA {
/**
* Returns true, if expression <tt>a</tt> can alias expression <tt>b</tt>.
*/
public static boolean canAlias(final EditorContext context, final Expr a,
final Expr b) {
// Only memory reference expressions can have aliases.
if (!(a instanceof MemRefExpr)) {
return false;
}
// Only memory reference expressions can have aliases.
if (!(b instanceof MemRefExpr)) {
return false;
}
// Equal expressions can be aliases.
if (a.equalsExpr(b)) {
return true;
}
MemberRef af = null; // Field accessed by expression a
MemberRef bf = null; // Field accessed by expression b
if (a instanceof FieldExpr) {
af = ((FieldExpr) a).field();
}
if (a instanceof StaticFieldExpr) {
af = ((StaticFieldExpr) a).field();
}
if (b instanceof FieldExpr) {
bf = ((FieldExpr) b).field();
}
if (b instanceof StaticFieldExpr) {
bf = ((StaticFieldExpr) b).field();
}
// Arrays and fields cannot alias the same location.
if ((a instanceof ArrayRefExpr) && (bf != null)) {
return false;
}
// Arrays and fields cannot alias the same location.
if ((b instanceof ArrayRefExpr) && (af != null)) {
return false;
}
final ClassHierarchy hier = context.getHierarchy();
// Only type-compatible arrays can alias the same location.
if ((a instanceof ArrayRefExpr) && (b instanceof ArrayRefExpr)) {
final ArrayRefExpr aa = (ArrayRefExpr) a;
final ArrayRefExpr bb = (ArrayRefExpr) b;
final Type aaIndexType = aa.index().type();
final Type bbIndexType = bb.index().type();
final Type aaArrayType = aa.array().type();
final Type bbArrayType = bb.array().type();
Assert.isTrue(aaIndexType.isIntegral(), aa.index() + " in " + aa
+ " (" + aaIndexType + ") is not an integer");
Assert.isTrue(bbIndexType.isIntegral(), bb.index() + " in " + bb
+ " (" + bbIndexType + ") is not an integer");
Assert.isTrue(aaArrayType.isArray()
|| aaArrayType.equals(Type.OBJECT)
|| aaArrayType.equals(Type.SERIALIZABLE)
|| aaArrayType.equals(Type.CLONEABLE)
|| aaArrayType.isNull(), aa.array() + " in " + aa + " ("
+ aaArrayType + ") is not an array");
Assert.isTrue(bbArrayType.isArray()
|| bbArrayType.equals(Type.OBJECT)
|| bbArrayType.equals(Type.SERIALIZABLE)
|| bbArrayType.equals(Type.CLONEABLE)
|| bbArrayType.isNull(), bb.array() + " in " + bb + " ("
+ bbArrayType + ") is not an array");
// Optimization: if constant indices. Only equal indices can
// alias the same location.
if ((aa.index() instanceof ConstantExpr)
&& (bb.index() instanceof ConstantExpr)) {
final ConstantExpr ai = (ConstantExpr) aa.index();
final ConstantExpr bi = (ConstantExpr) bb.index();
if ((ai.value() != null) && (bi.value() != null)) {
if (!ai.value().equals(bi.value())) {
return false;
}
}
}
return TBAA.intersects(hier, aaArrayType, bbArrayType);
}
try {
if (af != null) {
final FieldEditor e = context.editField(af);
if (e.isVolatile()) {
context.release(e.fieldInfo());
return true;
}
if (e.isFinal()) {
context.release(e.fieldInfo());
return false;
}
context.release(e.fieldInfo());
}
if (bf != null) {
final FieldEditor e = context.editField(bf);
if (e.isVolatile()) {
context.release(e.fieldInfo());
return true;
}
if (e.isFinal()) {
context.release(e.fieldInfo());
return false;
}
context.release(e.fieldInfo());
}
} catch (final NoSuchFieldException e) {
// A field wasn't found. Silently assume there is an alias.
return true;
}
// Only fields with the same name can alias the same location.
if ((af != null) && (bf != null)) {
return af.equals(bf);
}
// Default case. This shouldn't happen.
return TBAA.intersects(hier, a.type(), b.type());
}
/**
* Returns <tt>true</tt> if type a and type c intersect. That is, the two
* types have a non-null intersection.
*/
private static boolean intersects(final ClassHierarchy hier, final Type a,
final Type b) {
return !hier.intersectType(a, b).isNull();
}
}