0001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
0002:
0003: This file is part of the db4o open source object database.
0004:
0005: db4o is free software; you can redistribute it and/or modify it under
0006: the terms of version 2 of the GNU General Public License as published
0007: by the Free Software Foundation and as clarified by db4objects' GPL
0008: interpretation policy, available at
0009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
0010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
0011: Suite 350, San Mateo, CA 94403, USA.
0012:
0013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
0014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: for more details.
0017:
0018: You should have received a copy of the GNU General Public License along
0019: with this program; if not, write to the Free Software Foundation, Inc.,
0020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
0021: package EDU.purdue.cs.bloat.optimize;
0022:
0023: import java.io.*;
0024: import java.text.*;
0025: import java.util.*;
0026:
0027: import EDU.purdue.cs.bloat.cfg.*;
0028: import EDU.purdue.cs.bloat.codegen.*;
0029: import EDU.purdue.cs.bloat.context.*;
0030: import EDU.purdue.cs.bloat.diva.*;
0031: import EDU.purdue.cs.bloat.editor.*;
0032: import EDU.purdue.cs.bloat.file.*;
0033: import EDU.purdue.cs.bloat.inline.*;
0034: import EDU.purdue.cs.bloat.reflect.*;
0035: import EDU.purdue.cs.bloat.ssa.*;
0036: import EDU.purdue.cs.bloat.tbaa.*;
0037: import EDU.purdue.cs.bloat.trans.*;
0038: import EDU.purdue.cs.bloat.tree.*;
0039:
0040: /**
0041: * Usage: java EDU.purdue.cs.bloat.optimize.Main [-options] classes dir
0042: *
0043: * where options include: -help print out this message -v -verbose turn on
0044: * verbose mode -debug display a hideous amount of debug info -classpath
0045: * <directories separated by colons> list directories in which to look for
0046: * classes -f optimize files even if up-to-date -closure recursively optimize
0047: * referenced classes -relax-loading don't report errors if a class is not found
0048: * -skip <class|package.*> skip the given class or package -only
0049: * <class|package.*> skip all but the given class or package -preserve-debug try
0050: * to preserve debug information -[no]anno insert an annotation in the contant
0051: * pool -[no]stack-alloc try to push locals onto the operand stack -peel-loops
0052: * <n|all> peel innermost loops to enable code hoisting (n >= 0 is the maximum
0053: * loop level to peel) -[no]pre perform partial redundency elimination
0054: * -[no]appre perform partial redundency elimination on access paths -[no]dce
0055: * perform dead code elimination -diva perform demand-driven induction variable
0056: * analysis -[no]prop perform copy and constant propagation
0057: *
0058: */
0059: public class Main {
0060: // Flags that can be set/unset from the command line
0061: static boolean DEBUG = false; // Display debugging information
0062:
0063: static boolean VERBOSE = false; // Display status information as program
0064: // runs
0065:
0066: public static boolean TRACE = false; // Track our progress
0067:
0068: static boolean FORCE = false; // Optimize file even if they are up-to-date
0069:
0070: static boolean CLOSURE = false; // Opimtize over entire heirarchy (i.e.
0071: // start
0072:
0073: // at the specified classes and recurse up the
0074: // class heirarchy)
0075:
0076: static DateFormat dateFormat = DateFormat.getDateTimeInstance(
0077: DateFormat.SHORT, DateFormat.LONG);
0078:
0079: static boolean DIVA = false;
0080:
0081: public static boolean PRE = true;
0082:
0083: public static boolean DCE = true;
0084:
0085: public static boolean PROP = true;
0086:
0087: public static boolean FOLD = true; // Value folding
0088:
0089: public static boolean INFER = true; // Type inference
0090:
0091: public static boolean NUMBER = true; // Value numbering
0092:
0093: public static boolean PERSIST = false; // Persistent check elimination
0094:
0095: public static boolean STACK_ALLOC = false;
0096:
0097: public static boolean COMPACT_ARRAY_INIT = true;
0098:
0099: static boolean ANNO = true; // Note that class file was optimized
0100:
0101: public static boolean VERIFY = true;
0102:
0103: public static boolean OPT_STACK_1 = false; // Perform stack optimizations
0104:
0105: public static boolean OPT_STACK_2 = false;
0106:
0107: static String[] ARGS = null; // Arguments from the command line
0108:
0109: public static List SKIP = new ArrayList(); // Classes that are specifically
0110: // not optimized
0111:
0112: static List ONLY = new ArrayList(); // Classes that are specifically
0113: // optimized
0114:
0115: static String METHOD = null; // The name of one method to edit
0116:
0117: static BloatContext context = null;
0118:
0119: static ClassFileLoader loader = null; // Used to load classes from class
0120:
0121: // files
0122:
0123: /**
0124: * Parses the command line. The user must specify at least one class to
0125: * optimize and the directory in which to place the optimized class files.
0126: * The methods of the specified classes are then optimized according to the
0127: * command line options.
0128: *
0129: * @see ClassEditor
0130: * @see ClassFileLoader
0131: * @see ClassFile
0132: * @see MethodEditor
0133: * @see MethodInfo
0134: *
0135: * @see CompactArrayInitializer
0136: * @see FlowGraph
0137: *
0138: */
0139: public static void main(final String[] args) {
0140: try {
0141: Main.loader = new ClassFileLoader();
0142:
0143: List classes = new ArrayList(args.length); // The classes to
0144: // optimize
0145: boolean gotdir = false; // Has an output directory been specified?
0146:
0147: Main.ARGS = args;
0148:
0149: for (int i = 0; i < args.length; i++) {
0150: if (args[i].equals("-v") || args[i].equals("-verbose")) {
0151: Main.VERBOSE = true;
0152: Main.loader.setVerbose(true);
0153:
0154: } else if (args[i].equals("-debug")) {
0155: Main.DEBUG = true;
0156: Main.loader.setVerbose(true);
0157: ClassFileLoader.DEBUG = true;
0158: CompactArrayInitializer.DEBUG = true;
0159: ClassEditor.DEBUG = true;
0160: FlowGraph.DEBUG = true;
0161: DominatorTree.DEBUG = true;
0162: Tree.DEBUG = true;
0163: CodeGenerator.DEBUG = true;
0164: Liveness.DEBUG = true;
0165: SSA.DEBUG = true;
0166: SSAGraph.DEBUG = true;
0167: PersistentCheckElimination.DEBUG = true;
0168: ValueNumbering.DEBUG = true;
0169: ValueFolding.DEBUG = true;
0170: ClassHierarchy.DEBUG = true;
0171: TypeInference.DEBUG = true;
0172: SSAPRE.DEBUG = true;
0173: StackPRE.DEBUG = true;
0174: ExprPropagation.DEBUG = true;
0175: DeadCodeElimination.DEBUG = true;
0176: CodeGenerator.DB_OPT_STACK = true;
0177:
0178: } else if (args[i].equals("-trace")) {
0179: Main.TRACE = true;
0180:
0181: } else if (args[i].equals("-db")) {
0182:
0183: if (++i >= args.length) {
0184: System.err
0185: .println("** No debugging option specified");
0186: Main.usage();
0187: }
0188:
0189: if (args[i].equals("bc")) {
0190: CodeArray.DEBUG = true;
0191:
0192: } else if (args[i].equals("cfg")) {
0193: FlowGraph.DEBUG = true;
0194:
0195: } else if (args[i].equals("ssa")) {
0196: SSA.DEBUG = true;
0197: SSAGraph.DEBUG = true;
0198:
0199: } else if (args[i].equals("graphs")) {
0200: FlowGraph.DB_GRAPHS = true;
0201:
0202: } else if (args[i].startsWith("-")) {
0203: i--;
0204:
0205: } else {
0206: System.err
0207: .println("** Unknown debugging option: "
0208: + args[i]);
0209: Main.usage();
0210: }
0211:
0212: } else if (args[i].equals("-debugvf")) {
0213: ValueFolding.DUMP = true;
0214:
0215: } else if (args[i].equals("-debugbc")) {
0216: BloatContext.DEBUG = true;
0217:
0218: } else if (args[i].equals("-help")) {
0219: Main.usage();
0220:
0221: } else if (args[i].equals("-noanno")) {
0222: Main.ANNO = false;
0223:
0224: } else if (args[i].equals("-anno")) {
0225: Main.ANNO = true;
0226:
0227: } else if (args[i].equals("-print-flow-graph")) {
0228: FlowGraph.PRINT_GRAPH = true;
0229:
0230: } else if (args[i].equals("-preserve-debug")) {
0231: MethodEditor.PRESERVE_DEBUG = true;
0232:
0233: } else if (args[i].equals("-nouse-stack-vars")) {
0234: Tree.USE_STACK = false;
0235:
0236: } else if (args[i].equals("-use-stack-vars")) {
0237: Tree.USE_STACK = true;
0238:
0239: } else if (args[i].equals("-unique-handlers")) {
0240: MethodEditor.UNIQUE_HANDLERS = true;
0241:
0242: } else if (args[i].equals("-nocompact-array-init")) {
0243: Main.COMPACT_ARRAY_INIT = false;
0244:
0245: } else if (args[i].equals("-compact-array-init")) {
0246: Main.COMPACT_ARRAY_INIT = true;
0247:
0248: } else if (args[i].equals("-nostack-alloc")) {
0249: Main.STACK_ALLOC = false;
0250:
0251: } else if (args[i].equals("-stack-alloc")) {
0252: Main.STACK_ALLOC = true;
0253:
0254: } else if (args[i].equals("-no-verify")) {
0255: Main.VERIFY = false;
0256:
0257: } else if (args[i].equals("-peel-loops")) {
0258: if (++i >= args.length) {
0259: Main.usage();
0260: }
0261:
0262: final String n = args[i];
0263:
0264: if (n.equals("all")) {
0265: FlowGraph.PEEL_LOOPS_LEVEL = FlowGraph.PEEL_ALL_LOOPS;
0266:
0267: } else {
0268: try {
0269: FlowGraph.PEEL_LOOPS_LEVEL = Integer
0270: .parseInt(n);
0271:
0272: if (FlowGraph.PEEL_LOOPS_LEVEL < 0) {
0273: Main.usage();
0274: }
0275: } catch (final NumberFormatException ex) {
0276: Main.usage();
0277: }
0278: }
0279:
0280: } else if (args[i].equals("-color")) {
0281: Liveness.UNIQUE = false;
0282:
0283: } else if (args[i].equals("-nocolor")) {
0284: Liveness.UNIQUE = true;
0285:
0286: } else if (args[i].equals("-only-method")) {
0287: if (++i >= args.length) {
0288: Main.usage();
0289: }
0290:
0291: Main.METHOD = args[i];
0292:
0293: } else if (args[i].equals("-classpath")) {
0294: if (++i >= args.length) {
0295: Main.usage();
0296: }
0297:
0298: final String classpath = args[i];
0299: Main.loader.setClassPath(classpath);
0300:
0301: } else if (args[i].equals("-classpath/p")) {
0302: if (++i >= args.length) {
0303: Main.usage();
0304: }
0305:
0306: final String classpath = args[i];
0307: Main.loader.prependClassPath(classpath);
0308:
0309: } else if (args[i].equals("-skip")) {
0310: if (++i >= args.length) {
0311: Main.usage();
0312: }
0313:
0314: String pkg = args[i];
0315:
0316: // Account for class file name on command line
0317: if (pkg.endsWith(".class")) {
0318: pkg = pkg.substring(0, pkg.lastIndexOf('.'));
0319: }
0320:
0321: Main.SKIP.add(pkg.replace('.', '/'));
0322:
0323: } else if (args[i].equals("-only")) {
0324: if (++i >= args.length) {
0325: Main.usage();
0326: }
0327:
0328: String pkg = args[i];
0329:
0330: // Account for class file name on command line
0331: if (pkg.endsWith(".class")) {
0332: pkg = pkg.substring(0, pkg.lastIndexOf('.'));
0333: }
0334:
0335: Main.ONLY.add(pkg.replace('.', '/'));
0336:
0337: } else if (args[i].equals("-nodce")) {
0338: Main.DCE = false;
0339:
0340: } else if (args[i].equals("-noprop")) {
0341: Main.PROP = false;
0342:
0343: } else if (args[i].equals("-noappre")) {
0344: SSAPRE.NO_ACCESS_PATHS = true;
0345:
0346: } else if (args[i].equals("-nopre")) {
0347: Main.PRE = false;
0348:
0349: } else if (args[i].equals("-dce")) {
0350: Main.DCE = true;
0351:
0352: } else if (args[i].equals("-prop")) {
0353: Main.PROP = true;
0354:
0355: } else if (args[i].equals("-appre")) {
0356: SSAPRE.NO_ACCESS_PATHS = false;
0357:
0358: } else if (args[i].equals("-pre")) {
0359: Main.PRE = true;
0360:
0361: } else if (args[i].equals("-closure")) {
0362: Main.CLOSURE = true;
0363:
0364: } else if (args[i].equals("-opt-stack-1")) {
0365: Main.OPT_STACK_1 = true;
0366: CodeGenerator.OPT_STACK = true;
0367:
0368: } else if (args[i].equals("-opt-stack-2")) {
0369: Main.OPT_STACK_2 = true;
0370: MethodEditor.OPT_STACK_2 = true;
0371:
0372: } else if (args[i].equals("-diva")) {
0373: Main.DIVA = true;
0374:
0375: } else if (args[i].equals("-no-thread")) {
0376: SSAPRE.NO_THREAD = true;
0377:
0378: } else if (args[i].equals("-no-precise")) {
0379: SSAPRE.NO_PRECISE = true;
0380:
0381: } else if (args[i].equals("-relax-loading")) {
0382: ClassHierarchy.RELAX = true;
0383:
0384: } else if (args[i].equals("-f")
0385: || args[i].equals("-force")) {
0386: Main.FORCE = true;
0387:
0388: } else if (args[i].startsWith("-")) {
0389: System.err.println("No such option: " + args[i]);
0390: Main.usage();
0391:
0392: } else if (i == args.length - 1) {
0393: // Last argument is the name of the output directory
0394:
0395: final File f = new File(args[i]);
0396:
0397: if (f.exists() && !f.isDirectory()) {
0398: System.err.println("No such directory: "
0399: + f.getPath());
0400: System.exit(2);
0401: }
0402:
0403: if (!f.exists()) {
0404: f.mkdirs();
0405: }
0406:
0407: if (!f.exists()) {
0408: System.err
0409: .println("Couldn't create directory: "
0410: + f.getPath());
0411: System.exit(2);
0412: }
0413:
0414: // Tell class loader to put optimized classes in f directory
0415: Main.loader.setOutputDir(f);
0416: gotdir = true;
0417: } else {
0418: // The argument must be a class name...
0419: classes.add(args[i]);
0420: }
0421: }
0422:
0423: if (!gotdir) {
0424: System.err.println("No output directory specified");
0425: Main.usage();
0426: }
0427:
0428: if (classes.size() == 0) {
0429: System.err.println("** No classes specified");
0430: Main.usage();
0431: }
0432:
0433: // Use the CachingBloatingContext
0434: Main.context = new CachingBloatContext(Main.loader,
0435: classes, Main.CLOSURE);
0436:
0437: boolean errors = false;
0438:
0439: final Iterator iter = classes.iterator();
0440:
0441: // Now that we've parsed the command line, load the classes into the
0442: // class loader
0443: while (iter.hasNext()) {
0444: final String name = (String) iter.next();
0445:
0446: try {
0447: Main.context.loadClass(name);
0448:
0449: } catch (final ClassNotFoundException ex) {
0450: System.err.println("Couldn't find class: "
0451: + ex.getMessage());
0452:
0453: errors = true;
0454: }
0455: }
0456:
0457: if (errors) {
0458: System.exit(1);
0459: }
0460:
0461: if (!Main.CLOSURE) {
0462: final Iterator e = classes.iterator();
0463:
0464: // Edit only the classes that were specified on the command line
0465:
0466: while (e.hasNext()) {
0467: final String name = (String) e.next();
0468: Main.editClass(name);
0469: }
0470: } else {
0471: // Edit all the classes in the class file editor and their
0472: // superclasses
0473:
0474: classes = null;
0475:
0476: if (Main.TRACE) {
0477: System.out.println("Computing closure "
0478: + Main.dateFormat.format(new Date()));
0479: }
0480:
0481: final Iterator e = Main.context.getHierarchy()
0482: .classes().iterator();
0483:
0484: while (e.hasNext()) {
0485: final Type t = (Type) e.next();
0486:
0487: if (t.isObject()) {
0488: Main.editClass(t.className());
0489: }
0490: }
0491: }
0492: } catch (final ExceptionInInitializerError ex) {
0493: ex.printStackTrace();
0494: System.out.println(ex.getException());
0495: }
0496: }
0497:
0498: private static void usage() {
0499: System.err
0500: .println("\nUsage: java EDU.purdue.cs.bloat.optimize.Main"
0501: + "\n [-options] classes dir"
0502: + "\n"
0503: + "\nwhere options include:"
0504: + "\n -help print out this message"
0505: + "\n -v -verbose turn on verbose mode"
0506: + "\n -debug display a hideous amount of debug info"
0507: + "\n -classpath <directories separated by colons>"
0508: + "\n list directories in which to look for classes"
0509: + "\n -f optimize files even if up-to-date"
0510: + "\n -closure recursively optimize referenced classes"
0511: + "\n -relax-loading don't report errors if a class is not found"
0512: + "\n -skip <class|package.*>"
0513: + "\n skip the given class or package"
0514: + "\n -only <class|package.*>"
0515: + "\n skip all but the given class or package"
0516: + "\n -preserve-debug try to preserve debug information"
0517: + "\n -[no]anno insert an annotation in the contant pool"
0518: + "\n -[no]stack-alloc try to push locals onto the operand stack"
0519: + "\n -peel-loops <n|all>"
0520: + "\n peel innermost loops to enable code hoisting"
0521: + "\n (n >= 0 is the maximum loop level to peel)"
0522: + "\n -[no]pre perform partial redundency elimination"
0523: + "\n -[no]dce perform dead code elimination"
0524: + "\n -diva perform demand-driven induction variable analysis"
0525: + "\n -[no]prop perform copy and constant propagation"
0526: + "");
0527: System.exit(0);
0528: }
0529:
0530: /**
0531: * Performs the actual editing of a class. Does a whole mess of stuff
0532: * including reading in the classfile, building data structures to represent
0533: * the class file, converting the CFG for each method in the class into SSA
0534: * form, perform some anlayses and optimizations on the method, and finally
0535: * committing it back to the class file. Phew.
0536: */
0537: private static void editClass(final String className) {
0538: ClassFile classFile; // Holds info about a class (implements
0539: // ClassInfo)
0540:
0541: // Get information about the class className
0542: try {
0543: classFile = (ClassFile) Main.context.loadClass(className);
0544: } catch (final ClassNotFoundException ex) {
0545: System.err.println("** Couldn't find class: "
0546: + ex.getMessage());
0547: return;
0548: }
0549:
0550: if (!Main.FORCE) {
0551: // Check to see if the file is up-to-date (i.e. has been
0552: // recompiled since it was last optimized). If so, do nothing
0553: // because the FORCE flag is false.
0554:
0555: final File source = classFile.file();
0556: final File target = classFile.outputFile();
0557:
0558: if ((source != null) && (target != null) && source.exists()
0559: && target.exists()
0560: && (source.lastModified() < target.lastModified())) {
0561:
0562: if (Main.VERBOSE) {
0563: System.out.println(classFile.name()
0564: + " is up to date");
0565: }
0566:
0567: return;
0568: }
0569: }
0570:
0571: if (Main.DEBUG) {
0572: // Print the contents of the class file to System.out
0573: classFile.print(System.out);
0574: }
0575:
0576: final ClassEditor c = Main.context.editClass(classFile);
0577:
0578: boolean skip = false;
0579:
0580: final String name = c.type().className();
0581: final String qual = c.type().qualifier() + "/*";
0582:
0583: // Edit only classes explicitly mentioned.
0584: if (Main.ONLY.size() > 0) {
0585: skip = true;
0586:
0587: // Only edit classes we explicitly don't name.
0588: for (int i = 0; i < Main.ONLY.size(); i++) {
0589: final String pkg = (String) Main.ONLY.get(i);
0590:
0591: if (name.equals(pkg) || qual.equals(pkg)) {
0592: skip = false;
0593: break;
0594: }
0595: }
0596: }
0597:
0598: // Don't edit classes we explicitly skip.
0599: if (!skip) {
0600: for (int i = 0; i < Main.SKIP.size(); i++) {
0601: final String pkg = (String) Main.SKIP.get(i);
0602:
0603: if (name.equals(pkg) || qual.equals(pkg)) {
0604: skip = true;
0605: break;
0606: }
0607: }
0608: }
0609:
0610: if (skip) {
0611: if (Main.VERBOSE) {
0612: System.out.println("Skipping " + c.type().className());
0613: }
0614:
0615: // We're done with this class file, decrement its reference count
0616: Main.context.release(classFile);
0617: return;
0618: }
0619:
0620: // Touch the output file first. That is, create the file, but make
0621: // it empty, just to make sure we can create it.
0622:
0623: try {
0624: final File f = classFile.outputFile();
0625:
0626: if (f.exists()) {
0627: f.delete();
0628: }
0629:
0630: final File dir = new File(f.getParent());
0631: dir.mkdirs();
0632:
0633: if (!dir.exists()) {
0634: throw new RuntimeException(
0635: "Couldn't create directory: " + dir);
0636: }
0637:
0638: final DataOutputStream out = new DataOutputStream(
0639: new FileOutputStream(f));
0640: new PrintStream(out).println();
0641: out.close();
0642: } catch (final IOException e) {
0643: e.printStackTrace();
0644: System.exit(1);
0645: }
0646:
0647: if (Main.VERBOSE) {
0648: System.out.println("Optimizing " + c.type().className());
0649: }
0650:
0651: // Finally, we can start playing with the methods...
0652: final MethodInfo[] methods = c.methods();
0653:
0654: final int numMethods = methods.length + 1;
0655: ;
0656: int whichMethod = 0;
0657:
0658: for (int j = 0; j < methods.length; j++) {
0659: final MethodEditor m;
0660:
0661: try {
0662: m = Main.context.editMethod(methods[j]);
0663: } catch (final ClassFormatException ex) {
0664: System.err.println(ex.getMessage());
0665: continue;
0666: }
0667:
0668: if (Main.TRACE) {
0669: whichMethod++;
0670: System.out.println("Optimizing " + name + "."
0671: + m.name() + " (method " + whichMethod + " of "
0672: + numMethods + ")");
0673: }
0674:
0675: if (Main.METHOD != null) {
0676: // A method name has been specified on the command line using
0677: // -only-method.
0678: boolean pass = true;
0679:
0680: String t = m.name() + m.type();
0681:
0682: if (t.equals(Main.METHOD)) {
0683: pass = false;
0684: }
0685:
0686: t = m.name();
0687:
0688: if (t.equals(Main.METHOD)) {
0689: pass = false;
0690: }
0691:
0692: if (pass) {
0693: // This isn't the method we're looking for.
0694: // Decrement its reference count.
0695: Main.context.release(methods[j]);
0696: continue;
0697: }
0698: }
0699:
0700: if (Main.DEBUG) {
0701: m.print(System.out);
0702: }
0703:
0704: if (m.isNative() || m.isAbstract()) {
0705: // We can't edit native or abstract methods
0706: Main.context.release(methods[j]);
0707: continue;
0708: }
0709:
0710: Main.bloatMethod(m, Main.context);
0711: }
0712:
0713: if (Main.ANNO) {
0714: String s = "Optimized with: EDU.purdue.cs.bloat.optimize.Main";
0715:
0716: for (int i = 0; i < Main.ARGS.length; i++) {
0717: if ((Main.ARGS[i].indexOf(' ') >= 0)
0718: || (Main.ARGS[i].indexOf('\t') >= 0)
0719: || (Main.ARGS[i].indexOf('\r') >= 0)
0720: || (Main.ARGS[i].indexOf('\n') >= 0)) {
0721: s += " '" + Main.ARGS[i] + "'";
0722: } else {
0723: s += " " + Main.ARGS[i];
0724: }
0725: }
0726:
0727: System.out.println(s);
0728: // c.constants().addConstant(Constant.UTF8, s);
0729: }
0730:
0731: Main.context.commit(classFile);
0732: Main.context.release(classFile);
0733:
0734: if (Main.TRACE) {
0735: System.out.println(Main.context.toString());
0736: }
0737: }
0738:
0739: /**
0740: * Runs BLOAT on a method.
0741: */
0742: public static void bloatMethod(final MethodEditor m,
0743: final BloatContext context) {
0744: try {
0745: if (Main.COMPACT_ARRAY_INIT) {
0746: // Compact the initialization of arrays of the basic types by
0747: // putting the values of the array into a string in the constant
0748: // pool. The initialization code is replaced with a loop that
0749: // loads the array from the string in the constant pool.
0750:
0751: if (Main.TRACE) {
0752: System.out.println(" Compacting Arrays: "
0753: + Main.dateFormat.format(new Date()));
0754: }
0755:
0756: CompactArrayInitializer.transform(m);
0757:
0758: if (Main.DEBUG) {
0759: System.out.println("---------- After compaction:");
0760: m.print(System.out);
0761: System.out.println("---------- end print");
0762: }
0763: }
0764:
0765: FlowGraph cfg; // The control flow graph for a method
0766:
0767: if (Main.TRACE) {
0768: System.out.println(" Constructing CFG: "
0769: + Main.dateFormat.format(new Date()));
0770: }
0771:
0772: try {
0773: // Construct the control flow graph for method m
0774: cfg = new FlowGraph(m);
0775: } catch (final ClassFormatException ex) {
0776: System.err.println(ex.getMessage());
0777: context.release(m.methodInfo());
0778: return;
0779: }
0780:
0781: // We separate out initialization since before this the FlowGraph
0782: // more exactly represents the input program.
0783: cfg.initialize();
0784:
0785: if (Main.TRACE) {
0786: System.out.println(" Transforming to SSA: "
0787: + Main.dateFormat.format(new Date()));
0788: }
0789:
0790: SSA.transform(cfg);
0791:
0792: if (FlowGraph.DEBUG) {
0793: System.out.println("---------- After SSA:");
0794: cfg.print(System.out);
0795: System.out.println("---------- end print");
0796: }
0797:
0798: if (Main.DEBUG) {
0799: cfg.visit(new VerifyCFG(false));
0800: }
0801:
0802: if (!Tree.USE_STACK) {
0803: // Do copy propagation and value numbering first to get rid of
0804: // all the extra copies inserted for dups. If they're left in,
0805: // it really slows down value numbering.
0806: if (Main.PROP) {
0807: if (Main.DEBUG) {
0808: System.out
0809: .println("-----Before Copy Propagation-----");
0810: }
0811:
0812: if (Main.TRACE) {
0813: System.out.println(" Copy propagation: "
0814: + Main.dateFormat.format(new Date()));
0815: }
0816:
0817: final ExprPropagation copy = new ExprPropagation(
0818: cfg);
0819: copy.transform();
0820:
0821: if (Main.DEBUG) {
0822: cfg.visit(new VerifyCFG(false));
0823: }
0824:
0825: if (Main.DEBUG) {
0826: System.out
0827: .println("------After Copy Propagation-----");
0828: cfg.print(System.out);
0829: }
0830: }
0831: }
0832:
0833: DeadCodeElimination dce = null;
0834:
0835: if (Main.DCE) {
0836:
0837: if (Main.TRACE) {
0838: System.out.println(" Dead Code Elimination: "
0839: + Main.dateFormat.format(new Date()));
0840: }
0841:
0842: if (Main.DEBUG) {
0843: System.out
0844: .println("---Before Dead Code Elimination--");
0845: }
0846:
0847: dce = new DeadCodeElimination(cfg);
0848: dce.transform();
0849:
0850: if (Main.DEBUG) {
0851: cfg.visit(new VerifyCFG(false));
0852: }
0853:
0854: if (Main.DEBUG) {
0855: System.out
0856: .println("---After Dead Code Elimination---");
0857: cfg.print(System.out);
0858: }
0859: }
0860:
0861: if (Main.INFER) {
0862:
0863: if (Main.DEBUG) {
0864: System.out
0865: .println("---------Doing type inference--------");
0866: }
0867:
0868: if (Main.TRACE) {
0869: System.out.println(" Type Inferencing: "
0870: + Main.dateFormat.format(new Date()));
0871: }
0872:
0873: TypeInference.transform(cfg, context.getHierarchy());
0874: }
0875:
0876: if (Main.NUMBER) {
0877:
0878: if (Main.TRACE) {
0879: System.out.println(" Value Numbering: "
0880: + Main.dateFormat.format(new Date()));
0881: }
0882:
0883: if (Main.DEBUG) {
0884: System.out
0885: .println("--------Doing value numbering--------");
0886: }
0887:
0888: (new ValueNumbering()).transform(cfg);
0889: }
0890:
0891: if (Main.FOLD) {
0892: if (Main.DEBUG) {
0893: System.out
0894: .println("--------Before Value Folding---------");
0895: }
0896:
0897: if (Main.TRACE) {
0898: System.out.println(" Value Folding: "
0899: + Main.dateFormat.format(new Date()));
0900: }
0901:
0902: (new ValueFolding()).transform(cfg);
0903:
0904: if (Main.DEBUG) {
0905: cfg.visit(new VerifyCFG());
0906: }
0907:
0908: if (Main.DEBUG) {
0909: System.out
0910: .println("---------After Value Folding---------");
0911: cfg.print(System.out);
0912: }
0913:
0914: }
0915:
0916: if (Main.PRE) {
0917: if (Main.DEBUG) {
0918: System.out
0919: .println("-------------Before SSAPRE-----------");
0920: }
0921:
0922: if (Main.TRACE) {
0923: System.out.println(" SSAPRE: "
0924: + Main.dateFormat.format(new Date()));
0925: }
0926:
0927: final SSAPRE pre = new SSAPRE(cfg, context);
0928: pre.transform();
0929:
0930: if (Main.DEBUG) {
0931: cfg.visit(new VerifyCFG());
0932: }
0933:
0934: if (Main.DEBUG) {
0935: System.out
0936: .println("-------------After SSAPRE------------");
0937: cfg.print(System.out);
0938: }
0939: }
0940:
0941: if (Main.FOLD) {
0942: if (Main.DEBUG) {
0943: System.out
0944: .println("--------Before Value Folding---------");
0945: }
0946:
0947: if (Main.TRACE) {
0948: System.out.println(" Value Folding: "
0949: + Main.dateFormat.format(new Date()));
0950: }
0951:
0952: (new ValueFolding()).transform(cfg);
0953:
0954: if (Main.DEBUG) {
0955: cfg.visit(new VerifyCFG());
0956: }
0957:
0958: if (Main.DEBUG) {
0959: System.out
0960: .println("---------After Value Folding---------");
0961: cfg.print(System.out);
0962: }
0963:
0964: }
0965:
0966: if (Main.PROP) {
0967: if (Main.DEBUG) {
0968: System.out
0969: .println("-------Before Copy Propagation-------");
0970: }
0971:
0972: if (Main.TRACE) {
0973: System.out.println(" Copy Propagation "
0974: + Main.dateFormat.format(new Date()));
0975: }
0976:
0977: final ExprPropagation copy = new ExprPropagation(cfg);
0978: copy.transform();
0979:
0980: if (Main.DEBUG) {
0981: cfg.visit(new VerifyCFG());
0982: }
0983:
0984: if (Main.DEBUG) {
0985: System.out
0986: .println("--------After Copy Propagation-------");
0987: cfg.print(System.out);
0988: }
0989: }
0990:
0991: // make sure we've done at least one thing since the last DCE
0992: if (Main.DCE
0993: && (Main.INFER || Main.NUMBER || Main.FOLD
0994: || Main.PRE || Main.PROP)) {
0995: if (Main.DEBUG) {
0996: System.out
0997: .println("-----Before Dead Code Elimination----");
0998: }
0999:
1000: if (Main.TRACE) {
1001: System.out.println(" Dead Code Elimination: "
1002: + Main.dateFormat.format(new Date()));
1003: }
1004:
1005: dce = new DeadCodeElimination(cfg);
1006: dce.transform();
1007:
1008: if (Main.DEBUG) {
1009: cfg.visit(new VerifyCFG());
1010: }
1011:
1012: if (Main.DEBUG) {
1013: System.out
1014: .println("-----After Dead Code Elimination-----");
1015: cfg.print(System.out);
1016: }
1017: }
1018:
1019: if (Main.PERSIST) {
1020: (new PersistentCheckElimination()).transform(cfg);
1021: }
1022:
1023: if (Main.DIVA) {
1024: if (Main.DEBUG) {
1025: System.out.println("-----Before DIVA------");
1026: }
1027:
1028: if (Main.TRACE) {
1029: System.out.println(" DIVA: "
1030: + Main.dateFormat.format(new Date()));
1031: }
1032:
1033: (new InductionVarAnalyzer()).transform(cfg);
1034:
1035: if (Main.DEBUG) {
1036: System.out.println("-----After DIVA-----");
1037: cfg.print(System.out);
1038: }
1039:
1040: }
1041:
1042: /*
1043: * if (STACK_ALLOC) { if (DEBUG) {
1044: * System.out.println("------------Before StackPRE----------"); }
1045: *
1046: * StackPRE pre = new StackPRE(cfg); pre.transform();
1047: *
1048: * if (DEBUG) { cfg.visit(new VerifyCFG()); }
1049: *
1050: * if (DEBUG) { System.out.println("------------After
1051: * StackPRE-----------"); cfg.print(System.out); } }
1052: */
1053:
1054: // Do the new stack optimization
1055: if (Main.OPT_STACK_2) {
1056:
1057: if (Main.TRACE) {
1058: System.out.println(" New stack optimization: "
1059: + Main.dateFormat.format(new Date()));
1060: }
1061:
1062: // generate code without doing liveness or register allocation
1063: final CodeGenerator codegen = new CodeGenerator(m);
1064: codegen.replacePhis(cfg);
1065: m.clearCode2();
1066: cfg.visit(codegen);
1067: // do stack optimization on the bytecode
1068:
1069: final StackOpt so = new StackOpt();
1070: so.transform(m);
1071:
1072: // convert it back to a cfg
1073: cfg = new FlowGraph(m);
1074: cfg.initialize();
1075:
1076: // convert it back to SSA
1077: SSA.transform(cfg);
1078:
1079: // do more dead code elimination (eliminate stores)
1080: dce = new DeadCodeElimination(cfg);
1081: dce.transform();
1082: }
1083:
1084: if (Main.TRACE) {
1085: System.out.println(" Register allocation: "
1086: + Main.dateFormat.format(new Date()));
1087: }
1088:
1089: if (Main.VERIFY) {
1090: try {
1091: cfg.visit(new VerifyCFG());
1092: } catch (final IllegalArgumentException ee) {
1093: System.out
1094: .println(" NOTE: CFG did not verify while "
1095: + "bloating "
1096: + m.name()
1097: + " after all optimizations. Exception: "
1098: + ee);
1099: }
1100: }
1101:
1102: // We're all done performing optimizations. Let's generate some code
1103: // and go home.
1104:
1105: // Perform liveness analysis of variables in the method.
1106: // Assign local variables ("registers") to expression values.
1107: final Liveness liveness = new Liveness(cfg);
1108: final RegisterAllocator alloc = new RegisterAllocator(cfg,
1109: liveness);
1110:
1111: // Gather information which can be used to optimize use of the stack
1112: if (CodeGenerator.OPT_STACK) {
1113: if (Main.TRACE) {
1114: System.out.println(" Old stack optimization: "
1115: + Main.dateFormat.format(new Date()));
1116: }
1117: StackOptimizer.optimizeCFG(cfg);
1118: }
1119:
1120: if (Main.TRACE) {
1121: System.out.println(" Code Generation: "
1122: + Main.dateFormat.format(new Date()));
1123: }
1124:
1125: // Start the code generation process.
1126: final CodeGenerator codegen = new CodeGenerator(m);
1127: codegen.replacePhis(cfg);
1128:
1129: if (Main.DEBUG) {
1130: System.out
1131: .println("After fixing Phis------------------------");
1132: cfg.print(System.out);
1133: System.out
1134: .println("End print--------------------------------");
1135: }
1136:
1137: codegen.simplifyControlFlow(cfg);
1138: codegen.allocReturnAddresses(cfg, alloc);
1139:
1140: if (Main.DEBUG) {
1141: System.out
1142: .println("After removing empty blocks--------------");
1143: cfg.print(System.out);
1144: System.out
1145: .println("End print--------------------------------");
1146: }
1147:
1148: // Clear the old contents of the bytecode store and generate new
1149: // code.
1150: // Code is generated using a visitor pattern on the CFG.
1151: m.clearCode();
1152: cfg.visit(codegen);
1153:
1154: Peephole.transform(m);
1155:
1156: // Commit any changes that have been made to the method
1157: context.commit(m.methodInfo());
1158:
1159: } catch (final Exception ex99) {
1160: final String msg = "** Exception while optimizing "
1161: + m.name() + m.type() + " of class "
1162: + m.declaringClass().name();
1163: System.err.println(msg);
1164: System.err.println(ex99.getMessage());
1165: ex99.printStackTrace(System.err);
1166: System.exit(1);
1167: }
1168: }
1169:
1170: public static void dumpcode(final MethodEditor m) {
1171:
1172: final PrintWriter out = new PrintWriter(System.out, true);
1173: final StackHeightCounter shc = new StackHeightCounter(m);
1174:
1175: out.println("Code for method " + m.name() + m.type());
1176: final List instructions = m.code();
1177: final ListIterator iter = instructions.listIterator();
1178: while (iter.hasNext()) {
1179: final Object obj = iter.next();
1180: if (obj instanceof Label) {
1181: shc.handle((Label) obj);
1182: } else if (obj instanceof Instruction) {
1183: shc.handle((Instruction) obj);
1184: }
1185:
1186: System.out.println(" " + obj + " (sh: "
1187: + shc.height() + ")");
1188: }
1189: }
1190:
1191: }
|