/* Soot - a J*va Optimization Framework * Copyright (C) 1999 Patrick Lam, Raja Vallee-Rai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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-2003. * See the 'credits' file distributed with Soot for the complete list of * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot) */ /* Reference Version: $SootVersion: 1.2.3.dev.4 $ */ package ptolemy.copernicus.kernel; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import soot.Local; import soot.Scene; import soot.SceneTransformer; import soot.SootClass; import soot.SootMethod; import soot.ValueBox; import soot.jimple.InstanceInvokeExpr; import soot.jimple.InvokeExpr; import soot.jimple.Jimple; import soot.jimple.JimpleBody; import soot.jimple.SpecialInvokeExpr; import soot.jimple.StaticInvokeExpr; import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Filter; import soot.jimple.toolkits.callgraph.InstanceInvokeEdgesPred; import soot.jimple.toolkits.callgraph.Targets; import soot.jimple.toolkits.invoke.AccessManager; /** Uses the Scene's currently-active InvokeGraph to statically bind monomorphic call sites. */ public class InvocationBinder extends SceneTransformer { private static InvocationBinder instance = new InvocationBinder(); private InvocationBinder() { } public static InvocationBinder v() { return instance; } public String getDefaultOptions() { return "insert-null-checks insert-redundant-casts allowed-modifier-changes:unsafe VTA-passes:0"; } public String getDeclaredOptions() { return "insert-null-checks insert-redundant-casts allowed-modifier-changes VTA-passes"; } protected void internalTransform(String phaseName, Map options) { System.out.println("InvocationBinder.internalTransform(" + phaseName + ", " + options + ")"); Filter instanceInvokesFilter = new Filter(new InstanceInvokeEdgesPred()); String modifierOptions = "unsafe"; //HashMap instanceToStaticMap = new HashMap(); Scene.v().setCallGraph(new CallGraph()); CallGraph cg = Scene.v().getCallGraph(); Iterator classesIt = Scene.v().getApplicationClasses().iterator(); while (classesIt.hasNext()) { SootClass c = (SootClass) classesIt.next(); LinkedList methodsList = new LinkedList(); methodsList.addAll(c.getMethods()); while (!methodsList.isEmpty()) { SootMethod container = (SootMethod) methodsList.removeFirst(); if (!container.isConcrete()) { // System.out.println("skipping " + container + ": not concrete"); continue; } if (!instanceInvokesFilter.wrap(cg.edgesOutOf(container)) .hasNext()) { continue; } JimpleBody b = (JimpleBody) container.getActiveBody(); List unitList = new ArrayList(); unitList.addAll(b.getUnits()); Iterator unitIt = unitList.iterator(); while (unitIt.hasNext()) { Stmt s = (Stmt) unitIt.next(); if (!s.containsInvokeExpr()) { continue; } InvokeExpr ie = s.getInvokeExpr(); if (ie instanceof StaticInvokeExpr || ie instanceof SpecialInvokeExpr) { // System.out.println("skipping " + container + ":" + // s + ": not virtual"); continue; } Iterator targets = new Targets(cg.edgesOutOf(s)); if (!targets.hasNext()) { continue; } SootMethod target = (SootMethod) targets.next(); if (targets.hasNext()) { continue; } // Ok, we have an Interface or VirtualInvoke going to 1. if (!AccessManager.ensureAccess(container, target, modifierOptions)) { // System.out.println("skipping: no access"); continue; } if (!target.isConcrete()) { // System.out.println("skipping: not concrete"); continue; } // HACK! because the callgraph seems to be // incorrect in soot 2.0.1 if (!Scene.v().getApplicationClasses().contains( target.getDeclaringClass())) { continue; } // Change the InterfaceInvoke or VirtualInvoke to // a new VirtualInvoke. ValueBox box = s.getInvokeExprBox(); box.setValue(Jimple.v().newVirtualInvokeExpr( (Local) ((InstanceInvokeExpr) ie).getBase(), target.makeRef(), ie.getArgs())); } } } } }