Package dk.brics.xact.analysis

Source Code of dk.brics.xact.analysis.XMLAnalysis

package dk.brics.xact.analysis;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import dk.brics.automaton.Automaton;
import dk.brics.misc.Origin;
import dk.brics.xact.XMLException;
import dk.brics.xact.analysis.concurrent.ExecutorTaskRunner;
import dk.brics.xact.analysis.concurrent.SingleThreadedTaskRunner;
import dk.brics.xact.analysis.concurrent.XactTaskRunner;
import dk.brics.xact.analysis.config.Configuration;
import dk.brics.xact.analysis.config.StandardConfiguration;
import dk.brics.xact.analysis.flowgraph.FlowGraph;
import dk.brics.xact.analysis.soot.Jimple2FlowGraph;
import dk.brics.xact.analysis.soot.TranslationResult;
import dk.brics.xact.analysis.transformations.ArrayTransformer;
import dk.brics.xact.analysis.transformations.CallTransformer;
import dk.brics.xact.analysis.transformations.DefUseTransformer;
import dk.brics.xact.analysis.transformations.FieldTransformer;
import dk.brics.xact.analysis.transformations.FlowGraph2Dot;
import dk.brics.xact.analysis.transformations.SchemaTypeLinking;
import dk.brics.xact.analysis.transformations.Splitter;
import dk.brics.xact.analysis.transformations.UnreachableTransformer;
import dk.brics.xact.analysis.xmlgraph.XMLGraphBuilder;
import dk.brics.xact.analysis.xmlgraph.XMLGraphChecker;
import dk.brics.xmlgraph.AttributeNode;
import dk.brics.xmlgraph.ElementNode;
import dk.brics.xmlgraph.Node;
import dk.brics.xmlgraph.NodeProcessor;
import dk.brics.xmlgraph.TextNode;
import dk.brics.xmlgraph.XMLGraph;

/**
* Program analysis for XACT.
* <p/>
* <h3>Running multiple analyses concurrently</h3>
* Separate instances of <code>XMLAnalysis</code> can safely be run in parallel.
* However, because Soot does not support separate instances of itself running,
* the initial phase will lock <tt>soot.G.class</tt> to prevent interference.
* The remaining phases will run concurrently with other analyses.
* <p/>
* <h3>Enabling concurrency in the analysis</h3>
* To enable concurrency within one analysis, use {@link #setTaskRunner(XactTaskRunner)}
* or {@link #setExecutorService(ExecutorService)}. The analysis will be single-threaded
* if neither method is called before starting the analysis.
*/
public class XMLAnalysis {
 
  private List<String> classes;
 
  private List<SootClass> soot_classes = new LinkedList<SootClass>();
 
  private ErrorHandler errors = new ErrorHandler();
 
  private Diagnostics diagnostics = Diagnostics.NULL;
  private Configuration config = new StandardConfiguration();
  private XactTaskRunner tasks = new SingleThreadedTaskRunner();
 
  private String classpath;

  private static void initializeSoot() {
        soot.Scene.v().loadBasicClasses();
    soot.options.Options.v().set_keep_line_number(true);
  }
 
  /**
   * Initializes XACT program analysis for the given classes.
   * The first class is assumed to be the main class.
   * @param soot_classpath the class path for the classes to be analyzed
   *                       (if null, just use the normal class path)
   * @param classes names of the classes to be analyzed
   */
  public XMLAnalysis(String soot_classpath, List<String> classes) {
    this.classes = classes;
    this.classpath = soot_classpath;
  }
 
  /**
   * Sets the {@link Diagnostics} object to receive event notifications.
   */
  public void setDiagnostics(Diagnostics diag) {
    this.diagnostics = diag;
  }
  /**
   * Sets the {@link Configuration} object to be used in the analysis.
   */
  public void setConfiguration(Configuration config) {
    this.config = config;
  }
 
  /**
   * Sets an {@link ExecutorService} used to perform parallelizable tasks.
   * This is equivalent to
   * <pre>
   * setTaskRunner(new ExecutorTaskRunner(executor));
   * </pre>
   *
   * @param executor an executor service
   * @see Executors
   * @see #setTaskRunner(XactTaskRunner)
   */
  public void setExecutorService(ExecutorService executor) {
      setTaskRunner(new ExecutorTaskRunner(executor));
    }
 
  /**
   * Sets the {@link XactTaskRunner} used to perform parallelizable tasks.
   * @param tasks the tasks runner
   * @see #setExecutorService(ExecutorService)
   */
  public void setTaskRunner(XactTaskRunner tasks) {
      this.tasks = tasks;
  }
 
  /**
   * Marks the start of a phase.
   * For debug info only.
   */
  static void startPhase(String msg) {
    Debug.println(1, true, msg);
    Debug.inc();
  }
 
  /**
   * Marks the end of a phase.
   * For debug info only.
   */
  static void endPhase() {
    Debug.dec();
  }
 
  public void printMessages() {
      printMessages(System.out);
    }
 
    public void printMessages(PrintStream out) {
        errors.printMessages(out);
    }
    public void printMessages(PrintWriter out) {
        errors.printMessages(out);
    }

    /**
   * Runs the analysis.
   * <p/>
   * This method will lock <tt>soot.G.class</tt> during the initial phase.
   * <p/>
   * One cannot use hotpsots when using this method. If hotspot statements are of
   * interest, use the other more low-level methods.
   */
  public void analyze() {
      if (Debug.getLevel() >= 1 && tasks.maybeMultiThreaded()) {
          Debug.println(1, false, "Warning: Concurrency can mess up the debug output");
      }
    try {
      FlowGraph g;
            synchronized (soot.G.class) {
        try {
              initializeSoot();
              if (classpath != null)
                  soot.options.Options.v().set_soot_classpath(classpath);
          loadClasses();
          diagnostics.afterSootLoaded();
          g = buildFlowGraph().getGraph();
        } finally {
          releaseSoot();
        }
            }
      transformFlowGraph(g);
            final XMLGraph sharedXg = g.getXMLGraph();
      List<FlowGraph> graphs = splitFlowGraph(g);
      g = null;
      int index=0;
      final ThreadLocal<XMLGraph> localXg = new ThreadLocal<XMLGraph>();
      for (final FlowGraph g2 : graphs) {
        Debug.println(2, true, "Subgraph index..." + index);
        Debug.println(2, true, "Node count......." + g2.getNodes().size());
        Debug.println(2, true, "Edge count......." + g2.getNumberOfEdges());
          tasks.addTask(new Runnable() {
              public void run() {
                  try {
                      XMLGraph xg = localXg.get();
                      if (xg == null) {
                          xg = safeCloneGraph(sharedXg);
                          localXg.set(xg);
                      }
                      g2.setXMLGraph(xg);
                          XMLGraphBuilder b = buildXMLGraphs(g2);    
                          analyzeXMLGraphs(g2, b);
                  } catch (XMLException e) {
                      Origin or = e.getOrigin();
                      errors.error(or, ErrorType.OTHER, e.getMessage());
                      System.out.println("Error: " + e.getMessage() +
                              ((or!=null ? " at " + or.getFile() + " line " + or.getLine() +
                                      (or.getColumn()>0 ? " column " + or.getColumn() : ""): "")));
                  } catch (Throwable t) {
                      errors.error(t);
                  }
              }
          });
        index++;
      }
      tasks.runTasks();
    } catch (XMLAnalysisException e) {
      Origin or = e.getOrigin();
      errors.error(or, ErrorType.OTHER, e.getMessage());
      System.out.println("Error: " + e.getMessage() +
          ((or!=null ? " at " + or.getFile() + " line " + or.getLine() +
              (or.getColumn()>0 ? " column " + or.getColumn() : ""): "")));
    }
  }
 
  /**
   * Clones all {@link Automaton} instances in the given XML graph
   * so there is no interference with other threads.
   * @param xg an XML graph
   * @return a new XML graph
   */
  private XMLGraph safeCloneGraph(XMLGraph xg) {
      final XMLGraph output = xg.clone();
      for (int i=0; i<xg.getNodes().size(); i++) {
          Node node = output.getNode(i);
          node.process(new NodeProcessor<Object>() {
              @Override
              public Object process(AttributeNode n) {
                  n.setName(n.getName().clone(), output);
                  return this;
              }
                @Override
                public Object process(ElementNode n) {
                    n.setName(n.getName().clone(), output);
                    return this;
                }
                @Override
                public Object process(TextNode n) {
                    n.replaceText(n.getText().clone(), output);
                    return this;
                }
          });
      }
      return output;
  }
 
  private List<FlowGraph> splitFlowGraph(FlowGraph g) {
    startPhase("Splitting flow graph...");
    List<FlowGraph> list = new Splitter().split(g);
    Debug.println(2, true, "Created " + list.size() + " subgraphs");
    diagnostics.afterSplit(g, list);
    endPhase();
    return list;
  }
 
  /**
   * Loads the class files.
   * This method is <i>not</i> thread-safe (because of Soot).
   */
  public void loadClasses() {
    startPhase("Loading classes...");
    Scene.v().addBasicClass("java.util.Collection");
    Scene.v().addBasicClass("java.util.List");
    Scene.v().addBasicClass("java.util.Set");
    Scene.v().addBasicClass("java.util.SortedSet");
    Scene.v().addBasicClass("java.util.Queue");
    Scene.v().addBasicClass("java.util.Deque");
    Scene.v().addBasicClass("java.util.Iterator");
    Scene.v().addBasicClass("java.util.ListIterator");
    Scene.v().addBasicClass("java.lang.Iterable");
    Scene.v().addBasicClass("java.util.Arrays");
    Scene.v().addBasicClass("java.util.Collections");
        Scene.v().addBasicClass("java.util.Map");
        Scene.v().addBasicClass("java.util.Map$Entry");
        Scene.v().addBasicClass("java.util.SortedMap");
        Scene.v().addBasicClass("java.util.NavigableMap");
        Scene.v().addBasicClass("java.util.ConcurrentMap");
    boolean first = true;
    for (String classname : classes) {
      Debug.println(2, true, classname);
      loadClass(classname, first);
      first = false;
    }
    Scene.v().loadBasicClasses();
    endPhase();
  }
 
  /**
   * Loads the named class into the Soot scene, marks it as an application
   * class, and generates bodies for all of its concrete methods.
   */
  private void loadClass(String name, boolean main) {
    SootClass c = Scene.v().loadClassAndSupport(name);
    soot_classes.add(c);
    c.setApplicationClass();
    //if (main)
    //  Scene.v().setMainClass(c);
    for (SootMethod sm : c.getMethods())
      if (sm.isConcrete())
        sm.retrieveActiveBody();
  }
 
  /**
   * Builds the flow graph and finds schema URLs.
   * This method is <i>not</i> thread-safe (because of Soot).
   */
  public TranslationResult buildFlowGraph() {
    startPhase("Building flow graph...");
    TranslationResult tr = new Jimple2FlowGraph(config, errors).run();
    FlowGraph g = tr.getGraph();
    Debug.println(2, true, "Flow graph nodes: " + g.getNodes().size()
        + ", edges: " + g.getNumberOfEdges()
        + ", entries: " + g.getEntries().size());
    dumpFlowGraph(g, "fg1.dot");
    endPhase();
    return tr;
  }
 
  /**
   * Resets Soot.
   * Can be invoked after string analysis and flow graph construction.
   */
  public void releaseSoot() {
    soot.G.reset();
    //System.gc();
  }
   
  /**
   * Performs various transformations of the given flow graph.
   * Must be invoked before XML graph construction.
   */
  public void transformFlowGraph(FlowGraph g) {
    diagnostics.afterControlFlow(g);
   
    startPhase("Fixing arrays...");
    new ArrayTransformer().run(g);  diagnostics.afterArrays(g);
    endPhase();
   
    startPhase("Transforming method calls");
    new CallTransformer().run(g); diagnostics.afterCalls(g);
    endPhase();
   
    startPhase("Removing unreachable statements...");
    new UnreachableTransformer().run(g); diagnostics.afterUnreachable(g);
    endPhase();
   
    startPhase("Linking fields...");
    new FieldTransformer().run(g);
    endPhase();
   
    /*startPhase("Removing dead nodes...");
    new IgnoreDeadTransformer().run(g); diagnostics.afterDead(g);
    endPhase();*/

    startPhase("Reducing flow graph...");
    new DefUseTransformer().run(g);  diagnostics.afterDefUse(g);
    endPhase();
   
        startPhase("Linking SchemaTypes...");
        new SchemaTypeLinking().run(g, config); diagnostics.afterSchemaTypeLinking(g);
        endPhase();
       
    /*startPhase("Fixing annotations...");
    new AnnotationTransformer().run(g);*/
    Debug.println(2, true, "Flow graph nodes: " + g.getNodes().size()
        + ", edges: " + g.getNumberOfEdges()
        + ", entries: " + g.getEntries().size());
    //dumpFlowGraph(g, "fg3.dot");
    //endPhase();
  }

  /**
   * Builds the XML graphs.
   */
  public XMLGraphBuilder buildXMLGraphs(FlowGraph g) {
    startPhase("Constructing XML graphs...");
    XMLGraphBuilder b = new XMLGraphBuilder(g, config);
    endPhase();
    return b;
  }

  /**
   * Analyzes the XML graphs.
   */
  public void analyzeXMLGraphs(FlowGraph g, XMLGraphBuilder b) {
    startPhase("Analyzing XML graphs...");
    XMLGraphChecker checker = new XMLGraphChecker(errors);
    checker.run(g, b);
    endPhase();
  }
 
  private void dumpFlowGraph(FlowGraph g, String name) {
    if (Debug.getLevel() >= 3) {
      try {
        String path = System.getProperty("java.io.tmpdir");
        String sep = System.getProperty("file.separator");
        if (!path.endsWith(sep))
          path += sep;
        path += name;
        Debug.println(3, true, "Writing flow graph to: " + path);
        FileOutputStream out = new FileOutputStream(path);
        PrintStream pout = new PrintStream(out);
        new FlowGraph2Dot(pout).print(g);
        pout.close();
      } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
      }
    }
  }
 
  public List<ErrorReport> getErrors() {
    return errors.getErrors();
  }
}
TOP

Related Classes of dk.brics.xact.analysis.XMLAnalysis

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.