/** 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);
      }
    }
  }