[Soot-list] Help (fwd)

Rahul Nagpal rahul at csa.iisc.ernet.in
Wed May 25 14:03:23 EDT 2005


Hi Ondroz,

	Thanks for pointing out that. Though I set the flag to true and
recompiled the G.java file containing the flag. I did not recompiled the
javafiles that uses the flag. After doing that change I got the error[1]
that I could get rid of by commenting out these two lines (Thought I don't
know what can be the possible sideeffect of doing this)

239:resolveClassErrorSet.add(AnySubType.v(Scene.v().getRefType("java.lang.ClassFormatError")));
263:initializationErrorSet.add(AnySubType.v(Scene.v().getRefType("java.lang.Error")));

in file "soot/toolkits/exceptions/ThrowableSet.java". Now I  am successful
in using soot directly with the J2ME library along with  -w
flag to create the callgraph for HelloWorld Program at least.

		I am also able to use the ptolemy interfaced with
soot if I bypass the callgraph creation. However if I create the callgraph
from ptolemy which creats the call graph with some specific options and
some default starting points I get one of the old error[2]. I am looking
at the  matter at present. I am attaching a java source file from ptolemy
that call the soot functions for creating the call graph.
I will be  thankful if you can give me some hint on what might be
the cause of this problem.

Thanks a lot
Rahul

[1]Exception in thread "main" java.lang.NullPointerException
        at soot.AnySubType.v(AnySubType.java:44)
        at soot.toolkits.exceptions.ThrowableSet$Manager.<init>(ThrowableSet.java:263)
        at soot.Singletons.soot_toolkits_exceptions_ThrowableSet_Manager(Singletons.java:1005)
        at soot.toolkits.exceptions.ThrowableSet$Manager.v(ThrowableSet.java:274)
        at soot.toolkits.exceptions.PedanticThrowAnalysis.mightThrow(PedanticThrowAnalysis.java:68)
        at soot.toolkits.graph.ExceptionalUnitGraph.getExceptionDests(ExceptionalUnitGraph.java:803)
        at soot.toolkits.graph.ExceptionalUnitGraph.buildHeadsAndTails(ExceptionalUnitGraph.java:766)
        at soot.toolkits.graph.ExceptionalUnitGraph.initialize(ExceptionalUnitGraph.java:283)
        at soot.toolkits.graph.ExceptionalUnitGraph.<init>(ExceptionalUnitGraph.java:148)
        at soot.toolkits.graph.ExceptionalUnitGraph.<init>(ExceptionalUnitGraph.java:180)
        at soot.toolkits.scalar.LocalSplitter.internalTransform(LocalSplitter.java:78)
        at soot.BodyTransformer.transform(BodyTransformer.java:51)
        at soot.Transform.apply(Transform.java:104)
        at soot.JimpleBodyPack.applyPhaseOptions(JimpleBodyPack.java:61)
        at soot.JimpleBodyPack.internalApply(JimpleBodyPack.java:93)
        at soot.Pack.apply(Pack.java:120)
        at soot.coffi.CoffiMethodSource.getBody(CoffiMethodSource.java:115)
        at soot.SootMethod.getBodyFromMethodSource(SootMethod.java:80)
        at soot.SootMethod.retrieveActiveBody(SootMethod.java:304)
        at ptolemy.copernicus.c.MethodCodeGenerator.generate(MethodCodeGenerator.java:76)
        at ptolemy.copernicus.c.CodeFileGenerator.generate(CodeFileGenerator.java:146)
        at ptolemy.copernicus.c.RequiredFileGenerator._generateC(RequiredFileGenerator.java:282)
        at ptolemy.copernicus.c.RequiredFileGenerator.generateTransitiveClosureOf(RequiredFileGenerator.java:94)
        at ptolemy.copernicus.c.JavaToC.convert(JavaToC.java:119)
        at ptolemy.copernicus.c.JavaToC.main(JavaToC.java:186)

[2]
Exception in thread "main"
soot.AbstractSootMethodRef$ClassResolutionFailedException: Class
com.sun.cldc.io.ConsoleOutputStream doesn't have method <init>([]) : void;
failed to resolve in superclasses and interfacesLooking in
com.sun.cldc.io.ConsoleOutputStream which has methods []

        at soot.AbstractSootMethodRef.resolve(AbstractSootMethodRef.java:136)
        at soot.AbstractSootMethodRef.resolve(AbstractSootMethodRef.java:95)
        at soot.jimple.internal.AbstractInvokeExpr.getMethod(AbstractInvokeExpr.java:55)
        at soot.jimple.toolkits.callgraph.OnFlyCallGraphBuilder.getImplicitTargets(OnFlyCallGraphBuilder.java:235)
        at soot.jimple.toolkits.callgraph.OnFlyCallGraphBuilder.processNewMethod(OnFlyCallGraphBuilder.java:183)
        at soot.jimple.toolkits.callgraph.OnFlyCallGraphBuilder.processReachables(OnFlyCallGraphBuilder.java:81)
        at soot.jimple.spark.solver.OnFlyCallGraph.build(OnFlyCallGraph.java:69)
        at soot.jimple.spark.builder.ContextInsensitiveBuilder.build(ContextInsensitiveBuilder.java:78)
        at soot.jimple.spark.SparkTransformer.internalTransform(SparkTransformer.java:53)
        at soot.SceneTransformer.transform(SceneTransformer.java:39)
        at ptolemy.copernicus.c.CallGraphPruner.<init>(CallGraphPruner.java:109)
        at ptolemy.copernicus.c.RequiredFileGenerator._pruneLevel1(RequiredFileGenerator.java:243)
        at ptolemy.copernicus.c.RequiredFileGenerator.init(RequiredFileGenerator.java:152)
        at ptolemy.copernicus.c.JavaToC.convert(JavaToC.java:89)
        at ptolemy.copernicus.c.JavaToC.main(JavaToC.java:186)

On Tue, 24 May
2005, Ondrej Lhotak wrote:

-->On Tue, May 24, 2005 at 12:39:53AM +0530, Rahul Nagpal wrote:
-->> Hi,
-->> 	I hope you have received my last mail (in case not the details are
-->> given below) where I have given the exception raised by soot if I use
-->> j2me class directly with soot.
-->
-->Our whole lab was down for the past several days for hardware upgrades.
-->Everything seems to be back now, and hopefully people are receiving your
-->message.
-->
-->> 	I will be thankful if you can help (or redirect) me in this
-->> regard. I am  ready to make whatever modification are required to get the
-->> soot working with j2me ( I will myself takeup the ptolmy inteface part later once I get
-->> the soot working with j2me classes). But because of my inexperience with
-->> soot I am not able to find the cause of these problems.
-->
-->J2ME has somewhat different semantics than J2SE, and Soot is built with
-->J2SE in mind. So, getting it to work with J2ME may require some
-->tinkering. Unfortunately, I don't know of anyone with experience getting
-->Soot to work with J2ME that I could direct you to.
-->
-->I've walked through your stack trace for you, and noticed the following
-->line:
-->at soot.jimple.toolkits.typing.ClassHierarchy.<init>(ClassHierarchy.java:82)
-->
-->The code at this point is:
-->    79      // hack for J2ME library which does not have Cloneable and Serializable
-->    80      // reported by Stephen Chen
-->    81      if (!G.v().isJ2ME) {
-->    82        CLONEABLE = typeNode(RefType.v("java.lang.Cloneable"));
-->    83        SERIALIZABLE = typeNode(RefType.v("java.io.Serializable"));
-->    84      } else {
-->    85        CLONEABLE = null;
-->    86        SERIALIZABLE = null;
-->    87      }
-->
-->If you have isJ2ME set to true, line 82 (and 83) should never be getting
-->executed.
-->
-->Ondrej
-->
-->>
-->> Thanks and Regards
-->> Rahul
-->>
-->> On Thu, 19 May 2005, Rahul Nagpal wrote:
-->>
-->> -->Hi,
-->> -->	I think you are right. I should have first checked on the
-->> -->application  directly. Now I have done that I got this error[1]
-->> -->if I use J2ME classes  ( I am doing "java soot.Main -cp <the j2me class path>)
-->> -->irrespective of whether I use -w option or not.
-->> -->
-->> -->	Notably the ptolemy is working fine with soot when I use the
-->> -->J2SE classes and only the use of J2ME classes causes the problem.
-->> -->
-->> -->Thanks and Regards
-->> -->Rahul
-->> -->
-->> -->[1]
-->> -->Exception in thread "main" java.lang.RuntimeException: This operation
-->> -->requires resolving level HIERARCHY but java.lang.Cloneable is at resolving
-->> -->level DANGLING
-->> -->        at soot.SootClass.checkLevel(SootClass.java:123)
-->> -->        at soot.SootClass.hasSuperclass(SootClass.java:702)
-->> -->        at soot.jimple.toolkits.typing.TypeNode.<init>(TypeNode.java:86)
-->> -->        at soot.jimple.toolkits.typing.ClassHierarchy$ConstructorChooser.caseRefType(ClassHierarchy.java:238)
-->> -->        at soot.RefType.apply(RefType.java:137)
-->> -->        at soot.jimple.toolkits.typing.ClassHierarchy$ConstructorChooser.typeNode(ClassHierarchy.java:231)
-->> -->        at soot.jimple.toolkits.typing.ClassHierarchy.typeNode(ClassHierarchy.java:127)
-->> -->        at soot.jimple.toolkits.typing.ClassHierarchy.classHierarchy(ClassHierarchy.java:105)
-->> -->        at soot.jimple.toolkits.typing.TypeResolver.<init>(TypeResolver.java:153)
-->> -->        at soot.jimple.toolkits.typing.TypeResolver.resolve(TypeResolver.java:178)
-->> -->        at soot.jimple.toolkits.typing.TypeAssigner.internalTransform(TypeAssigner.java:57)
-->> -->        at soot.BodyTransformer.transform(BodyTransformer.java:51)
-->> -->        at soot.Transform.apply(Transform.java:104)
-->> -->        at soot.JimpleBodyPack.applyPhaseOptions(JimpleBodyPack.java:70)
-->> -->        at soot.JimpleBodyPack.internalApply(JimpleBodyPack.java:93)
-->> -->        at soot.Pack.apply(Pack.java:120)
-->> -->        at soot.coffi.CoffiMethodSource.getBody(CoffiMethodSource.java:115)
-->> -->        at soot.SootMethod.getBodyFromMethodSource(SootMethod.java:80)
-->> -->        at soot.SootMethod.retrieveActiveBody(SootMethod.java:304)
-->> -->        at soot.PackManager.retrieveAllBodies(PackManager.java:711)
-->> -->        at soot.PackManager.runPacks(PackManager.java:302)
-->> -->        at soot.Main.run(Main.java:179)
-->> -->        at soot.Main.main(Main.java:153)
-->> -->
-->> -->
-->> -->On Wed, 18 May 2005, Ondrej Lhotak wrote:
-->> -->
-->> -->-->On Tue, May 17, 2005 at 01:56:33AM +0530, Rahul Nagpal wrote:
-->> -->-->> [1]
-->> -->-->> Exception in thread "main"
-->> -->-->> soot.AbstractSootMethodRef$ClassResolutionFailedException: Class
-->> -->-->> com.sun.cldc.io.ConsoleOutputStream doesn't have method <init>([]) : void;
-->> -->-->> failed to resolve in superclasses and interfacesLooking in
-->> -->-->> com.sun.cldc.io.ConsoleOutputStream which has methods []
-->> -->-->> 	at soot.AbstractSootMethodRef.resolve(AbstractSootMethodRef.java:136)
-->> -->-->
-->> -->-->....
-->> -->-->
-->> -->-->>         at ptolemy.copernicus.c.CallGraphPruner.<init>(CallGraphPruner.java:109)
-->> -->-->>         at ptolemy.copernicus.c.RequiredFileGenerator._pruneLevel1(RequiredFileGenerator.java:243)
-->> -->-->>         at ptolemy.copernicus.c.RequiredFileGenerator.init(RequiredFileGenerator.java:152)
-->> -->-->>         at ptolemy.copernicus.c.JavaToC.convert(JavaToC.java:89)
-->> -->-->>         at ptolemy.copernicus.c.JavaToC.main(JavaToC.java:186)
-->> -->-->
-->> -->-->Soot doesn't seem to have any methods in the class
-->> -->-->com.sun.cldc.io.ConsoleOutputStream, which suggests that the class was
-->> -->-->not resolved properly. It could be due to some interaction between
-->> -->-->Ptolemy and the Soot resolver. Does the same thing happen when you run
-->> -->-->Soot on your application, with the -w switch (to make it build a call
-->> -->-->graph)?
-->> -->-->
-->> -->-->> [2]Exception in thread "main" java.lang.NullPointerException
-->> -->-->>         at soot.AnySubType.v(AnySubType.java:44)
-->> -->-->>         at soot.toolkits.exceptions.ThrowableSet$Manager.<init>(ThrowableSet.java:239)
-->> -->-->>         at soot.Singletons.soot_toolkits_exceptions_ThrowableSet_Manager(Singletons.java:1005)
-->> -->-->>         at soot.toolkits.exceptions.ThrowableSet$Manager.v(ThrowableSet.java:274)
-->> -->-->
-->> -->-->...
-->> -->-->
-->> -->-->>         at ptolemy.copernicus.c.MethodCodeGenerator.generate(MethodCodeGenerator.java:76)
-->> -->-->>         at ptolemy.copernicus.c.CodeFileGenerator.generate(CodeFileGenerator.java:146)
-->> -->-->>         at ptolemy.copernicus.c.RequiredFileGenerator._generateC(RequiredFileGenerator.java:282)
-->> -->-->>         at ptolemy.copernicus.c.RequiredFileGenerator.generateTransitiveClosureOf(RequiredFileGenerator.java:94)
-->> -->-->>         at ptolemy.copernicus.c.JavaToC.convert(JavaToC.java:119)
-->> -->-->>         at ptolemy.copernicus.c.JavaToC.main(JavaToC.java:186)
-->> -->-->
-->> -->-->This suggests that the java.lang.ClassFormatError class is not getting
-->> -->-->loaded, even though the Scene sets it to be a basic class. Maybe Ptolemy
-->> -->-->is not running Scene.v().loadBasicClasses(). Again, does this problem
-->> -->-->happen when you run Soot on your application?
-->> -->-->
-->> -->-->Ondrej
-->> -->-->
-->> -->-->
-->> -->
-->> -->---------------------------------------------------------------------
-->> -->  __    __
-->> -->   / /\  / /\		RAHUL NAGPAL
-->> -->  / /_/_/ / /		Room No. U-77, IISc Hostels,
-->> --> /_______/ / /\
-->> --> \  ____ \ \/  \      	Phone Nos 080-2293-2634/2591 (Hostel)
-->> -->  \ \/__\ \  /\ \    	080-22932368/468-104 (Compiler Lab)
-->> -->   \_______\/ / / 	080-22932368-115 (CL1)
-->> -->    /_/ /  /_/ /    	080-22932368-102 (CL2)
-->> -->    \_\/   \_\/    	080-22932368-227 (Intel LAB)
-->> -->--------------------------------------------------------------------
-->> -->
-->>
-->> ---------------------------------------------------------------------
-->>   __    __
-->>    / /\  / /\		RAHUL NAGPAL
-->>   / /_/_/ / /		Room No. U-77, IISc Hostels,
-->>  /_______/ / /\
-->>  \  ____ \ \/  \      	Phone Nos 080-2293-2634/2591 (Hostel)
-->>   \ \/__\ \  /\ \    	080-22932368/468-104 (Compiler Lab)
-->>    \_______\/ / / 	080-22932368-115 (CL1)
-->>     /_/ /  /_/ /    	080-22932368-102 (CL2)
-->>     \_\/   \_\/    	080-22932368-227 (Intel LAB)
-->> --------------------------------------------------------------------
-->>
-->

---------------------------------------------------------------------
  __    __
   / /\  / /\		RAHUL NAGPAL
  / /_/_/ / /		Room No. U-77, IISc Hostels,
 /_______/ / /\
 \  ____ \ \/  \      	Phone Nos 080-2293-2634/2591 (Hostel)
  \ \/__\ \  /\ \    	080-22932368/468-104 (Compiler Lab)
   \_______\/ / / 	080-22932368-115 (CL1)
    /_/ /  /_/ /    	080-22932368-102 (CL2)
    \_\/   \_\/    	080-22932368-227 (Intel LAB)
--------------------------------------------------------------------
-------------- next part --------------
/* Class that uses the Soot Framework to find out which methods/classes
   are really needed for code generation.

   Copyright (c) 2003-2004 The University of Maryland.
   All rights reserved.
   Permission is hereby granted, without written agreement and without
   license or royalty fees, to use, copy, modify, and distribute this
   software and its documentation for any purpose, provided that the above
   copyright notice and the following two paragraphs appear in all copies
   of this software.

   IN NO EVENT SHALL THE UNIVERSITY OF MARYLAND BE LIABLE TO ANY PARTY
   FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
   ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
   THE UNIVERSITY OF MARYLAND HAS BEEN ADVISED OF THE POSSIBILITY OF
   SUCH DAMAGE.

   THE UNIVERSITY OF MARYLAND SPECIFICALLY DISCLAIMS ANY WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
   PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
   MARYLAND HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
   ENHANCEMENTS, OR MODIFICATIONS.

*/

package ptolemy.copernicus.c;


import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import soot.Hierarchy;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Trap;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.ValueBox;
import soot.jimple.FieldRef;
import soot.jimple.InstanceOfExpr;
import soot.jimple.InvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.spark.SparkTransformer;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.Edge;
import soot.options.SparkOptions;


//////////////////////////////////////////////////////////////////////////
//// CallGraphPruner
/**
   Class that uses the Soot Framework to find out which methods/classes
   are really needed for code generation.

   @author Ankush Varma
   @version $Id: CallGraphPruner.java,v 1.9 2004/04/16 22:38:08 shuvra Exp $
@since Ptolemy II 4.0
@Pt.ProposedRating Red (ankush)
@Pt.AcceptedRating Red (ssb)
*/

public class CallGraphPruner {

    /** Dummy constructor to allow inheritance.*/
    public CallGraphPruner() {
    }

    /** Constructor. Creates an CallGraph and applies a specialized
     * pruning strategy to it, tailored for C code generation.
     * @param source The class to use as the root for the pruned tree.
     */
    public CallGraphPruner(SootClass source) {
        Scene.v().setMainClass(source);

        Map sootOptions = new Hashtable();
        //sootOptions.put("vta", "true");
        sootOptions.put("on-fly-cg", "true");
        sootOptions.put("simulate-natives", "false");
        sootOptions.put("enabled", "true");
        sootOptions.put("verbose", "true");

        sootOptions.put("propagator", "worklist");
        sootOptions.put("set-impl", "double");
        sootOptions.put("double-set-old", "hybrid");
        sootOptions.put("double-set-new", "hybrid");
        //CHATransformer.v().transform("cg.cha", sootOptions);

        SparkOptions sparkOptions = new SparkOptions(sootOptions);
        /*
          PAG analyzer = new PAG(sparkOptions);

          CallGraphBuilder builder = new CallGraphBuilder(analyzer);
          CallGraph callGraph = builder.getCallGraph();
          Scene.v().setCallGraph(callGraph);
        */

        // Set entry points for call graph. The default entry points lead to
        // excessive code size.
        Scene.v().setEntryPoints(_getCallGraphEntryPoints(source));
        SparkTransformer.v().transform("cg.spark", sootOptions);

        _growTree(source);

        if (Options.v().getBoolean("reportEntities")) {
            System.out.println("\nReporting Entities ...");

            System.out.println(_reachableClasses.size()
                    + " classes generated.");

            System.out.println(_reachableMethods.size()
                    + " methods generated.");

            System.out.println(_reachableFields.size()
                    + " fields generated.");
        }
    }

    ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////

    /** Get the set of all reachable classes.
     *  @return The set of all reachable classes.
     */
    public HashSet getReachableClasses() {
        return _reachableClasses;
    }

    /** Get the set of all reachable fields.
     *  @return The set of all reachable fields.
     */
    public HashSet getReachableFields() {
        return _reachableFields;
    }

    /** Get the set of all reachable methods.
     *  @return The set of all reachable methods.
     */
    public HashSet getReachableMethods() {
        return _reachableMethods;
    }


    ///////////////////////////////////////////////////////////////////
    ////                         public fields                     ////


    ///////////////////////////////////////////////////////////////////
    ////                         protected methods                 ////
    /** Adds a whole collection of classes/methods/fields to _gray.
     * @param nodes The collection of nodes to add.
     */
    protected void _add(Collection nodes) {
        Iterator i = nodes.iterator();
        while (i.hasNext()) {
            _add(i.next());
        }
    }

    /** Adds an object to the _gray list if the object is not in the gray
     * or a _reachable list. The object is assumed to be a class, method or
     * field.
     * @param node The object to add.
     */
    protected void _add(Object node) {
        if (!_gray.contains(node)) {
            if (node instanceof SootClass) {
                if (!_reachableClasses.contains(node)) {
                    _gray.addLast(node);
                }
            }
            else if (node instanceof SootMethod) {
                if (!_reachableMethods.contains(node)) {
                    _gray.addLast(node);
                }
            }
            else if (node instanceof SootField) {
                if (!_reachableFields.contains(node)) {
                    _gray.addLast(node);
                }
            }
        }

    }

    /** Adds a class, method or field  to the appropriate reachable list.
     * @param node The class/field/method to process.
     */
    protected void _done(Object node) {
        if (_gray.contains(node)) {
            _gray.remove(node);
        }
        if (node instanceof SootClass) {
            _reachableClasses.add(node);
        }
        else if (node instanceof SootMethod) {
            _reachableMethods.add(node);
        }
        else if (node instanceof SootField) {
            _reachableFields.add(node);
        }
    }

    /** Returns the list of methods that should be considered entry points
     * for building the CallGraph.
     * @param source The main class in the Scene.
     * @return The list of entry points.
     */
    protected LinkedList _getCallGraphEntryPoints(SootClass source) {
        // Just pick the compulsory nodes that are methods but are not
        // overridden.
        LinkedList entryPoints = new LinkedList();
        Iterator nodes = _getCompulsoryNodes().iterator();

        while (nodes.hasNext()) {
            Object node = nodes.next();
            if (node instanceof SootMethod) {
                SootMethod method = (SootMethod)node;
                if (method.isConcrete()
                        && !OverriddenMethodGenerator.isOverridden(method)) {
                    entryPoints.add(method);
                }
            }
        }

        if (source.declaresMethodByName("main")) {
            entryPoints.add(source.getMethodByName("main"));
        }

        return entryPoints;
    }

    /** Returns the list of nodes(methods/classes/fields) that are always
     * needed, regardless of whether the source class reaches them
     * explicitly.
     * @return The list of compulsory methods.
     */
    protected LinkedList _getCompulsoryNodes() {
        LinkedList compulsoryNodes = new LinkedList();

        // User-defined compulsory methods.
        compulsoryNodes.addAll(_getForcedCompulsoryMethods());


        // Add java.lang.String.String(char[]). Initializer
        SootClass source = Scene.v().getSootClass("java.lang.String");
        SootMethod method = source.getMethod("void <init>(char[])");
        compulsoryNodes.add(method);
        // Add java.lang.String.<clinit>.
        /*method = source.getMethodByName("<clinit>");
        compulsoryNodes.add(method);*/
        // java.lang.String.toString() is needed.
        method = source.getMethodByName("toString");
        compulsoryNodes.add(method);
        // All fields of String are required.
        compulsoryNodes.addAll(source.getFields());

        // Add java.lang.System.initializeSystemClass()
        source = Scene.v().getSootClass("java.lang.System");
        /*method = source.getMethodByName("initializeSystemClass");
        compulsoryNodes.add(method);*/
        // System.out is required by initializeSystemClass
        SootField field = source.getFieldByName("out");
        compulsoryNodes.add(field);
        // System.err is required by initializeSystemClass
        field = source.getFieldByName("err");
        compulsoryNodes.add(field);


        // Printstream is required by the force-overridden version of
        // System.initializeSystemClass(), but it doesn't have a clinit.
        source = Scene.v().getSootClass("java.io.PrintStream");
        method = source.getMethod("void println(int)");
        compulsoryNodes.add(method);

        // Class is required by Object.
        source = Scene.v().getSootClass("java.lang.Class");
        compulsoryNodes.add(source);

        // Exception is required pccg_runtime.h
        source = Scene.v().getSootClass("java.lang.Exception");
        compulsoryNodes.add(source);

        // Printstream is required in initializeSystemClass.
        source = Scene.v().getSootClass("java.io.PrintStream");
        compulsoryNodes.add(source);

        return compulsoryNodes;
    }

    /** Returns the list of methods required by inheritance. If a class C
     * implements an interface I or extends a class I, then C.m is required
     * if I.m is required.
     * @param classSet The set of classes that are candidates for C.
     * @param methodSet The set of methods to which I.m may belong.
     * @return The set of all methods of <i>classes</i> that may be
     * implementing a method in <i>methods </i>.
     */
    protected HashSet _getMethodsRequiredByInheritance(Collection
            classSet, Collection methodSet) {
        HashSet requiredMethodSet = new HashSet();

        Iterator classes = classSet.iterator();
        while (classes.hasNext()) {
            SootClass source = (SootClass)classes.next();
            Iterator methods = methodSet.iterator();
            Hierarchy hierarchy = new Hierarchy();

            // Candidates for I. All superclasses and all implemented
            // interfaces.
            Collection allParents = AnalysisUtilities
                    .getAllInterfacesOf(source);

            if (!source.isInterface()) {
                allParents.addAll(hierarchy.getSuperclassesOf(source));
            }

            while (methods.hasNext()) {
                SootMethod method = (SootMethod)methods.next();
                String subSignature = method.getSubSignature();

                if (source.declaresMethod(subSignature)
                        && allParents.contains(method.getDeclaringClass())
                    ) {
                    requiredMethodSet.add(source.getMethod(subSignature));
                }
            }
        }

        return requiredMethodSet;
    }


    /** Returns a set of the nodes referenced in the body of a given
     * method. This includes:
     * <UL>
     * <LI> Methods directly called (sometimes invokegraph fails to catch
     * these).
     * <LI> Fields accessed.
     * <LI> Classes called by instanceof expressions.
     * </UL>
     * These are computed here in the same method so that only one pass
     * through the statements in the body is required.
     * @param method The method.
     * @return The set of nodes unambiguously referenced in the statements
     * comprising its body.
     */
    protected HashSet _getNodesAccessedInBodyOf(SootMethod method) {
        HashSet nodes = new HashSet();
        Scene.v().loadClassAndSupport(method.getDeclaringClass().getName());

        if (method.isConcrete() && !OverriddenMethodGenerator
                .isOverridden(method)) {
            boolean leaf = _isLeaf(method);

            Iterator units = method.retrieveActiveBody()
                .getUnits().iterator();
            while (units.hasNext()) {
                Unit unit = (Unit)units.next();
                if (unit instanceof Stmt) {
                    Stmt stmt = (Stmt)unit;

                    // Add accessed fields.
                    if (stmt.containsFieldRef()) {
                        FieldRef fieldRef = (FieldRef)stmt.getFieldRef();
                        SootField field = fieldRef.getField();
                        nodes.add(field);
                    }

                    // Add directly called methods.
                    if (!leaf && stmt.containsInvokeExpr()) {
                        SootMethod m = ((InvokeExpr)stmt.getInvokeExpr())
                            .getMethod();
                        nodes.add(m);
                        nodes.add(m.getDeclaringClass());
                    }
                }

                // Get all classes used in all "instanceof" expressions.
                Iterator boxes = unit.getUseAndDefBoxes().iterator();
                while (boxes.hasNext()) {
                    ValueBox box = (ValueBox)boxes.next();
                    Value value = box.getValue();
                    if (value instanceof InstanceOfExpr) {
                        InstanceOfExpr expr = (InstanceOfExpr)value;
                        Type checkType = expr.getCheckType();
                        if (checkType instanceof RefType) {
                            nodes.add(((RefType)checkType).getSootClass());
                        }
                    }
                }
            }
        }

        return nodes;
    }

    /** Gets the set of fields, methods and classes to be started off with.
     * @return The set of nodes that are needed to start off with.
     */
    protected HashSet _getRoots(SootClass source) {
        // Using a HashSet prevents duplication.
        HashSet roots = new HashSet();

        roots.addAll(source.getMethods());
        roots.addAll(source.getFields());
        roots.addAll(_getCompulsoryNodes());
        roots.add(source);
        roots.addAll(Scene.v().getSootClass("java.lang.Object").getMethods());

        return roots;
    }

    /** Computes the set of classes, methods and fields reachable from a
     * given class.
     * @param source The class.
     */
    protected void _growTree(SootClass source) {

        // FIFO queue to store all nodes for processing.
        _gray.addAll(_getRoots(source));


        while (!_gray.isEmpty()) {
            while (!_gray.isEmpty()) {

                Object node = _gray.getFirst();
                if (node instanceof SootClass) {
                    _processClass((SootClass)node);
                }
                else if (node instanceof SootMethod) {
                    if (((SootMethod)node).isDeclared()) {
                        _processMethod((SootMethod)node);
                    }
                    else {
                        _gray.removeFirst();
                        System.out.println(
                                "CallGraphPruner._growTree: "
                                + "Removed an undeclared method\n");
                    }
                }
                else if (node instanceof SootField) {
                    _processField((SootField)node);
                }
                else {
                    throw new RuntimeException("Invalid node type.");
                }
            }

            // We move this to an outer loop to prevent it from being
            // executed frequently.
            //_add(_getMethodsRequiredByInheritance(_reachableClasses,
            //        _reachableMethods));
        }

    }

    /** Figures out if a the targets of a method need to be computed.
     * Computation terminates at a "leaf" method. All native and
     * force-overridden methods are leaves.
     * @param method The method.
     * @return True if the method is a leaf.
     */
    protected boolean _isLeaf(SootMethod method) {
        return (method.isNative()
                || OverriddenMethodGenerator.isOverridden(method));
    }

    /** Performs the appropriate operations for the discovery of a new
     *  class.
     *  @param node The class.
     */
    protected void _processClass(SootClass node) {
        if (_reachableClasses.contains(node)) {
            return;
        }

        if (!OverriddenMethodGenerator.isOverridden(node)) {
            // Add the clinit method.
            if (node.declaresMethodByName("<clinit>")) {
                _add(node.getMethodByName("<clinit>"));
            }
            // Add all superClasses.
            SootClass superclass = node;
            while (superclass.hasSuperclass()
                    && !_reachableClasses.contains(superclass)) {
                superclass = superclass.getSuperclass();
                _add(superclass);
            }

        }

        _done(node);
    }

    /** Performs the appropriate operations for the discovery of a new
     * field.
     * @param field The field.
     */
    protected void _processField(SootField field) {
        if (_reachableFields.contains(field)) {
            return;
        }
        _add(AnalysisUtilities.classesRequiredBy(field));
        _done(field);
    }

    /** Performs the appropriate operations for the discovery of a new
     * method.
     * @param method The method.
     */
    protected void _processMethod(SootMethod method) {
        // If the method is in an undiscovered class, refresh the
        // invokeGraph.
        SootClass source = method.getDeclaringClass();
        int oldSize = _gray.size();

        // Care must be taken in what goes inside this if block. All trails
        // that terminate at leaf nodes must be inside it.
        if (!_isLeaf(method)) {
            // Add all methods shown by the local callGraph to be called
            // by this method.
            CallGraph callGraph = Scene.v().getCallGraph();
            Iterator outEdges = callGraph.edgesOutOf(method);
            while (outEdges.hasNext()) {
                Edge edge = (Edge)outEdges.next();
                SootMethod targetMethod = edge.tgt();
                _add(targetMethod);
            }

            // Add the nodes called in the body of the method.
            _add(_getNodesAccessedInBodyOf(method));

            // Add the locals declared in the body of this method.
            _add(AnalysisUtilities.getLocalTypeClasses(method));

            // Add all exceptions that can be caught by this method.
            if (method.isConcrete()
                    && !OverriddenMethodGenerator.isOverridden(method)) {
                Iterator traps = method.retrieveActiveBody().getTraps()
                    .iterator();
                while (traps.hasNext()) {
                    Trap trap = (Trap)traps.next();
                    _add(trap.getException());
                }
            }
        }


        // Add all exception classes that can be thrown by this method.
        _add(method.getExceptions());

        // Add all arguments of this method.
        _add(AnalysisUtilities.getArgumentClasses(method));

        /*
          if (_gray.size() - oldSize >20) {
          System.out.println(method);
          }
        */
        // Remove the method from the queue.
        _done(method);
    }



    ///////////////////////////////////////////////////////////////////
    ////                       protected fields                    ////
    /** The list of all classes, methods, and fields discovered but not yet
     * processed.
     */
    protected LinkedList _gray = new LinkedList();

    /** The list of all reachable classes.
     */
    protected HashSet _reachableClasses = new HashSet();

    /** The list of all reachable fields.
     */
    protected HashSet _reachableFields = new HashSet();

    /** The list of all reachable methods.
     */
    protected HashSet _reachableMethods = new HashSet();



    ///////////////////////////////////////////////////////////////////
    ////                         private methods                   ////

    /** Parse the "compulsory" option and return the list of entities that
     * forced to be compulsory by the user.
     */
    private LinkedList _getForcedCompulsoryMethods() {
        String optionString = Options.v().get("compulsoryMethods");
        LinkedList methods = new LinkedList();

        if (optionString.equals("")) {
            return methods;
        }

        // semicolon follwed by 0 or 1 spaces.
        String[] names = optionString.split("; ?+");

        for (int i = 0; i < names.length; i++) {
            String className, subSignature;

            int parenthesisIndex = names[i].indexOf('(');
            int spaceIndex = names[i].indexOf(' ');
            int classNameEndIndex = names[i]
                    .lastIndexOf('.', parenthesisIndex);

            subSignature = names[i].substring(0, spaceIndex)
                        + " "
                        + names[i].substring(classNameEndIndex + 1);

            className = names[i].substring(spaceIndex + 1, classNameEndIndex);

            SootClass source = Scene.v().getSootClass(className);
            SootMethod method = source.getMethod(subSignature);
            methods.add(method);
        }

        return methods;
    }



    /** Set all classes in the Scene as library classes. */
    private void _setAllClassesAsLibrary() {

        if (_verbose) {
            System.out.println(
                    "Setting all classes to library classes ...");
        }

        Iterator classes = Scene.v().getClasses().iterator();
        while (classes.hasNext()) {
            SootClass source = (SootClass)classes.next();
            source.setLibraryClass();
        }
    }

    /** Set all classes in the Scene that are not overridden as library
        classes.
    */
    private void _setUnOverriddenClassesAsLibrary() {
        if (_verbose) {
            System.out.println(
                    "Setting all un-overridden classes to library classes ...");
        }

        Iterator classes = Scene.v().getClasses().iterator();
        while (classes.hasNext()) {
            SootClass source = (SootClass)classes.next();
            if (OverriddenMethodGenerator.isOverridden(source)) {
                source.setLibraryClass();
            }
        }
    }


    ///////////////////////////////////////////////////////////////////
    ////                         private fields                    ////

    /** True if the "verbose" option is on. */
    private boolean _verbose;

}


More information about the Soot-list mailing list