/* Soot - a J*va Optimization Framework * Copyright (C) 2002 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.spark.pag; import java.util.*; import soot.*; import soot.jimple.spark.sets.*; import java.io.*; import soot.jimple.spark.solver.TopoSorter; import soot.jimple.spark.sets.PointsToSetInternal; /** Dumps a pointer assignment graph to a file. * @author Ondrej Lhotak */ public class PAGDumper { public PAGDumper( PAG pag , String output_dir ) { this.pag = pag; this.output_dir = output_dir; } public void dumpPointsToSets() { try { final PrintWriter file = new PrintWriter( new FileOutputStream( new File(output_dir, "solution") ) ); file.println( "Solution:" ); for( Iterator vnIt = pag.getVarNodeNumberer().iterator(); vnIt.hasNext(); ) { final VarNode vn = (VarNode) vnIt.next(); if( vn.getReplacement() != vn ) { continue; } PointsToSetInternal p2set = vn.getP2Set(); if( p2set == null ) continue; p2set.forall( new P2SetVisitor() { public final void visit( Node n ) { try { dumpNode( vn, file ); file.print( " " ); dumpNode( n, file ); file.println( "" ); } catch( IOException e ) { throw new RuntimeException( "Couldn't dump solution."+e ); } } } ); } file.close(); } catch( IOException e ) { throw new RuntimeException( "Couldn't dump solution."+e ); } } public void dump() { try { PrintWriter file = new PrintWriter( new FileOutputStream( new File(output_dir, "pag") ) ); if( pag.getOpts().topo_sort() ) { new TopoSorter( pag, false ).sort(); } file.println( "Allocations:" ); for (Object object : pag.allocSources()) { final AllocNode n = (AllocNode) object; if( n.getReplacement() != n ) continue; Node[] succs = pag.allocLookup( n ); for (Node element0 : succs) { dumpNode( n, file ); file.print( " "); dumpNode( element0, file ); file.println( ""); } } file.println( "Assignments:" ); for (Object object : pag.simpleSources()) { final VarNode n = (VarNode) object; if( n.getReplacement() != n ) continue; Node[] succs = pag.simpleLookup( n ); for (Node element0 : succs) { dumpNode( n, file ); file.print( " "); dumpNode( element0, file ); file.println( ""); } } file.println( "Loads:" ); for (Object object : pag.loadSources()) { final FieldRefNode n = (FieldRefNode) object; Node[] succs = pag.loadLookup( n ); for (Node element0 : succs) { dumpNode( n, file ); file.print( " "); dumpNode( element0, file ); file.println( ""); } } file.println( "Stores:" ); for (Object object : pag.storeSources()) { final VarNode n = (VarNode) object; if( n.getReplacement() != n ) continue; Node[] succs = pag.storeLookup( n ); for (Node element0 : succs) { dumpNode( n, file ); file.print( " "); dumpNode( element0, file ); file.println( ""); } } if( pag.getOpts().dump_types() ) { dumpTypes( file ); } file.close(); } catch( IOException e ) { throw new RuntimeException( "Couldn't dump PAG."+e ); } } /* End of public methods. */ /* End of package methods. */ protected PAG pag; protected String output_dir; protected int fieldNum = 0; protected HashMap<SparkField, Integer> fieldMap = new HashMap<SparkField, Integer>(); protected ObjectNumberer root = new ObjectNumberer( null, 0 ); protected void dumpTypes( PrintWriter file ) throws IOException { HashSet<Type> declaredTypes = new HashSet<Type>(); HashSet<Type> actualTypes = new HashSet<Type>(); HashSet<SparkField> allFields = new HashSet<SparkField>(); for( Iterator nIt = pag.getVarNodeNumberer().iterator(); nIt.hasNext(); ) { final Node n = (Node) nIt.next(); Type t = n.getType(); if( t != null ) declaredTypes.add( t ); } for (Object object : pag.loadSources()) { final Node n = (Node) object; if( n.getReplacement() != n ) continue; Type t = n.getType(); if( t != null ) declaredTypes.add( t ); allFields.add( ((FieldRefNode) n ).getField() ); } for (Object object : pag.storeInvSources()) { final Node n = (Node) object; if( n.getReplacement() != n ) continue; Type t = n.getType(); if( t != null ) declaredTypes.add( t ); allFields.add( ((FieldRefNode) n ).getField() ); } for (Object object : pag.allocSources()) { final Node n = (Node) object; if( n.getReplacement() != n ) continue; Type t = n.getType(); if( t != null ) actualTypes.add( t ); } HashMap<Type, Integer> typeToInt = new HashMap<Type, Integer>(); int nextint = 1; for (Type type : declaredTypes) { typeToInt.put( type, new Integer( nextint++ ) ); } for (Type t : actualTypes) { if( !typeToInt.containsKey( t ) ) { typeToInt.put( t, new Integer( nextint++ ) ); } } file.println( "Declared Types:" ); for (Type declType : declaredTypes) { for (Type actType : actualTypes) { if( pag.getTypeManager().castNeverFails( actType, declType ) ) { file.println( ""+typeToInt.get( declType )+" "+typeToInt.get( actType ) ); } } } file.println( "Allocation Types:" ); for (Object object : pag.allocSources()) { final Node n = (Node) object; if( n.getReplacement() != n ) continue; Type t = n.getType(); dumpNode( n, file ); if( t == null ) { throw new RuntimeException( "allocnode with null type" ); //file.println( " 0" ); } else { file.println( " "+typeToInt.get( t ) ); } } file.println( "Variable Types:" ); for( Iterator nIt = pag.getVarNodeNumberer().iterator(); nIt.hasNext(); ) { final Node n = (Node) nIt.next(); if( n.getReplacement() != n ) continue; Type t = n.getType(); dumpNode( n, file ); if( t == null ) { file.println( " 0" ); } else { file.println( " "+typeToInt.get( t ) ); } } } protected int fieldToNum( SparkField f ) { Integer ret = fieldMap.get( f ); if( ret == null ) { ret = new Integer( ++ fieldNum ); fieldMap.put( f, ret ); } return ret.intValue(); } protected void dumpNode( Node n, PrintWriter out ) throws IOException { if( n.getReplacement() != n ) throw new RuntimeException( "Attempt to dump collapsed node." ); if( n instanceof FieldRefNode ) { FieldRefNode fn = (FieldRefNode) n; dumpNode( fn.getBase(), out ); out.print( " "+fieldToNum( fn.getField() ) ); } else if( pag.getOpts().class_method_var() && n instanceof VarNode ) { VarNode vn = (VarNode) n; SootMethod m = null; if( vn instanceof LocalVarNode ) { m = ((LocalVarNode)vn).getMethod(); } SootClass c = null; if( m != null ) c = m.getDeclaringClass(); ObjectNumberer cl = root.findOrAdd( c ); ObjectNumberer me = cl.findOrAdd( m ); ObjectNumberer vr = me.findOrAdd( vn ); /* if( vr.num > 256 ) { G.v().out.println( "Var with num: "+vr.num+" is "+vn+ " in method "+m+" in class "+c ); } */ out.print( ""+cl.num+" "+me.num+" "+vr.num ); } else if( pag.getOpts().topo_sort() && n instanceof VarNode ) { out.print( ""+((VarNode) n).finishingNumber ); } else { out.print( ""+n.getNumber() ); } } class ObjectNumberer { Object o = null; int num = 0; int nextChildNum = 1; HashMap<Object, ObjectNumberer> children = null; ObjectNumberer( Object o, int num ) { this.o = o; this.num = num; } ObjectNumberer findOrAdd( Object child ) { if( children == null ) children = new HashMap<Object, ObjectNumberer>(); ObjectNumberer ret = children.get( child ); if( ret == null ) { ret = new ObjectNumberer( child, nextChildNum++ ); children.put( child, ret ); } return ret; } } }