/** Performs peephole optimizations on a program's live methods. */
  private static void peephole(final BloatContext context) {

    final Set liveMethods = new TreeSet(new MemberRefComparator());
    final CallGraph cg = context.getCallGraph();
    liveMethods.addAll(cg.liveMethods());

    // Perform peephole optimizations. We do this separately because
    // some peephole optimizations do things to the stack that
    // inlining doesn't like. For instance, a peephole optimizations
    // might make it so that a method has a non-empty stack upon
    // return. Inlining will barf at the sight of this.
    BloatBenchmark.tr("Performing peephole optimizations");

    final Iterator iter = liveMethods.iterator();
    while (BloatBenchmark.PEEPHOLE && iter.hasNext()) {
      try {
        final MethodEditor live = context.editMethod((MemberRef) iter.next());
        Peephole.transform(live);
        context.commit(live.methodInfo());
        context.release(live.methodInfo());

      } catch (final NoSuchMethodException ex314) {
        BloatBenchmark.err.println("** Could not find method " + ex314.getMessage());
        ex314.printStackTrace(System.err);
        System.exit(1);
      }
    }
  }
  /** Specializes the live methods in a program. */
  private static void specialize(final BloatContext context) {

    final CallGraph cg = context.getCallGraph();

    final Set liveMethods = new TreeSet(new MemberRefComparator());
    liveMethods.addAll(cg.liveMethods());

    // Specialize all possible methods
    final InlineStats stats = context.getInlineStats();

    if (BloatBenchmark.statsFile != null) {
      Specialize.STATS = true;
      stats.setConfigName("BloatBenchmark");
    }

    if (BloatBenchmark.MORPH != -1) {
      Specialize.MAX_MORPH = BloatBenchmark.MORPH;
    }
    final Specialize spec = new Specialize(context);

    if (Specialize.STATS) {
      stats.noteLiveMethods(liveMethods.size());
      stats.noteLiveClasses(cg.liveClasses().size());
    }

    BloatBenchmark.tr("Specializing live methods");
    final Iterator iter = liveMethods.iterator();

    for (int count = 0; iter.hasNext(); count++) {
      try {
        final MethodEditor live = context.editMethod((MemberRef) iter.next());

        if (context.ignoreMethod(live.memberRef())) {
          // Don't display ignored methods, it's misleading.
          continue;
        }

        BloatBenchmark.tr(
            "  " + count + ") " + live.declaringClass().name() + "." + live.name() + live.type());

        spec.specialize(live);

      } catch (final NoSuchMethodException ex2) {
        BloatBenchmark.err.println("** Could not find method " + ex2.getMessage());
        System.exit(1);
      }
    }
  }
  /** Inlines calls to static methods in the live methods of a given program. */
  private static void inline(final BloatContext context) {

    final Set liveMethods = new TreeSet(new MemberRefComparator());
    final CallGraph cg = context.getCallGraph();
    liveMethods.addAll(cg.liveMethods());

    BloatBenchmark.tr("Inlining " + liveMethods.size() + " live methods");

    if (BloatBenchmark.CALLEE_SIZE != -1) {
      Inline.CALLEE_SIZE = BloatBenchmark.CALLEE_SIZE;
    }

    final Iterator iter = liveMethods.iterator();
    for (int count = 0; BloatBenchmark.INLINE && iter.hasNext(); count++) {
      try {
        final MethodEditor live = context.editMethod((MemberRef) iter.next());

        if (context.ignoreMethod(live.memberRef())) {
          // Don't display ignored methods, it's misleading.
          continue;
        }

        BloatBenchmark.tr(
            "  " + count + ") " + live.declaringClass().name() + "." + live.name() + live.type());

        final Inline inline = new Inline(context, BloatBenchmark.SIZE);
        inline.setMaxCallDepth(BloatBenchmark.DEPTH);
        inline.inline(live);

        // Commit here in an attempt to conserve memory
        context.commit(live.methodInfo());
        context.release(live.methodInfo());

      } catch (final NoSuchMethodException ex3) {
        BloatBenchmark.err.println("** Could not find method " + ex3.getMessage());
        System.exit(1);
      }
    }
  }
  /**
   * Returns the live methods of a program whose root methods are the <tt>main</tt> method of a set
   * of classes.
   *
   * @param classes Names of classes containing root methods
   * @param context Repository for accessing BLOAT stuff
   * @return The <tt>MemberRef</tt>s of the live methods
   */
  private static Collection liveMethods(final Collection classes, final BloatContext context) {

    // Determine the roots of the call graph
    final Set roots = new HashSet();
    Iterator iter = classes.iterator();
    while (iter.hasNext()) {
      final String className = (String) iter.next();
      try {
        final ClassEditor ce = context.editClass(className);
        final MethodInfo[] methods = ce.methods();

        for (int i = 0; i < methods.length; i++) {
          final MethodEditor me = context.editMethod(methods[i]);

          if (!me.name().equals("main")) {
            continue;
          }

          BloatBenchmark.tr("  Root " + ce.name() + "." + me.name() + me.type());
          roots.add(me.memberRef());
        }

      } catch (final ClassNotFoundException ex1) {
        BloatBenchmark.err.println("** Could not find class: " + ex1.getMessage());
        System.exit(1);
      }
    }

    if (roots.isEmpty()) {
      BloatBenchmark.err.print("** No main method found in classes: ");
      iter = classes.iterator();
      while (iter.hasNext()) {
        final String name = (String) iter.next();
        BloatBenchmark.err.print(name);
        if (iter.hasNext()) {
          BloatBenchmark.err.print(", ");
        }
      }
      BloatBenchmark.err.println("");
    }

    context.setRootMethods(roots);
    final CallGraph cg = context.getCallGraph();

    final Set liveMethods = new TreeSet(new MemberRefComparator());
    liveMethods.addAll(cg.liveMethods());

    return (liveMethods);
  }
Example #5
0
  /**
   * Parses the command line. The user must specify at least one class to optimize and the directory
   * in which to place the optimized class files. The methods of the specified classes are then
   * optimized according to the command line options.
   *
   * @see ClassEditor
   * @see ClassFileLoader
   * @see ClassFile
   * @see MethodEditor
   * @see MethodInfo
   * @see CompactArrayInitializer
   * @see FlowGraph
   */
  public static void main(final String[] args) {
    try {
      Main.loader = new ClassFileLoader();

      List classes = new ArrayList(args.length); // The classes to
      // optimize
      boolean gotdir = false; // Has an output directory been specified?

      Main.ARGS = args;

      for (int i = 0; i < args.length; i++) {
        if (args[i].equals("-v") || args[i].equals("-verbose")) {
          Main.VERBOSE = true;
          Main.loader.setVerbose(true);

        } else if (args[i].equals("-debug")) {
          Main.DEBUG = true;
          Main.loader.setVerbose(true);
          ClassFileLoader.DEBUG = true;
          CompactArrayInitializer.DEBUG = true;
          ClassEditor.DEBUG = true;
          FlowGraph.DEBUG = true;
          DominatorTree.DEBUG = true;
          Tree.DEBUG = true;
          CodeGenerator.DEBUG = true;
          Liveness.DEBUG = true;
          SSA.DEBUG = true;
          SSAGraph.DEBUG = true;
          PersistentCheckElimination.DEBUG = true;
          ValueNumbering.DEBUG = true;
          ValueFolding.DEBUG = true;
          ClassHierarchy.DEBUG = true;
          TypeInference.DEBUG = true;
          SSAPRE.DEBUG = true;
          StackPRE.DEBUG = true;
          ExprPropagation.DEBUG = true;
          DeadCodeElimination.DEBUG = true;
          CodeGenerator.DB_OPT_STACK = true;

        } else if (args[i].equals("-trace")) {
          Main.TRACE = true;

        } else if (args[i].equals("-db")) {

          if (++i >= args.length) {
            System.err.println("** No debugging option specified");
            Main.usage();
          }

          if (args[i].equals("bc")) {
            CodeArray.DEBUG = true;

          } else if (args[i].equals("cfg")) {
            FlowGraph.DEBUG = true;

          } else if (args[i].equals("ssa")) {
            SSA.DEBUG = true;
            SSAGraph.DEBUG = true;

          } else if (args[i].equals("graphs")) {
            FlowGraph.DB_GRAPHS = true;

          } else if (args[i].startsWith("-")) {
            i--;

          } else {
            System.err.println("** Unknown debugging option: " + args[i]);
            Main.usage();
          }

        } else if (args[i].equals("-debugvf")) {
          ValueFolding.DUMP = true;

        } else if (args[i].equals("-debugbc")) {
          BloatContext.DEBUG = true;

        } else if (args[i].equals("-help")) {
          Main.usage();

        } else if (args[i].equals("-noanno")) {
          Main.ANNO = false;

        } else if (args[i].equals("-anno")) {
          Main.ANNO = true;

        } else if (args[i].equals("-print-flow-graph")) {
          FlowGraph.PRINT_GRAPH = true;

        } else if (args[i].equals("-preserve-debug")) {
          MethodEditor.PRESERVE_DEBUG = true;

        } else if (args[i].equals("-nouse-stack-vars")) {
          Tree.USE_STACK = false;

        } else if (args[i].equals("-use-stack-vars")) {
          Tree.USE_STACK = true;

        } else if (args[i].equals("-unique-handlers")) {
          MethodEditor.UNIQUE_HANDLERS = true;

        } else if (args[i].equals("-nocompact-array-init")) {
          Main.COMPACT_ARRAY_INIT = false;

        } else if (args[i].equals("-compact-array-init")) {
          Main.COMPACT_ARRAY_INIT = true;

        } else if (args[i].equals("-nostack-alloc")) {
          Main.STACK_ALLOC = false;

        } else if (args[i].equals("-stack-alloc")) {
          Main.STACK_ALLOC = true;

        } else if (args[i].equals("-no-verify")) {
          Main.VERIFY = false;

        } else if (args[i].equals("-peel-loops")) {
          if (++i >= args.length) {
            Main.usage();
          }

          final String n = args[i];

          if (n.equals("all")) {
            FlowGraph.PEEL_LOOPS_LEVEL = FlowGraph.PEEL_ALL_LOOPS;

          } else {
            try {
              FlowGraph.PEEL_LOOPS_LEVEL = Integer.parseInt(n);

              if (FlowGraph.PEEL_LOOPS_LEVEL < 0) {
                Main.usage();
              }
            } catch (final NumberFormatException ex) {
              Main.usage();
            }
          }

        } else if (args[i].equals("-color")) {
          Liveness.UNIQUE = false;

        } else if (args[i].equals("-nocolor")) {
          Liveness.UNIQUE = true;

        } else if (args[i].equals("-only-method")) {
          if (++i >= args.length) {
            Main.usage();
          }

          Main.METHOD = args[i];

        } else if (args[i].equals("-classpath")) {
          if (++i >= args.length) {
            Main.usage();
          }

          final String classpath = args[i];
          Main.loader.setClassPath(classpath);

        } else if (args[i].equals("-classpath/p")) {
          if (++i >= args.length) {
            Main.usage();
          }

          final String classpath = args[i];
          Main.loader.prependClassPath(classpath);

        } else if (args[i].equals("-skip")) {
          if (++i >= args.length) {
            Main.usage();
          }

          String pkg = args[i];

          // Account for class file name on command line
          if (pkg.endsWith(".class")) {
            pkg = pkg.substring(0, pkg.lastIndexOf('.'));
          }

          Main.SKIP.add(pkg.replace('.', '/'));

        } else if (args[i].equals("-only")) {
          if (++i >= args.length) {
            Main.usage();
          }

          String pkg = args[i];

          // Account for class file name on command line
          if (pkg.endsWith(".class")) {
            pkg = pkg.substring(0, pkg.lastIndexOf('.'));
          }

          Main.ONLY.add(pkg.replace('.', '/'));

        } else if (args[i].equals("-nodce")) {
          Main.DCE = false;

        } else if (args[i].equals("-noprop")) {
          Main.PROP = false;

        } else if (args[i].equals("-noappre")) {
          SSAPRE.NO_ACCESS_PATHS = true;

        } else if (args[i].equals("-nopre")) {
          Main.PRE = false;

        } else if (args[i].equals("-dce")) {
          Main.DCE = true;

        } else if (args[i].equals("-prop")) {
          Main.PROP = true;

        } else if (args[i].equals("-appre")) {
          SSAPRE.NO_ACCESS_PATHS = false;

        } else if (args[i].equals("-pre")) {
          Main.PRE = true;

        } else if (args[i].equals("-closure")) {
          Main.CLOSURE = true;

        } else if (args[i].equals("-opt-stack-1")) {
          Main.OPT_STACK_1 = true;
          CodeGenerator.OPT_STACK = true;

        } else if (args[i].equals("-opt-stack-2")) {
          Main.OPT_STACK_2 = true;
          MethodEditor.OPT_STACK_2 = true;

        } else if (args[i].equals("-diva")) {
          Main.DIVA = true;

        } else if (args[i].equals("-no-thread")) {
          SSAPRE.NO_THREAD = true;

        } else if (args[i].equals("-no-precise")) {
          SSAPRE.NO_PRECISE = true;

        } else if (args[i].equals("-relax-loading")) {
          ClassHierarchy.RELAX = true;

        } else if (args[i].equals("-f") || args[i].equals("-force")) {
          Main.FORCE = true;

        } else if (args[i].startsWith("-")) {
          System.err.println("No such option: " + args[i]);
          Main.usage();

        } else if (i == args.length - 1) {
          // Last argument is the name of the output directory

          final File f = new File(args[i]);

          if (f.exists() && !f.isDirectory()) {
            System.err.println("No such directory: " + f.getPath());
            System.exit(2);
          }

          if (!f.exists()) {
            f.mkdirs();
          }

          if (!f.exists()) {
            System.err.println("Couldn't create directory: " + f.getPath());
            System.exit(2);
          }

          // Tell class loader to put optimized classes in f directory
          Main.loader.setOutputDir(f);
          gotdir = true;
        } else {
          // The argument must be a class name...
          classes.add(args[i]);
        }
      }

      if (!gotdir) {
        System.err.println("No output directory specified");
        Main.usage();
      }

      if (classes.size() == 0) {
        System.err.println("** No classes specified");
        Main.usage();
      }

      // Use the CachingBloatingContext
      Main.context = new CachingBloatContext(Main.loader, classes, Main.CLOSURE);

      boolean errors = false;

      final Iterator iter = classes.iterator();

      // Now that we've parsed the command line, load the classes into the
      // class loader
      while (iter.hasNext()) {
        final String name = (String) iter.next();

        try {
          Main.context.loadClass(name);

        } catch (final ClassNotFoundException ex) {
          System.err.println("Couldn't find class: " + ex.getMessage());

          errors = true;
        }
      }

      if (errors) {
        System.exit(1);
      }

      if (!Main.CLOSURE) {
        final Iterator e = classes.iterator();

        // Edit only the classes that were specified on the command line

        while (e.hasNext()) {
          final String name = (String) e.next();
          Main.editClass(name);
        }
      } else {
        // Edit all the classes in the class file editor and their
        // superclasses

        classes = null;

        if (Main.TRACE) {
          System.out.println("Computing closure " + Main.dateFormat.format(new Date()));
        }

        final Iterator e = Main.context.getHierarchy().classes().iterator();

        while (e.hasNext()) {
          final Type t = (Type) e.next();

          if (t.isObject()) {
            Main.editClass(t.className());
          }
        }
      }
    } catch (final ExceptionInInitializerError ex) {
      ex.printStackTrace();
      System.out.println(ex.getException());
    }
  }
  /**
   * Performs intraprocedural BLOAT on a program's live methods.
   *
   * @param liveMethods Should be alphabetized. This way we can commit a class once we've BLOATed
   *     all of its methods.
   */
  private static void intraBloat(final Collection liveMethods, final BloatContext context) {

    ClassEditor prevClass = null;
    final Iterator iter = liveMethods.iterator();
    for (int count = 0; iter.hasNext(); count++) {
      MethodEditor live = null;
      ClassEditor ce = null; // Hack to make sure commit happens
      try {
        live = context.editMethod((MemberRef) iter.next());
        ce = context.editClass(live.declaringClass().classInfo());

      } catch (final NoSuchMethodException ex3) {
        BloatBenchmark.err.println("** Could not find method " + ex3.getMessage());
        System.exit(1);
      }

      /* So we can skip classes or packages */
      final String name = ce.type().className();
      final String qual = ce.type().qualifier() + "/*";
      boolean skip = false;
      for (int i = 0; i < BloatBenchmark.SKIP.size(); i++) {
        final String pkg = (String) BloatBenchmark.SKIP.get(i);

        if (name.equals(pkg) || qual.equals(pkg)) {
          skip = true;
          break;
        }
      }

      if (context.ignoreMethod(live.memberRef()) || skip) {
        // Don't display ignored methods, it's misleading.
        context.release(live.methodInfo());
        continue;
      }

      final Runtime runtime = Runtime.getRuntime();
      runtime.gc();

      final Date start = new Date();
      BloatBenchmark.tr(
          "  " + count + ") " + live.declaringClass().name() + "." + live.name() + live.type());
      BloatBenchmark.tr("    Start: " + start);

      try {
        EDU.purdue.cs.bloat.optimize.Main.TRACE = BloatBenchmark.TRACE;
        if (!BloatBenchmark.VERIFY) {
          EDU.purdue.cs.bloat.optimize.Main.VERIFY = false;
        }
        EDU.purdue.cs.bloat.optimize.Main.bloatMethod(live, context);

      } catch (final Exception oops) {
        BloatBenchmark.err.println("******************************************");
        BloatBenchmark.err.println(
            "Exception while BLOATing "
                + live.declaringClass().name()
                + "."
                + live.name()
                + live.type());
        BloatBenchmark.err.println(oops.getMessage());
        oops.printStackTrace(System.err);
        BloatBenchmark.err.println("******************************************");
      }

      // Commit here in an attempt to conserve memory
      context.commit(live.methodInfo());
      context.release(live.methodInfo());

      if (prevClass == null) {
        prevClass = ce;

      } else if (!prevClass.equals(ce)) {
        // We've finished BLOATed the methods for prevClass, commit
        // prevClass and move on
        BloatBenchmark.tr(prevClass.type() + " != " + ce.type());
        context.commit(prevClass.classInfo());
        context.release(prevClass.classInfo());
        // context.commitDirty();
        // tr(context.toString());
        prevClass = ce;

      } else {
        context.release(ce.classInfo());
      }

      final Date end = new Date();
      BloatBenchmark.tr("    Ellapsed time: " + (end.getTime() - start.getTime()) + " ms");
    }

    context.commitDirty();
  }