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 soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
The newest version!
package soot.jimple.toolkits.typing.fast;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.ListIterator;
import soot.ArrayType;
import soot.FloatType;
import soot.IntegerType;
import soot.NullType;
import soot.PrimType;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.Type;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2008 Ben Bellamy
*
* All rights reserved.
* %%
* This program 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 program 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
/**
* @author Ben Bellamy
*/
public class BytecodeHierarchy implements IHierarchy {
/*
* 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) {
if (root.getSootClass().isPhantom()) {
return Collections.emptyList();
}
LinkedList leafs = new LinkedList();
leafs.add(new AncestryTreeNode(null, root));
LinkedList r = new LinkedList();
final RefType objectType = Scene.v().getObjectType();
while (!leafs.isEmpty()) {
AncestryTreeNode node = leafs.remove();
if (TypeResolver.typesEqual(node.type, objectType)) {
r.add(node);
} else {
SootClass sc = node.type.getSootClass();
for (SootClass i : sc.getInterfaces()) {
leafs.add(new AncestryTreeNode(node, (i).getType()));
}
// The superclass of all interfaces is Object
// -- try to discard phantom interfaces.
if ((!sc.isInterface() || sc.getInterfaceCount() == 0) && !sc.isPhantom() && sc.hasSuperclass()) {
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 static Collection lcas_(Type a, Type b) {
return lcas_(a, b, false);
}
public static Collection lcas_(Type a, Type b, boolean useWeakObjectType) {
if (TypeResolver.typesEqual(a, b)) {
return Collections.singletonList(a);
} else if (a instanceof BottomType) {
return Collections.singletonList(b);
} else if (b instanceof BottomType) {
return Collections.singletonList(a);
} else if (a instanceof WeakObjectType && b instanceof RefType) {
return Collections.singletonList(b);
} else if (b instanceof WeakObjectType && a instanceof RefType) {
return Collections.singletonList(a);
} else if (a instanceof IntegerType && b instanceof IntegerType) {
int m = Math.max(IntUtils.getMaxValue((IntegerType) a), IntUtils.getMaxValue((IntegerType) b));
return Collections.singletonList((Type) IntUtils.getTypeByWidth(m));
} else if (a instanceof IntegerType && b instanceof FloatType) {
return Collections.singletonList(FloatType.v());
} else if (b instanceof IntegerType && a instanceof FloatType) {
return Collections.singletonList(FloatType.v());
} else if (a instanceof PrimType || b instanceof PrimType) {
return Collections.emptyList();
} else if (a instanceof NullType) {
return Collections.singletonList(b);
} else if (b instanceof NullType) {
return Collections.singletonList(a);
} 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 || etb instanceof PrimType) {
ts = Collections.emptyList();
} else {
ts = lcas_(eta, etb);
}
LinkedList r = new LinkedList();
if (ts.isEmpty()) {
if (useWeakObjectType) {
r.add(new WeakObjectType(Scene.v().getObjectType().toString()));
} else {
// From Java Language Spec 2nd ed., Chapter 10, Arrays
r.add(RefType.v(Scene.v().getObjectType().toString()));
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 = (a instanceof ArrayType) ? b : 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(Scene.v().getObjectType(), rt)) {
RefType refSerializable = RefType.v("java.io.Serializable");
if (ancestor_(refSerializable, rt)) {
r.add(refSerializable);
}
RefType refCloneable = RefType.v("java.lang.Cloneable");
if (ancestor_(refCloneable, rt)) {
r.add(refCloneable);
}
}
if (r.isEmpty()) {
r.add(Scene.v().getObjectType());
}
return r;
} else {
// a and b are both RefType
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_ = 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(Scene.v().getObjectType());
}
return r;
}
}
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);
}
}
/**
* Returns a list of the super classes of a given type in which the anchor will always be the first element even when the
* types class is phantom. Note anchor should always be type {@link Throwable} as this is the root of all exception types.
*/
private static Deque superclassPath(RefType t, RefType anchor) {
Deque r = new ArrayDeque();
r.addFirst(t);
if (TypeResolver.typesEqual(t, anchor)) {
return r;
}
for (SootClass sc = t.getSootClass(); sc.hasSuperclass();) {
sc = sc.getSuperclass();
RefType cur = sc.getType();
r.addFirst(cur);
if (TypeResolver.typesEqual(cur, anchor)) {
break;
}
}
if (!TypeResolver.typesEqual(r.getFirst(), anchor)) {
r.addFirst(anchor);
}
return r;
}
public static RefType lcsc(RefType a, RefType b) {
return lcsc(a, b, Scene.v().getObjectType());
}
public static RefType lcsc(RefType a, RefType b, RefType anchor) {
if (a == b) {
return a;
}
Deque pathA = superclassPath(a, anchor);
Deque pathB = superclassPath(b, anchor);
RefType r = null;
while (!(pathA.isEmpty() || pathB.isEmpty()) && TypeResolver.typesEqual(pathA.getFirst(), pathB.getFirst())) {
r = pathA.removeFirst();
pathB.removeFirst();
}
return r;
}
@Override
public Collection lcas(Type a, Type b, boolean useWeakObjectType) {
return lcas_(a, b, useWeakObjectType);
}
@Override
public boolean ancestor(Type ancestor, Type child) {
return ancestor_(ancestor, child);
}
private static class AncestryTreeNode {
public final AncestryTreeNode next;
public final RefType type;
public AncestryTreeNode(AncestryTreeNode next, RefType type) {
this.next = next;
this.type = type;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy