All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
soot.Body Maven / Gradle / Ivy
/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-1999 Raja Vallee-Rai
*
* 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.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
package soot;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import soot.jimple.CaughtExceptionRef;
import soot.jimple.DefinitionStmt;
import soot.jimple.IdentityStmt;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InvokeExpr;
import soot.jimple.InvokeStmt;
import soot.jimple.ParameterRef;
import soot.jimple.ThisRef;
import soot.options.Options;
import soot.tagkit.AbstractHost;
import soot.tagkit.Tag;
import soot.toolkits.exceptions.PedanticThrowAnalysis;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.FlowSet;
import soot.toolkits.scalar.InitAnalysis;
import soot.toolkits.scalar.LocalDefs;
import soot.toolkits.scalar.SimpleLiveLocals;
import soot.toolkits.scalar.SmartLocalDefs;
import soot.util.Chain;
import soot.util.EscapedWriter;
import soot.util.HashChain;
/**
* Abstract base class that models the body (code attribute) of a Java method.
* Classes that implement an Intermediate Representation for a method body should subclass it.
* In particular the classes GrimpBody, JimpleBody and BafBody all extend this
* class. This class provides methods that are common to any IR, such as methods
* to get the body's units (statements), traps, and locals.
*
* @see soot.grimp.GrimpBody
* @see soot.jimple.JimpleBody
* @see soot.baf.BafBody
*/
public abstract class Body extends AbstractHost implements Serializable
{
/** The method associated with this Body. */
protected transient SootMethod method = null;
/** The chain of locals for this Body. */
protected Chain localChain = new HashChain();
/** The chain of traps for this Body. */
protected Chain trapChain = new HashChain();
// RoboVM note: Added
protected List localVariables = new ArrayList<>();
/** The chain of units for this Body. */
protected PatchingChain unitChain = new PatchingChain(new HashChain());
/** Creates a deep copy of this Body. */
abstract public Object clone();
/** Creates a Body associated to the given method. Used by subclasses during initialization.
* Creation of a Body is triggered by e.g. Jimple.v().newBody(options).
*/
protected Body(SootMethod m)
{
this.method = m;
}
/** Creates an extremely empty Body. The Body is not associated to any method. */
protected Body()
{
}
/**
* Returns the method associated with this Body.
* @return the method that owns this body.
*/
public SootMethod getMethod()
{
if(method == null)
throw new RuntimeException("no method associated w/ body");
return method;
}
/**
* Sets the method associated with this Body.
* @param method the method that owns this body.
*
*/
public void setMethod(SootMethod method)
{
this.method = method;
}
/** Returns the number of locals declared in this body. */
public int getLocalCount()
{
return localChain.size();
}
/** Copies the contents of the given Body into this one. */
public Map importBodyContentsFrom(Body b)
{
HashMap bindings = new HashMap();
{
Iterator it = b.getUnits().iterator();
// Clone units in body's statement list
while(it.hasNext()) {
Unit original = it.next();
Unit copy = (Unit) original.clone();
copy.addAllTagsOf(original);
// Add cloned unit to our unitChain.
unitChain.addLast(copy);
// Build old <-> new map to be able to patch up references to other units
// within the cloned units. (these are still refering to the original
// unit objects).
bindings.put(original, copy);
}
}
{
// Clone trap units.
Iterator it = b.getTraps().iterator();
while(it.hasNext()) {
Trap original = it.next();
Trap copy = (Trap) original.clone();
// Add cloned unit to our trap list.
trapChain.addLast(copy);
// Store old <-> new mapping.
bindings.put(original, copy);
}
}
{
// Clone local units.
Iterator it = b.getLocals().iterator();
while(it.hasNext()) {
Local original = it.next();
Local copy = (Local) original.clone();
// Add cloned unit to our trap list.
localChain.addLast(copy);
// Build old <-> new mapping.
bindings.put(original, copy);
}
}
{
// Patch up references within units using our (old <-> new) map.
Iterator it = getAllUnitBoxes().iterator();
while(it.hasNext()) {
UnitBox box = it.next();
Unit newObject, oldObject = box.getUnit();
// if we have a reference to an old object, replace it
// it's clone.
if( (newObject = (Unit) bindings.get(oldObject)) != null )
box.setUnit(newObject);
}
}
{
// backpatching all local variables.
Iterator it = getUseBoxes().iterator();
while(it.hasNext()) {
ValueBox vb = it.next();
if(vb.getValue() instanceof Local)
vb.setValue((Value) bindings.get(vb.getValue()));
}
it = getDefBoxes().iterator();
while(it.hasNext()) {
ValueBox vb = it.next();
if(vb.getValue() instanceof Local)
vb.setValue((Value) bindings.get(vb.getValue()));
}
}
return bindings;
}
/** Verifies a few sanity conditions on the contents on this body. */
public void validate()
{
//System.out.println("body: "+this.getUnits());
validateLocals();
validateTraps();
validateUnitBoxes();
validateLocalVariables(); // RoboVM note: Added
if (Options.v().debug() || Options.v().validate()) {
validateUses();
validateValueBoxes();
checkInit();
checkTypes();
checkLocals();
}
}
/** Verifies that a ValueBox is not used in more than one place. */
public void validateValueBoxes()
{
List l = getUseAndDefBoxes();
for( int i = 0; i < l.size(); i++ ) {
for( int j = 0; j < l.size(); j++ ) {
if( i == j ) continue;
if( l.get(i) == l.get(j) ) {
System.err.println("Aliased value box : "+l.get(i)+" in "+getMethod());
for( Iterator uIt = getUnits().iterator(); uIt.hasNext(); ) {
final Unit u = uIt.next();
System.err.println(""+u);
}
throw new RuntimeException("Aliased value box : "+l.get(i)+" in "+getMethod());
}
}
}
}
/** Verifies that each Local of getUseAndDefBoxes() is in this body's locals Chain. */
public void validateLocals()
{
Iterator it = getUseBoxes().iterator();
while(it.hasNext()){
validateLocal( it.next() );
}
it = getDefBoxes().iterator();
while(it.hasNext()){
validateLocal( it.next() );
}
}
private void validateLocal( ValueBox vb ) {
Value value;
if( (value = vb.getValue()) instanceof Local) {
//System.out.println("localChain: "+localChain);
if(!localChain.contains(value))
throw new RuntimeException("Local not in chain : "+value+" in "+getMethod());
}
}
/** Verifies that the begin, end and handler units of each trap are in this body. */
public void validateTraps()
{
Iterator it = getTraps().iterator();
while (it.hasNext())
{
Trap t = it.next();
if (!unitChain.contains(t.getBeginUnit()))
throw new RuntimeException("begin not in chain"+" in "+getMethod());
if (!unitChain.contains(t.getEndUnit()))
throw new RuntimeException("end not in chain"+" in "+getMethod());
if (!unitChain.contains(t.getHandlerUnit()))
throw new RuntimeException("handler not in chain"+" in "+getMethod());
}
}
// RoboVM note: Added
public void validateLocalVariables()
{
Iterator it = getLocalVariables().iterator();
while (it.hasNext())
{
LocalVariable lv = it.next();
if (lv.getStartUnit() != null && !unitChain.contains(lv.getStartUnit()))
throw new RuntimeException("start not in chain"+" in "+getMethod());
if (lv.getEndUnit() != null && !unitChain.contains(lv.getEndUnit()))
throw new RuntimeException("end not in chain"+" in "+getMethod());
}
}
/** Verifies that the UnitBoxes of this Body all point to a Unit contained within this body. */
public void validateUnitBoxes()
{
Iterator it = getAllUnitBoxes().iterator();
while (it.hasNext())
{
UnitBox ub = it.next();
if (!unitChain.contains(ub.getUnit()))
throw new RuntimeException
("Unitbox points outside unitChain! to unit : "+ub.getUnit()+" in "+getMethod());
}
}
/** Verifies that each use in this Body has a def. */
public void validateUses()
{
UnitGraph g = new ExceptionalUnitGraph(this);
LocalDefs ld = new SmartLocalDefs(g, new SimpleLiveLocals(g));
Iterator unitsIt = getUnits().iterator();
while (unitsIt.hasNext())
{
Unit u = unitsIt.next();
Iterator useBoxIt = u.getUseBoxes().iterator();
while (useBoxIt.hasNext())
{
Value v = (useBoxIt.next()).getValue();
if (v instanceof Local)
{
// This throws an exception if there is
// no def already; we check anyhow.
List l = ld.getDefsOfAt((Local)v, u);
if (l.size() == 0){
for( Iterator uuIt = getUnits().iterator(); uuIt.hasNext(); ) {
final Unit uu = uuIt.next();
System.err.println(""+uu);
}
throw new RuntimeException("no defs for value: "+v+"!"+" in "+getMethod());
}
}
}
}
}
/** Returns a backed chain of the locals declared in this Body. */
public Chain getLocals() {return localChain;}
/** Returns a backed view of the traps found in this Body. */
public Chain getTraps() {return trapChain;}
// RoboVM note: Added
public List getLocalVariables() {
return localVariables;
}
/** Return LHS of the first identity stmt assigning from \@this. **/
public Local getThisLocal()
{
Iterator unitsIt = getUnits().iterator();
while (unitsIt.hasNext())
{
Unit s = unitsIt.next();
if (s instanceof IdentityStmt &&
((IdentityStmt)s).getRightOp() instanceof ThisRef)
return (Local)(((IdentityStmt)s).getLeftOp());
}
throw new RuntimeException("couldn't find identityref!"+" in "+getMethod());
}
/** Return LHS of the first identity stmt assigning from \@parameter i. **/
public Local getParameterLocal(int i)
{
Iterator unitsIt = getUnits().iterator();
while (unitsIt.hasNext())
{
Unit s = unitsIt.next();
if (s instanceof IdentityStmt &&
((IdentityStmt)s).getRightOp() instanceof ParameterRef)
{
IdentityStmt is = (IdentityStmt)s;
ParameterRef pr = (ParameterRef)is.getRightOp();
if (pr.getIndex() == i)
return (Local)is.getLeftOp();
}
}
throw new RuntimeException("couldn't find parameterref!"+" in "+getMethod());
}
/**
* Returns the Chain of Units that make up this body. The units are
* returned as a PatchingChain. The client can then manipulate the chain,
* adding and removing units, and the changes will be reflected in the body.
* Since a PatchingChain is returned the client need not worry about removing exception
* boundary units or otherwise corrupting the chain.
*
* @return the units in this Body
*
* @see PatchingChain
* @see Unit
*/
public PatchingChain getUnits()
{
return unitChain;
}
/**
* Returns the result of iterating through all Units in this body
* and querying them for their UnitBoxes. All UnitBoxes thus
* found are returned. Branching Units and statements which use
* PhiExpr will have UnitBoxes; a UnitBox contains a Unit that is
* either a target of a branch or is being used as a pointer to
* the end of a CFG block.
*
* This method is typically used for pointer patching, eg when
* the unit chain is cloned.
*
* @return A list of all the UnitBoxes held by this body's units.
* @see UnitBox
* @see #getUnitBoxes(boolean)
* @see Unit#getUnitBoxes()
* @see soot.shimple.PhiExpr#getUnitBoxes()
**/
public List getAllUnitBoxes()
{
ArrayList unitBoxList = new ArrayList();
{
Iterator it = unitChain.iterator();
while(it.hasNext()) {
Unit item = it.next();
unitBoxList.addAll(item.getUnitBoxes());
}
}
{
Iterator it = trapChain.iterator();
while(it.hasNext()) {
Trap item = it.next();
unitBoxList.addAll(item.getUnitBoxes());
}
}
// RoboVM note: Added
{
Iterator it = localVariables.iterator();
while(it.hasNext()) {
LocalVariable item = it.next();
unitBoxList.addAll(item.getUnitBoxes());
}
}
return unitBoxList;
}
/**
* If branchTarget is true, returns the result of iterating
* through all branching Units in this body and querying them for
* their UnitBoxes. These UnitBoxes contain Units that are the
* target of a branch. This is useful for, say, labeling blocks
* or updating the targets of branching statements.
*
* If branchTarget is false, returns the result of iterating
* through the non-branching Units in this body and querying them
* for their UnitBoxes. Any such UnitBoxes (typically from
* PhiExpr) contain a Unit that indicates the end of a CFG block.
*
* @return a list of all the UnitBoxes held by this body's
* branching units.
*
* @see UnitBox
* @see #getAllUnitBoxes()
* @see Unit#getUnitBoxes()
* @see soot.shimple.PhiExpr#getUnitBoxes()
**/
public List getUnitBoxes(boolean branchTarget)
{
ArrayList unitBoxList = new ArrayList();
{
Iterator it = unitChain.iterator();
while(it.hasNext()) {
Unit item = it.next();
if(branchTarget){
if(item.branches())
unitBoxList.addAll(item.getUnitBoxes());
}
else{
if(!item.branches())
unitBoxList.addAll(item.getUnitBoxes());
}
}
}
{
Iterator it = trapChain.iterator();
while(it.hasNext()) {
Trap item = it.next();
unitBoxList.addAll(item.getUnitBoxes());
}
}
return unitBoxList;
}
/**
* Returns the result of iterating through all Units in this
* body and querying them for ValueBoxes used.
* All of the ValueBoxes found are then returned as a List.
*
* @return a list of all the ValueBoxes for the Values used this body's units.
*
* @see Value
* @see Unit#getUseBoxes
* @see ValueBox
* @see Value
*
*/
public List getUseBoxes()
{
ArrayList useBoxList = new ArrayList();
Iterator it = unitChain.iterator();
while(it.hasNext()) {
Unit item = it.next();
useBoxList.addAll(item.getUseBoxes());
}
return useBoxList;
}
/**
* Returns the result of iterating through all Units in this
* body and querying them for ValueBoxes defined.
* All of the ValueBoxes found are then returned as a List.
*
* @return a list of all the ValueBoxes for Values defined by this body's units.
*
* @see Value
* @see Unit#getDefBoxes
* @see ValueBox
* @see Value
*/
public List getDefBoxes()
{
ArrayList defBoxList = new ArrayList();
Iterator it = unitChain.iterator();
while(it.hasNext()) {
Unit item = it.next();
defBoxList.addAll(item.getDefBoxes());
}
return defBoxList;
}
/**
* Returns a list of boxes corresponding to Values
* either used or defined in any unit of this Body.
*
* @return a list of ValueBoxes for held by the body's Units.
*
* @see Value
* @see Unit#getUseAndDefBoxes
* @see ValueBox
* @see Value
*/
public List getUseAndDefBoxes()
{
ArrayList useAndDefBoxList = new ArrayList();
Iterator it = unitChain.iterator();
while(it.hasNext()) {
Unit item = it.next();
useAndDefBoxList.addAll(item.getUseBoxes());
useAndDefBoxList.addAll(item.getDefBoxes());
}
return useAndDefBoxList;
}
private void checkLocals() {
Chain locals=getLocals();
Iterator it=locals.iterator();
while(it.hasNext()) {
Local l=it.next();
if(l.getType() instanceof VoidType)
throw new RuntimeException("Local "+l+" in "+method+" defined with void type");
}
}
private void checkTypes() {
Chain units=getUnits();
Iterator it=units.iterator();
while(it.hasNext()) {
Unit stmt=(it.next());
InvokeExpr iexpr=null;
String errorSuffix=" at "+stmt+" in "+getMethod();
if(stmt instanceof DefinitionStmt) {
DefinitionStmt astmt=(DefinitionStmt) stmt;
if( !(astmt.getRightOp() instanceof CaughtExceptionRef ) ) {
Type leftType=Type.toMachineType(astmt.getLeftOp().getType());
Type rightType=Type.toMachineType(astmt.getRightOp().getType());
checkCopy(leftType,rightType,errorSuffix);
if(astmt.getRightOp() instanceof InvokeExpr)
iexpr=(InvokeExpr) (astmt.getRightOp());
}
}
if(stmt instanceof InvokeStmt) iexpr=((InvokeStmt) stmt).getInvokeExpr();
if(iexpr!=null) {
SootMethodRef called=iexpr.getMethodRef();
if(iexpr instanceof InstanceInvokeExpr) {
InstanceInvokeExpr iiexpr=(InstanceInvokeExpr) iexpr;
checkCopy(called.declaringClass().getType(),
iiexpr.getBase().getType(),
" in receiver of call"+errorSuffix);
}
if(called.parameterTypes().size() != iexpr.getArgCount())
throw new RuntimeException("Warning: Argument count doesn't match up with signature in call"+errorSuffix+" in "+getMethod());
else
for(int i=0;i units=getUnits();
ExceptionalUnitGraph g = new ExceptionalUnitGraph
(this, PedanticThrowAnalysis.v(), false);
// FIXME: Work around for bug in soot
Scene.v().releaseActiveHierarchy();
InitAnalysis analysis=new InitAnalysis(g);
Iterator it=units.iterator();
while(it.hasNext()) {
Unit s=(it.next());
FlowSet init=(FlowSet) analysis.getFlowBefore(s);
List uses=s.getUseBoxes();
Iterator usesIt=uses.iterator();
while(usesIt.hasNext()) {
Value v=((usesIt.next())).getValue();
if(v instanceof Local) {
Local l=(Local) v;
if(!init.contains(l))
throw new RuntimeException("Warning: Local variable "+l
+" not definitely defined at "+s
+" in "+method);
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
PrintWriter writerOut = new PrintWriter(new EscapedWriter(new OutputStreamWriter(streamOut)));
try {
Printer.v().printTo(this, writerOut);
} catch (RuntimeException e) {
e.printStackTrace(writerOut);
}
writerOut.flush();
writerOut.close();
return streamOut.toString();
}
}