soot.jimple.toolkits.typing.fast.BytecodeHierarchy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of robovm-soot Show documentation
Show all versions of robovm-soot Show documentation
RoboVM fork of Soot - A Java optimization framework
/* Soot - a J*va Optimization Framework
* Copyright (C) 2008 Ben Bellamy
*
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package soot.jimple.toolkits.typing.fast;
import java.util.*;
import soot.*;
/**
* @author Ben Bellamy
*/
public class BytecodeHierarchy implements IHierarchy
{
private static class AncestryTreeNode
{
public final AncestryTreeNode next;
public final RefType type;
public AncestryTreeNode(AncestryTreeNode next, RefType type)
{
this.next = next;
this.type = type;
}
}
/* Returns a collection of nodes, each with type Object, each at the leaf
end of a different path from root to Object. */
private static Collection buildAncestryTree(RefType root)
{
LinkedList leafs = new LinkedList();
leafs.add(new AncestryTreeNode(null, root));
LinkedList r = new LinkedList();
while ( !leafs.isEmpty() )
{
AncestryTreeNode node = leafs.remove();
if ( TypeResolver.typesEqual(
node.type, RefType.v("java.lang.Object")) )
r.add(node);
else
{
SootClass sc = node.type.getSootClass();
for ( Iterator i = sc.getInterfaces().iterator(); i.hasNext(); )
leafs.add(new AncestryTreeNode(
node, ((SootClass)i.next()).getType()));
// The superclass of all interfaces is Object
// -- try to discard phantom interfaces.
if ( ( !sc.isInterface() || sc.getInterfaceCount() == 0 ) && !sc.isPhantom())
leafs.add(new AncestryTreeNode(
node, sc.getSuperclass().getType()));
}
}
return r;
}
private static RefType leastCommonNode(
AncestryTreeNode a, AncestryTreeNode b)
{
RefType r = null;
while ( a != null && b != null
&& TypeResolver.typesEqual(a.type, b.type) )
{
r = a.type;
a = a.next;
b = b.next;
}
return r;
}
public Collection lcas(Type a, Type b)
{
return lcas_(a, b);
}
public static Collection lcas_(Type a, Type b)
{
if ( TypeResolver.typesEqual(a, b) )
return new SingletonList(a);
else if ( a instanceof BottomType )
return new SingletonList(b);
else if ( b instanceof BottomType )
return new SingletonList(a);
else if ( a instanceof IntegerType && b instanceof IntegerType )
return new SingletonList(IntType.v());
else if ( a instanceof PrimType || b instanceof PrimType )
return new EmptyList();
else if ( a instanceof NullType )
return new SingletonList(b);
else if ( b instanceof NullType )
return new SingletonList(a);
// a and b are both ArrayType or RefType
else if ( a instanceof ArrayType && b instanceof ArrayType )
{
Type eta = ((ArrayType)a).getElementType(),
etb = ((ArrayType)b).getElementType();
Collection ts;
// Primitive arrays are not covariant but all other arrays are
if ( eta instanceof PrimType || eta instanceof PrimType )
ts = new EmptyList();
else
ts = lcas_(eta, etb);
LinkedList r = new LinkedList();
if ( ts.isEmpty() )
{
r.add(RefType.v("java.io.Serializable"));
r.add(RefType.v("java.lang.Cloneable"));
}
else
for ( Type t : ts )
r.add(t.makeArrayType());
return r;
}
else if ( a instanceof ArrayType || b instanceof ArrayType )
{
Type rt;
if ( a instanceof ArrayType )
rt = b;
else
rt = a;
/* If the reference type implements Serializable or Cloneable then
these are the least common supertypes, otherwise the only one is
Object. */
LinkedList r = new LinkedList();
/* Do not consider Object to be a subtype of Serializable or Cloneable
(it can appear this way if phantom-refs is enabled and rt.jar is not
available) otherwise an infinite loop can result. */
if (!TypeResolver.typesEqual(RefType.v("java.lang.Object"), rt)) {
if ( ancestor_(RefType.v("java.io.Serializable"), rt) )
r.add(RefType.v("java.io.Serializable"));
if ( ancestor_(RefType.v("java.lang.Cloneable"), rt) )
r.add(RefType.v("java.lang.Cloneable"));
}
if ( r.isEmpty() )
r.add(RefType.v("java.lang.Object"));
return r;
}
// a and b are both RefType
else
{
Collection treea = buildAncestryTree((RefType)a),
treeb = buildAncestryTree((RefType)b);
LinkedList r = new LinkedList();
for ( AncestryTreeNode nodea : treea )
for ( AncestryTreeNode nodeb : treeb )
{
RefType t = leastCommonNode(nodea, nodeb);
boolean least = true;
for ( ListIterator i = r.listIterator(); i.hasNext(); )
{
Type t_ = (Type)i.next();
if ( ancestor_(t, t_) )
{
least = false;
break;
}
if ( ancestor_(t_, t) )
i.remove();
}
if ( least )
r.add(t);
}
//in case of phantom classes that screw up type resolution here,
//default to only possible common reftype, java.lang.Object
//kludge on a kludge on a kludge...
//syed - 05/06/2009
if ( r.isEmpty() )
r.add(RefType.v("java.lang.Object"));
return r;
}
}
public boolean ancestor(Type ancestor, Type child)
{
return ancestor_(ancestor, child);
}
public static boolean ancestor_(Type ancestor, Type child)
{
if ( TypeResolver.typesEqual(ancestor, child) )
return true;
else if ( child instanceof BottomType )
return true;
else if ( ancestor instanceof BottomType )
return false;
else if ( ancestor instanceof IntegerType
&& child instanceof IntegerType )
return true;
else if ( ancestor instanceof PrimType || child instanceof PrimType )
return false;
else if ( child instanceof NullType )
return true;
else if ( ancestor instanceof NullType )
return false;
else return Scene.v().getOrMakeFastHierarchy().canStoreType(
child, ancestor);
}
private static LinkedList superclassPath(RefType t)
{
LinkedList r = new LinkedList();
r.addFirst(t);
SootClass sc = t.getSootClass();
while ( sc.hasSuperclass() )
{
sc = sc.getSuperclass();
r.addFirst((RefType)sc.getType());
}
return r;
}
public static RefType lcsc(RefType a, RefType b)
{
LinkedList pathA = superclassPath(a),
pathB = superclassPath(b);
RefType r = null;
while ( !(pathA.isEmpty() || pathB.isEmpty())
&& TypeResolver.typesEqual(pathA.getFirst(), pathB.getFirst()) )
{
r = pathA.removeFirst();
pathB.removeFirst();
}
return r;
}
}