/** 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); } } }
/** Creates a <tt>BloatContext</tt> that loads classes from a given CLASSPATH. */ static BloatContext makeContext(final String classpath, final String outputDirName) { final ClassFileLoader loader = new ClassFileLoader(); if (classpath != null) { loader.prependClassPath(classpath); } // if(TRACE) { // loader.setVerbose(true); // } BloatBenchmark.tr(" Creating a BloatContext for CLASSPATH: " + loader.getClassPath()); if (outputDirName != null) { loader.setOutputDir(new File(outputDirName)); } final BloatContext context = new CachingBloatContext(loader, BloatBenchmark.CLASSES, true); // Always ignore the sun packages and the opj stuff for // interprocedural stuff if (!BloatBenchmark.SUN) { context.addIgnorePackage("sun"); } context.addIgnorePackage("java.lang.ref"); context.addIgnorePackage("org.opj.system"); if (BloatBenchmark.USE1_1) { // Toba can't deal with java.lang.Character context.addIgnoreClass(Type.getType("Ljava/lang/Character;")); } return (context); }
/** * 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); }
/** 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); } } }
/** Runs BLOAT on a method. */ public static void bloatMethod(final MethodEditor m, final BloatContext context) { try { if (Main.COMPACT_ARRAY_INIT) { // Compact the initialization of arrays of the basic types by // putting the values of the array into a string in the constant // pool. The initialization code is replaced with a loop that // loads the array from the string in the constant pool. if (Main.TRACE) { System.out.println(" Compacting Arrays: " + Main.dateFormat.format(new Date())); } CompactArrayInitializer.transform(m); if (Main.DEBUG) { System.out.println("---------- After compaction:"); m.print(System.out); System.out.println("---------- end print"); } } FlowGraph cfg; // The control flow graph for a method if (Main.TRACE) { System.out.println(" Constructing CFG: " + Main.dateFormat.format(new Date())); } try { // Construct the control flow graph for method m cfg = new FlowGraph(m); } catch (final ClassFormatException ex) { System.err.println(ex.getMessage()); context.release(m.methodInfo()); return; } // We separate out initialization since before this the FlowGraph // more exactly represents the input program. cfg.initialize(); if (Main.TRACE) { System.out.println(" Transforming to SSA: " + Main.dateFormat.format(new Date())); } SSA.transform(cfg); if (FlowGraph.DEBUG) { System.out.println("---------- After SSA:"); cfg.print(System.out); System.out.println("---------- end print"); } if (Main.DEBUG) { cfg.visit(new VerifyCFG(false)); } if (!Tree.USE_STACK) { // Do copy propagation and value numbering first to get rid of // all the extra copies inserted for dups. If they're left in, // it really slows down value numbering. if (Main.PROP) { if (Main.DEBUG) { System.out.println("-----Before Copy Propagation-----"); } if (Main.TRACE) { System.out.println(" Copy propagation: " + Main.dateFormat.format(new Date())); } final ExprPropagation copy = new ExprPropagation(cfg); copy.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG(false)); } if (Main.DEBUG) { System.out.println("------After Copy Propagation-----"); cfg.print(System.out); } } } DeadCodeElimination dce = null; if (Main.DCE) { if (Main.TRACE) { System.out.println(" Dead Code Elimination: " + Main.dateFormat.format(new Date())); } if (Main.DEBUG) { System.out.println("---Before Dead Code Elimination--"); } dce = new DeadCodeElimination(cfg); dce.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG(false)); } if (Main.DEBUG) { System.out.println("---After Dead Code Elimination---"); cfg.print(System.out); } } if (Main.INFER) { if (Main.DEBUG) { System.out.println("---------Doing type inference--------"); } if (Main.TRACE) { System.out.println(" Type Inferencing: " + Main.dateFormat.format(new Date())); } TypeInference.transform(cfg, context.getHierarchy()); } if (Main.NUMBER) { if (Main.TRACE) { System.out.println(" Value Numbering: " + Main.dateFormat.format(new Date())); } if (Main.DEBUG) { System.out.println("--------Doing value numbering--------"); } (new ValueNumbering()).transform(cfg); } if (Main.FOLD) { if (Main.DEBUG) { System.out.println("--------Before Value Folding---------"); } if (Main.TRACE) { System.out.println(" Value Folding: " + Main.dateFormat.format(new Date())); } (new ValueFolding()).transform(cfg); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("---------After Value Folding---------"); cfg.print(System.out); } } if (Main.PRE) { if (Main.DEBUG) { System.out.println("-------------Before SSAPRE-----------"); } if (Main.TRACE) { System.out.println(" SSAPRE: " + Main.dateFormat.format(new Date())); } final SSAPRE pre = new SSAPRE(cfg, context); pre.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("-------------After SSAPRE------------"); cfg.print(System.out); } } if (Main.FOLD) { if (Main.DEBUG) { System.out.println("--------Before Value Folding---------"); } if (Main.TRACE) { System.out.println(" Value Folding: " + Main.dateFormat.format(new Date())); } (new ValueFolding()).transform(cfg); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("---------After Value Folding---------"); cfg.print(System.out); } } if (Main.PROP) { if (Main.DEBUG) { System.out.println("-------Before Copy Propagation-------"); } if (Main.TRACE) { System.out.println(" Copy Propagation " + Main.dateFormat.format(new Date())); } final ExprPropagation copy = new ExprPropagation(cfg); copy.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("--------After Copy Propagation-------"); cfg.print(System.out); } } // make sure we've done at least one thing since the last DCE if (Main.DCE && (Main.INFER || Main.NUMBER || Main.FOLD || Main.PRE || Main.PROP)) { if (Main.DEBUG) { System.out.println("-----Before Dead Code Elimination----"); } if (Main.TRACE) { System.out.println(" Dead Code Elimination: " + Main.dateFormat.format(new Date())); } dce = new DeadCodeElimination(cfg); dce.transform(); if (Main.DEBUG) { cfg.visit(new VerifyCFG()); } if (Main.DEBUG) { System.out.println("-----After Dead Code Elimination-----"); cfg.print(System.out); } } if (Main.PERSIST) { (new PersistentCheckElimination()).transform(cfg); } if (Main.DIVA) { if (Main.DEBUG) { System.out.println("-----Before DIVA------"); } if (Main.TRACE) { System.out.println(" DIVA: " + Main.dateFormat.format(new Date())); } (new InductionVarAnalyzer()).transform(cfg); if (Main.DEBUG) { System.out.println("-----After DIVA-----"); cfg.print(System.out); } } /* * if (STACK_ALLOC) { if (DEBUG) { * System.out.println("------------Before StackPRE----------"); } * * StackPRE pre = new StackPRE(cfg); pre.transform(); * * if (DEBUG) { cfg.visit(new VerifyCFG()); } * * if (DEBUG) { System.out.println("------------After * StackPRE-----------"); cfg.print(System.out); } } */ // Do the new stack optimization if (Main.OPT_STACK_2) { if (Main.TRACE) { System.out.println(" New stack optimization: " + Main.dateFormat.format(new Date())); } // generate code without doing liveness or register allocation final CodeGenerator codegen = new CodeGenerator(m); codegen.replacePhis(cfg); m.clearCode2(); cfg.visit(codegen); // do stack optimization on the bytecode final StackOpt so = new StackOpt(); so.transform(m); // convert it back to a cfg cfg = new FlowGraph(m); cfg.initialize(); // convert it back to SSA SSA.transform(cfg); // do more dead code elimination (eliminate stores) dce = new DeadCodeElimination(cfg); dce.transform(); } if (Main.TRACE) { System.out.println(" Register allocation: " + Main.dateFormat.format(new Date())); } if (Main.VERIFY) { try { cfg.visit(new VerifyCFG()); } catch (final IllegalArgumentException ee) { System.out.println( " NOTE: CFG did not verify while " + "bloating " + m.name() + " after all optimizations. Exception: " + ee); } } // We're all done performing optimizations. Let's generate some code // and go home. // Perform liveness analysis of variables in the method. // Assign local variables ("registers") to expression values. final Liveness liveness = new Liveness(cfg); final RegisterAllocator alloc = new RegisterAllocator(cfg, liveness); // Gather information which can be used to optimize use of the stack if (CodeGenerator.OPT_STACK) { if (Main.TRACE) { System.out.println(" Old stack optimization: " + Main.dateFormat.format(new Date())); } StackOptimizer.optimizeCFG(cfg); } if (Main.TRACE) { System.out.println(" Code Generation: " + Main.dateFormat.format(new Date())); } // Start the code generation process. final CodeGenerator codegen = new CodeGenerator(m); codegen.replacePhis(cfg); if (Main.DEBUG) { System.out.println("After fixing Phis------------------------"); cfg.print(System.out); System.out.println("End print--------------------------------"); } codegen.simplifyControlFlow(cfg); codegen.allocReturnAddresses(cfg, alloc); if (Main.DEBUG) { System.out.println("After removing empty blocks--------------"); cfg.print(System.out); System.out.println("End print--------------------------------"); } // Clear the old contents of the bytecode store and generate new // code. // Code is generated using a visitor pattern on the CFG. m.clearCode(); cfg.visit(codegen); Peephole.transform(m); // Commit any changes that have been made to the method context.commit(m.methodInfo()); } catch (final Exception ex99) { final String msg = "** Exception while optimizing " + m.name() + m.type() + " of class " + m.declaringClass().name(); System.err.println(msg); System.err.println(ex99.getMessage()); ex99.printStackTrace(System.err); System.exit(1); } }
/** * Parse the command line. Inserts residency, update, and swizzle checks into the bytecode of the * methods of the specified classes. */ public static void main(final String[] args) { final ClassFileLoader loader = new ClassFileLoader(); List classes = new ArrayList(); // Names of classes from command line boolean gotdir = false; // Did user specify an output dir? for (int i = 0; i < args.length; i++) { if (args[i].equals("-v") || args[i].equals("-verbose")) { Main.VERBOSE++; } else if (args[i].equals("-help")) { Main.usage(); } else if (args[i].equals("-classpath")) { if (++i >= args.length) { Main.usage(); } final String classpath = args[i]; loader.setClassPath(classpath); } else if (args[i].equals("-skip")) { if (++i >= args.length) { Main.usage(); } final String pkg = args[i].replace('.', '/'); Main.SKIP.add(pkg); } else if (args[i].equals("-only")) { if (++i >= args.length) { Main.usage(); } final String pkg = args[i].replace('.', '/'); Main.ONLY.add(pkg); } else if (args[i].equals("-closure")) { Main.CLOSURE = true; } else if (args[i].equals("-relax-loading")) { ClassHierarchy.RELAX = true; } else if (args[i].equals("-f")) { Main.FORCE = true; } else if (args[i].equals("-norc")) { Main.RC = false; } else if (args[i].equals("-rc")) { Main.RC = true; } else if (args[i].equals("-nouc")) { Main.UC = false; } else if (args[i].equals("-uc")) { Main.UC = true; } else if (args[i].equals("-nosc")) { Main.SC = false; } else if (args[i].equals("-sc")) { Main.SC = true; } else if (args[i].startsWith("-")) { Main.usage(); } else if (i == args.length - 1) { // Last argument is the name of the outpu directory final File f = new File(args[i]); if (f.exists() && !f.isDirectory()) { System.err.println("No such directory: " + f.getPath()); System.exit(2); } loader.setOutputDir(f); gotdir = true; } else { classes.add(args[i]); } } if (!gotdir) { Main.usage(); } if (classes.size() == 0) { Main.usage(); } if (Main.VERBOSE > 3) { ClassFileLoader.DEBUG = true; ClassEditor.DEBUG = true; } boolean errors = false; final Iterator iter = classes.iterator(); // Load each class specified on the command line while (iter.hasNext()) { final String name = (String) iter.next(); try { loader.loadClass(name); } catch (final ClassNotFoundException ex) { System.err.println("Couldn't find class: " + ex.getMessage()); errors = true; } } if (errors) { System.exit(1); } final BloatContext context = new CachingBloatContext(loader, classes, Main.CLOSURE); if (!Main.CLOSURE) { final Iterator e = classes.iterator(); while (e.hasNext()) { final String name = (String) e.next(); try { final ClassInfo info = loader.loadClass(name); Main.decorateClass(context, info); } catch (final ClassNotFoundException ex) { System.err.println("Couldn't find class: " + ex.getMessage()); System.exit(1); } } } else { classes = null; final ClassHierarchy hier = context.getHierarchy(); final Iterator e = hier.classes().iterator(); while (e.hasNext()) { final Type t = (Type) e.next(); if (t.isObject()) { try { final ClassInfo info = loader.loadClass(t.className()); Main.decorateClass(context, info); } catch (final ClassNotFoundException ex) { System.err.println("Couldn't find class: " + ex.getMessage()); System.exit(1); } } } } }
/** * 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(); }
public static void main(final String[] args) { String CLASSPATH = null; String outputDirName = null; String lookIn = null; // Parse the command line for (int i = 0; i < args.length; i++) { if (args[i].equals("-trace")) { BloatBenchmark.TRACE = true; PersistentBloatContext.DB_COMMIT = true; } else if (args[i].equals("-calleeSize")) { if (++i >= args.length) { BloatBenchmark.err.println("** No callee size specified"); BloatBenchmark.usage(); } try { BloatBenchmark.CALLEE_SIZE = Integer.parseInt(args[i]); } catch (final NumberFormatException ex33) { BloatBenchmark.err.println("** Bad number: " + args[i]); BloatBenchmark.usage(); } } else if (args[i].startsWith("-classpath")) { if (++i >= args.length) { BloatBenchmark.err.println("** No classpath specified"); BloatBenchmark.usage(); } // If there is more than one -classpath append it to the // current one. That way the CLASSPATH reflects the order in // which the options came on the command line. if (CLASSPATH == null) { CLASSPATH = args[i]; } else { CLASSPATH += File.pathSeparator + args[i]; } } else if (args[i].equals("-no-stack-alloc")) { Main.STACK_ALLOC = false; } else if (args[i].equals("-peel-loops")) { if (++i >= args.length) { BloatBenchmark.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) { BloatBenchmark.usage(); } } catch (final NumberFormatException ex) { BloatBenchmark.usage(); } } } else if (args[i].equals("-no-color")) { Liveness.UNIQUE = true; } else if (args[i].equals("-no-dce")) { Main.DCE = false; } else if (args[i].equals("-no-prop")) { Main.PROP = false; } else if (args[i].equals("-no-pre")) { Main.PRE = false; } else if (args[i].equals("-no-check")) { BloatBenchmark.CHECK = false; } else if (args[i].equals("-depth")) { if (++i >= args.length) { BloatBenchmark.err.println("** No depth specified"); BloatBenchmark.usage(); } try { BloatBenchmark.DEPTH = Integer.parseInt(args[i]); } catch (final NumberFormatException ex33) { BloatBenchmark.err.println("** Bad number: " + args[i]); BloatBenchmark.usage(); } } else if (args[i].equals("-inline")) { // Inline calls to static methods BloatBenchmark.INLINE = true; } else if (args[i].equals("-intra")) { BloatBenchmark.INTRA = true; } else if (args[i].equals("-lookIn")) { if (++i >= args.length) { BloatBenchmark.err.println("** No directory specified"); BloatBenchmark.usage(); } if (lookIn != null) { lookIn += File.pathSeparator + args[i]; } else { lookIn = args[i]; } } else if (args[i].equals("-morph")) { if (++i >= args.length) { BloatBenchmark.err.println("** No morphosity specified"); BloatBenchmark.usage(); } try { BloatBenchmark.MORPH = Integer.parseInt(args[i]); } catch (final NumberFormatException ex33) { BloatBenchmark.err.println("** Bad number: " + args[i]); BloatBenchmark.usage(); } } else if (args[i].equals("-noinline")) { // Don't perform inlining, just specialize BloatBenchmark.INLINE = false; } else if (args[i].equals("-peephole")) { // Perform peephole optimizations when doing interprocedural // stuff BloatBenchmark.PEEPHOLE = true; } else if (args[i].equals("-size")) { if (++i >= args.length) { BloatBenchmark.err.println("** No size specified"); BloatBenchmark.usage(); } try { BloatBenchmark.SIZE = Integer.parseInt(args[i]); } catch (final NumberFormatException ex33) { BloatBenchmark.err.println("** Bad number: " + args[i]); BloatBenchmark.usage(); } } else if (args[i].equals("-specialize")) { // Specialize virtual method call sites BloatBenchmark.SPECIALIZE = true; } else if (args[i].equals("-stats")) { if (++i >= args.length) { BloatBenchmark.err.println("** No stats file specified"); BloatBenchmark.usage(); } BloatBenchmark.statsFile = args[i]; } else if (args[i].equals("-sun")) { // Optimize sun packages BloatBenchmark.SUN = true; } else if (args[i].equals("-times")) { BloatBenchmark.TIMES = true; if (++i >= args.length) { BloatBenchmark.err.println("** No times file specified"); BloatBenchmark.usage(); } BloatBenchmark.timesFile = args[i]; } else if (args[i].equals("-no-verify")) { BloatBenchmark.VERIFY = false; } else if (args[i].equals("-no-opt-stack")) { CodeGenerator.OPT_STACK = false; } else if (args[i].equals("-no-stack-vars")) { Tree.USE_STACK = false; } else if (args[i].equals("-skip")) { if (++i >= args.length) { BloatBenchmark.usage(); } String pkg = args[i]; // Account for class file name on command line if (pkg.endsWith(".class")) { pkg = pkg.substring(0, pkg.lastIndexOf('.')); } BloatBenchmark.SKIP.add(pkg.replace('.', '/')); } else if (args[i].equals("-1.1")) { // There are some classes that we don't want to be pre-live. // They don't exist in JDK1.1. BloatBenchmark.USE1_1 = true; CallGraph.USE1_2 = false; } else if (args[i].equals("-1.2")) { CallGraph.USE1_2 = true; if (lookIn != null) { lookIn += File.separator + "1.2"; } } else if (args[i].startsWith("-")) { BloatBenchmark.err.println("** Unrecognized option: " + args[i]); BloatBenchmark.usage(); } else if (i == args.length - 1) { outputDirName = args[i]; } else { BloatBenchmark.CLASSES.add(args[i]); } } if (BloatBenchmark.CLASSES.isEmpty()) { BloatBenchmark.err.println("** No classes specified"); BloatBenchmark.usage(); } if (outputDirName == null) { BloatBenchmark.err.println("** No output directory specified"); BloatBenchmark.usage(); } // Make sure the options the user entered make sense if (BloatBenchmark.CHECK) { BloatBenchmark.checkOptions(); } if (BloatBenchmark.USE1_1) { // Don't generate stats for 1.1 BloatBenchmark.statsFile = null; } if (lookIn != null) { CLASSPATH = lookIn + File.pathSeparator + CLASSPATH; } final StringBuffer sb = new StringBuffer(); for (int i = 0; i < args.length; i++) { sb.append(args[i] + " "); } BloatBenchmark.tr("BLOATing with command line: " + sb); BloatContext context = null; float systemStart = 0.0F; float systemDelta = 0.0F; float systemEnd = 0.0F; float systemTotal = 0.0F; float userStart = 0.0F; float userDelta = 0.0F; float userEnd = 0.0F; float userTotal = 0.0F; PrintWriter times = null; if (BloatBenchmark.TIMES) { try { times = new PrintWriter(new FileWriter(BloatBenchmark.timesFile), true); } catch (final IOException ex) { times = new PrintWriter(System.out, true); } } if (BloatBenchmark.INTRA) { BloatBenchmark.tr("Intraprocedural BLOAT"); // First compute the roots of the call graph. Figure out which // methods are live. context = BloatBenchmark.makeContext(CLASSPATH, null); final Collection liveMethods = BloatBenchmark.liveMethods(BloatBenchmark.CLASSES, context); // Run intraprocedural BLOAT on the live methods. BloatBenchmark.tr(liveMethods.size() + " live methods"); context = BloatBenchmark.makeContext(CLASSPATH, outputDirName); BloatBenchmark.intraBloat(liveMethods, context); } else { BloatBenchmark.tr("Interprocedural BLOAT"); if (BloatBenchmark.TIMES) { Times.snapshot(); systemStart = Times.systemTime(); userStart = Times.userTime(); } // Do the interprocedural BLOATing context = BloatBenchmark.makeContext(CLASSPATH, outputDirName); BloatBenchmark.liveMethods(BloatBenchmark.CLASSES, context); if (BloatBenchmark.TIMES) { // Take a measurement Times.snapshot(); systemEnd = Times.systemTime(); userEnd = Times.userTime(); systemDelta = systemEnd - systemStart; userDelta = userEnd - userStart; systemStart = systemEnd; userStart = userEnd; systemTotal += systemDelta; userTotal += userDelta; times.println("Call graph construction"); times.println(" User: "******" System: " + systemDelta); } if (BloatBenchmark.SPECIALIZE) { BloatBenchmark.specialize(context); } if (BloatBenchmark.TIMES) { // Take a measurement Times.snapshot(); systemEnd = Times.systemTime(); userEnd = Times.userTime(); systemDelta = systemEnd - systemStart; userDelta = userEnd - userStart; systemStart = systemEnd; userStart = userEnd; systemTotal += systemDelta; userTotal += userDelta; times.println("Call site specialization"); times.println(" User: "******" System: " + systemDelta); } if (BloatBenchmark.INLINE) { BloatBenchmark.inline(context); } if (BloatBenchmark.TIMES) { // Take a measurement Times.snapshot(); systemEnd = Times.systemTime(); userEnd = Times.userTime(); systemDelta = systemEnd - systemStart; userDelta = userEnd - userStart; systemStart = systemEnd; userStart = userEnd; systemTotal += systemDelta; userTotal += userDelta; times.println("Method inlining"); times.println(" User: "******" System: " + systemDelta); } if (BloatBenchmark.PEEPHOLE) { BloatBenchmark.peephole(context); } } // Commit dirty data BloatBenchmark.tr("Committing dirty methods"); context.commitDirty(); if (BloatBenchmark.TIMES) { // Take a measurement Times.snapshot(); systemEnd = Times.systemTime(); userEnd = Times.userTime(); systemDelta = systemEnd - systemStart; userDelta = userEnd - userStart; systemStart = systemEnd; userStart = userEnd; systemTotal += systemDelta; userTotal += userDelta; times.println("Committal"); times.println(" User: "******" System: " + systemDelta); } if (BloatBenchmark.TIMES) { times.println("Total"); times.println(" User: "******" System: " + systemTotal); } if (BloatBenchmark.statsFile != null) { final InlineStats stats = context.getInlineStats(); PrintWriter statsOut = null; try { statsOut = new PrintWriter(new FileWriter(BloatBenchmark.statsFile), true); } catch (final IOException ex) { statsOut = new PrintWriter(System.out, true); } stats.printSummary(statsOut); } BloatBenchmark.tr("Finished"); }