/* Soot - a J*va Optimization Framework * Copyright (C) 2003 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. */ package soot.jimple.toolkits.pointer; import soot.*; import java.util.*; import soot.jimple.toolkits.callgraph.*; import soot.jimple.*; public class SideEffectTagger extends BodyTransformer { public SideEffectTagger( Singletons.Global g ) {} public static SideEffectTagger v() { return G.v().soot_jimple_toolkits_pointer_SideEffectTagger(); } public int numRWs = 0; public int numWRs = 0; public int numRRs = 0; public int numWWs = 0; public int numNatives = 0; public Date startTime = null; boolean optionNaive = false; private CallGraph cg; protected class UniqueRWSets { protected ArrayList<RWSet> l = new ArrayList<RWSet>(); RWSet getUnique( RWSet s ) { if( s == null ) return s; for (RWSet ret : l) { if( ret.isEquivTo( s ) ) return ret; } l.add( s ); return s; } Iterator<RWSet> iterator() { return l.iterator(); } short indexOf( RWSet s ) { short i = 0; for (RWSet ret : l) { if( ret.isEquivTo( s ) ) return i; i++; } return -1; } } protected void initializationStuff( String phaseName ) { G.v().Union_factory = new UnionFactory() { //ReallyCheapRasUnion ru = new ReallyCheapRasUnion(); //public Union newUnion() { return new RasUnion(); } public Union newUnion() { return new MemoryEfficientRasUnion(); } }; if( startTime == null ) { startTime = new Date(); } cg = Scene.v().getCallGraph(); } protected Object keyFor( Stmt s ) { if( s.containsInvokeExpr() ) { if( optionNaive ) throw new RuntimeException( "shouldn't get here" ); Iterator it = cg.edgesOutOf( s ); if( !it.hasNext() ) { return Collections.EMPTY_LIST; } ArrayList ret = new ArrayList(); while( it.hasNext() ) { ret.add( it.next() ); } return ret; } else { return s; } } protected void internalTransform(Body body, String phaseName, Map options) { initializationStuff( phaseName ); SideEffectAnalysis sea = Scene.v().getSideEffectAnalysis(); optionNaive = PhaseOptions.getBoolean( options, "naive" ); if( !optionNaive ) { sea.findNTRWSets( body.getMethod() ); } HashMap<Object, RWSet> stmtToReadSet = new HashMap<Object, RWSet>(); HashMap<Object, RWSet> stmtToWriteSet = new HashMap<Object, RWSet>(); UniqueRWSets sets = new UniqueRWSets(); boolean justDoTotallyConservativeThing = body.getMethod().getName().equals( "<clinit>" ); for( Iterator stmtIt = body.getUnits().iterator(); stmtIt.hasNext(); ) { final Stmt stmt = (Stmt) stmtIt.next(); if( justDoTotallyConservativeThing || ( optionNaive && stmt.containsInvokeExpr() ) ) { stmtToReadSet.put( stmt, sets.getUnique( new FullRWSet() ) ); stmtToWriteSet.put( stmt, sets.getUnique( new FullRWSet() ) ); continue; } Object key = keyFor( stmt ); if( !stmtToReadSet.containsKey( key ) ) { stmtToReadSet.put( key, sets.getUnique( sea.readSet( body.getMethod(), stmt ) ) ); stmtToWriteSet.put( key, sets.getUnique( sea.writeSet( body.getMethod(), stmt ) ) ); } } DependenceGraph graph = new DependenceGraph(); for( Iterator<RWSet> outerIt = sets.iterator(); outerIt.hasNext(); ) { final RWSet outer = outerIt.next(); for( Iterator<RWSet> innerIt = sets.iterator(); innerIt.hasNext(); ) { final RWSet inner = innerIt.next(); if( inner == outer ) break; if( outer.hasNonEmptyIntersection( inner ) ) { //G.v().out.println( "inner set is: "+inner ); //G.v().out.println( "outer set is: "+outer ); graph.addEdge( sets.indexOf( outer ), sets.indexOf( inner ) ); } } } body.getMethod().addTag( graph ); for( Iterator stmtIt = body.getUnits().iterator(); stmtIt.hasNext(); ) { final Stmt stmt = (Stmt) stmtIt.next(); Object key; if( optionNaive && stmt.containsInvokeExpr() ) { key = stmt; } else { key = keyFor( stmt ); } RWSet read = stmtToReadSet.get( key ); RWSet write = stmtToWriteSet.get( key ); if( read != null || write != null ) { DependenceTag tag = new DependenceTag(); if( read != null && read.getCallsNative() ) { tag.setCallsNative(); numNatives++; } else if( write != null && write.getCallsNative() ) { tag.setCallsNative(); numNatives++; } tag.setRead( sets.indexOf( read ) ); tag.setWrite( sets.indexOf( write ) ); stmt.addTag( tag ); // The loop below is just for calculating stats. /* if( !justDoTotallyConservativeThing ) { for( Iterator innerIt = body.getUnits().iterator(); innerIt.hasNext(); ) { final Stmt inner = (Stmt) innerIt.next(); Object ikey; if( optionNaive && inner.containsInvokeExpr() ) { ikey = inner; } else { ikey = keyFor( inner ); } RWSet innerRead = (RWSet) stmtToReadSet.get( ikey ); RWSet innerWrite = (RWSet) stmtToWriteSet.get( ikey ); if( graph.areAdjacent( sets.indexOf( read ), sets.indexOf( innerWrite ) ) ) numRWs++; if( graph.areAdjacent( sets.indexOf( write ), sets.indexOf( innerRead ) ) ) numWRs++; if( inner == stmt ) continue; if( graph.areAdjacent( sets.indexOf( write ), sets.indexOf( innerWrite ) ) ) numWWs++; if( graph.areAdjacent( sets.indexOf( read ), sets.indexOf( innerRead ) ) ) numRRs++; } } */ } } } }