soot.jimple.toolkits.base.JimpleConstructorFolder 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) 2006 Ondrej Lhotak
*
* 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.jimple.toolkits.base;
import soot.options.*;
import soot.*;
import soot.toolkits.scalar.*;
import soot.jimple.*;
import soot.toolkits.graph.*;
import soot.util.*;
import java.util.*;
public class JimpleConstructorFolder extends BodyTransformer
{
static boolean isNew(Stmt s) {
if(!(s instanceof AssignStmt)) return false;
if(!(rhs(s) instanceof NewExpr)) return false;
return true;
}
static boolean isConstructor(Stmt s) {
if(!(s instanceof InvokeStmt)) return false;
InvokeStmt is = (InvokeStmt) s;
InvokeExpr expr = is.getInvokeExpr();
if(!(expr instanceof SpecialInvokeExpr)) return false;
SpecialInvokeExpr sie = (SpecialInvokeExpr) expr;
if(!sie.getMethodRef().name().equals(SootMethod.constructorName))
return false;
return true;
}
static Local base(Stmt s) {
InvokeStmt is = (InvokeStmt) s;
InstanceInvokeExpr expr = (InstanceInvokeExpr) is.getInvokeExpr();
return (Local) expr.getBase();
}
static void setBase(Stmt s, Local l) {
InvokeStmt is = (InvokeStmt) s;
InstanceInvokeExpr expr = (InstanceInvokeExpr) is.getInvokeExpr();
expr.getBaseBox().setValue(l);
}
static boolean isCopy(Stmt s) {
if(!(s instanceof AssignStmt)) return false;
if(!(rhs(s) instanceof Local)) return false;
if(!(lhs(s) instanceof Local)) return false;
return true;
}
static Value rhs(Stmt s) {
AssignStmt as = (AssignStmt) s;
return as.getRightOp();
}
static Value lhs(Stmt s) {
AssignStmt as = (AssignStmt) s;
return as.getLeftOp();
}
static Local rhsLocal(Stmt s) { return (Local) rhs(s); }
static Local lhsLocal(Stmt s) { return (Local) lhs(s); }
private class Fact {
private Map varToStmt = new HashMap();
private MultiMap stmtToVar = new HashMultiMap();
private Stmt alloc = null;
public void add(Local l, Stmt s) {
varToStmt.put(l, s);
stmtToVar.put(s, l);
}
public Stmt get(Local l) {
return varToStmt.get(l);
}
public Set get(Stmt s) {
return stmtToVar.get(s);
}
public void removeAll(Stmt s) {
for(Iterator it = stmtToVar.get(s).iterator(); it.hasNext();) {
final Local var = (Local) it.next();
varToStmt.remove(var);
}
stmtToVar.remove(s);
}
public void copyFrom(Fact in) {
varToStmt = new HashMap(in.varToStmt);
stmtToVar = new HashMultiMap(in.stmtToVar);
alloc = in.alloc;
}
public void mergeFrom(Fact in1, Fact in2) {
varToStmt = new HashMap();
Iterator it = in1.varToStmt.keySet().iterator();
while(it.hasNext()) {
Local l = it.next();
Stmt newStmt = in1.varToStmt.get(l);
if(in2.varToStmt.containsKey(l)) {
Stmt newStmt2 = in2.varToStmt.get(l);
if(!newStmt.equals(newStmt2)) {
throw new RuntimeException("Merge of different uninitialized values; are you sure this bytecode is verifiable?");
}
}
add(l, newStmt);
}
it = in2.varToStmt.keySet().iterator();
while(it.hasNext()) {
Local l = it.next();
Stmt newStmt = in2.varToStmt.get(l);
add(l, newStmt);
}
if(in1.alloc != null && in1.alloc.equals(in2.alloc)) {
alloc = in1.alloc;
} else {
alloc = null;
}
}
public boolean equals(Object other) {
if(!(other instanceof Fact)) return false;
Fact o = (Fact) other;
if(!stmtToVar.equals(o.stmtToVar)) return false;
if(alloc == null && o.alloc != null) return false;
if(alloc != null && o.alloc == null) return false;
if(alloc != null && !alloc.equals(o.alloc)) return false;
return true;
}
public Stmt alloc() { return alloc; }
public void setAlloc(Stmt newAlloc) { alloc = newAlloc; }
}
private class Analysis extends ForwardFlowAnalysis {
public Analysis(DirectedGraph graph) {
super(graph);
doAnalysis();
}
protected Object entryInitialFlow() {
return new Fact();
}
protected Object newInitialFlow() {
return new Fact();
}
public void flowThrough(Object inFact, Object unit, Object outFact) {
Stmt s = (Stmt) unit;
Fact in = (Fact) inFact;
Fact out = (Fact) outFact;
copy(in, out);
out.setAlloc(null);
if(isNew(s)) {
out.add(lhsLocal(s), s);
} else if(isCopy(s)) {
Stmt newStmt = out.get(rhsLocal(s));
if(newStmt != null) out.add(lhsLocal(s), newStmt);
} else if(isConstructor(s)) {
Stmt newStmt = out.get(base(s));
if(newStmt != null) {
out.removeAll(newStmt);
out.setAlloc(newStmt);
}
}
}
public void copy(Object source, Object dest) {
((Fact) dest).copyFrom((Fact) source);
}
public void merge(Object in1, Object in2, Object out) {
((Fact) out).mergeFrom((Fact) in1, (Fact) in2);
}
}
/** This method pushes all newExpr down to be the stmt directly before every
* invoke of the init */
public void internalTransform(Body b, String phaseName, Map options)
{
JimpleBody body = (JimpleBody)b;
//PhaseDumper.v().dumpBody(body, "constructorfolder.in");
if(Options.v().verbose())
G.v().out.println("[" + body.getMethod().getName() +
"] Folding Jimple constructors...");
Analysis analysis = new Analysis(new BriefUnitGraph(body));
Chain units = body.getUnits();
List stmtList = new ArrayList();
stmtList.addAll(units);
Iterator it;
it = stmtList.iterator();
while(it.hasNext()) {
Stmt s = (Stmt) it.next();
if(isCopy(s)) continue;
if(isConstructor(s)) continue;
Fact before = (Fact) analysis.getFlowBefore(s);
Iterator usesIt = s.getUseBoxes().iterator();
while(usesIt.hasNext()) {
ValueBox usebox = (ValueBox) usesIt.next();
Value value = usebox.getValue();
if(!(value instanceof Local)) continue;
Local local = (Local) value;
if(before.get(local) != null)
throw new RuntimeException("Use of an unitialized value "
+"before constructor call; are you sure this "
+"bytecode is verifiable?\n"+s);
}
}
// throw out all new statements
it = stmtList.iterator();
while(it.hasNext()) {
Stmt s = (Stmt) it.next();
if(isNew(s)) {
units.remove(s);
}
}
it = stmtList.iterator();
while(it.hasNext()) {
Stmt s = (Stmt) it.next();
Fact before = (Fact) analysis.getFlowBefore(s);
Fact after = (Fact) analysis.getFlowAfter(s);
// throw out copies of uninitialized variables
if(isCopy(s)) {
Stmt newStmt = before.get(rhsLocal(s));
if(newStmt != null) units.remove(s);
} else if(after.alloc() != null) {
// insert the new just before the constructor
Stmt newStmt = before.get(base(s));
setBase(s, lhsLocal(newStmt));
units.insertBefore(newStmt, s);
// add necessary copies
Iterator copyIt = before.get(newStmt).iterator();
while(copyIt.hasNext()) {
Local l = (Local) copyIt.next();
if(l.equals(base(s))) continue;
units.insertAfter(Jimple.v().newAssignStmt(l, base(s)), s);
}
}
}
//PhaseDumper.v().dumpBody(body, "constructorfolder.out");
}
}