001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.diva;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import EDU.purdue.cs.bloat.cfg.*;
027: import EDU.purdue.cs.bloat.codegen.*;
028: import EDU.purdue.cs.bloat.context.*;
029: import EDU.purdue.cs.bloat.editor.*;
030: import EDU.purdue.cs.bloat.file.*;
031: import EDU.purdue.cs.bloat.reflect.*;
032: import EDU.purdue.cs.bloat.ssa.*;
033: import EDU.purdue.cs.bloat.tbaa.*;
034: import EDU.purdue.cs.bloat.trans.*;
035: import EDU.purdue.cs.bloat.tree.*;
036:
037: /**
038: * Performs a number of analyses on the methods of some specified classes.
039: * However, it does not perform some of the optimizations that optimize.Main
040: * does.
041: *
042: * @see EDU.purdue.cs.bloat.optimize.Main
043: */
044: public class Main {
045: static boolean DEBUG = false;
046:
047: static boolean VERBOSE = false;
048:
049: static boolean FORCE = false;
050:
051: static boolean CLOSURE = false;
052:
053: static boolean PRE = true;
054:
055: static boolean DCE = true;
056:
057: static boolean PROP = true;
058:
059: static boolean FOLD = true;
060:
061: static boolean STACK_ALLOC = false;
062:
063: static boolean COMPACT_ARRAY_INIT = true;
064:
065: static boolean ANNO = true;
066:
067: static String[] ARGS = null;
068:
069: static List SKIP = new ArrayList();
070:
071: static List ONLY = new ArrayList();
072:
073: static String METHOD = null;
074:
075: static BloatContext context = null;
076:
077: static ClassFileLoader loader = null;
078:
079: public static void main(final String[] args) {
080: try {
081: Main.loader = new ClassFileLoader();
082:
083: List classes = new ArrayList(args.length);
084: boolean gotdir = false;
085:
086: Main.ARGS = args;
087:
088: for (int i = 0; i < args.length; i++) {
089: if (args[i].equals("-v") || args[i].equals("-verbose")) {
090: Main.VERBOSE = true;
091: Main.loader.setVerbose(true);
092: } else if (args[i].equals("-debug")) {
093: Main.DEBUG = true;
094: Main.loader.setVerbose(true);
095: ClassFileLoader.DEBUG = true;
096: CompactArrayInitializer.DEBUG = true;
097: ClassEditor.DEBUG = true;
098: FlowGraph.DEBUG = true;
099: DominatorTree.DEBUG = true;
100: Tree.DEBUG = true;
101: CodeGenerator.DEBUG = true;
102: Liveness.DEBUG = true;
103: SSA.DEBUG = true;
104: SSAGraph.DEBUG = true;
105: PersistentCheckElimination.DEBUG = true;
106: ValueNumbering.DEBUG = true;
107: ValueFolding.DEBUG = true;
108: ClassHierarchy.DEBUG = true;
109: TypeInference.DEBUG = true;
110: SSAPRE.DEBUG = true;
111: StackPRE.DEBUG = true;
112: ExprPropagation.DEBUG = true;
113: DeadCodeElimination.DEBUG = true;
114: } else if (args[i].equals("-help")) {
115: Main.usage();
116: } else if (args[i].equals("-noanno")) {
117: Main.ANNO = false;
118: } else if (args[i].equals("-anno")) {
119: Main.ANNO = true;
120: } else if (args[i].equals("-preserve-debug")) {
121: MethodEditor.PRESERVE_DEBUG = true;
122: } else if (args[i].equals("-nouse-stack-vars")) {
123: Tree.USE_STACK = false;
124: } else if (args[i].equals("-use-stack-vars")) {
125: Tree.USE_STACK = true;
126: } else if (args[i].equals("-nocompact-array-init")) {
127: Main.COMPACT_ARRAY_INIT = false;
128: } else if (args[i].equals("-compact-array-init")) {
129: Main.COMPACT_ARRAY_INIT = true;
130: } else if (args[i].equals("-nostack-alloc")) {
131: Main.STACK_ALLOC = false;
132: } else if (args[i].equals("-stack-alloc")) {
133: Main.STACK_ALLOC = true;
134: } else if (args[i].equals("-peel-loops")) {
135: if (++i >= args.length) {
136: Main.usage();
137: }
138:
139: final String n = args[i];
140:
141: if (n.equals("all")) {
142: FlowGraph.PEEL_LOOPS_LEVEL = FlowGraph.PEEL_ALL_LOOPS;
143: } else {
144: try {
145: FlowGraph.PEEL_LOOPS_LEVEL = Integer
146: .parseInt(n);
147:
148: if (FlowGraph.PEEL_LOOPS_LEVEL < 0) {
149: Main.usage();
150: }
151: } catch (final NumberFormatException ex) {
152: Main.usage();
153: }
154: }
155: } else if (args[i].equals("-color")) {
156: Liveness.UNIQUE = false;
157: } else if (args[i].equals("-nocolor")) {
158: Liveness.UNIQUE = true;
159: } else if (args[i].equals("-only-method")) {
160: if (++i >= args.length) {
161: Main.usage();
162: }
163:
164: Main.METHOD = args[i];
165: } else if (args[i].equals("-print-flow-graph")) {
166: FlowGraph.PRINT_GRAPH = true;
167: } else if (args[i].equals("-classpath")) {
168: if (++i >= args.length) {
169: Main.usage();
170: }
171:
172: final String classpath = args[i];
173: Main.loader.setClassPath(classpath);
174: } else if (args[i].equals("-skip")) {
175: if (++i >= args.length) {
176: Main.usage();
177: }
178:
179: final String pkg = args[i].replace('.', '/');
180: Main.SKIP.add(pkg);
181: } else if (args[i].equals("-only")) {
182: if (++i >= args.length) {
183: Main.usage();
184: }
185:
186: final String pkg = args[i].replace('.', '/');
187: Main.ONLY.add(pkg);
188: } else if (args[i].equals("-nodce")) {
189: Main.DCE = false;
190: } else if (args[i].equals("-noprop")) {
191: Main.PROP = false;
192: } else if (args[i].equals("-nopre")) {
193: Main.PRE = false;
194: } else if (args[i].equals("-dce")) {
195: Main.DCE = true;
196: } else if (args[i].equals("-prop")) {
197: Main.PROP = true;
198: } else if (args[i].equals("-pre")) {
199: Main.PRE = true;
200: } else if (args[i].equals("-closure")) {
201: Main.CLOSURE = true;
202: } else if (args[i].equals("-relax-loading")) {
203: ClassHierarchy.RELAX = true;
204: } else if (args[i].equals("-f")) {
205: Main.FORCE = true;
206: } else if (args[i].startsWith("-")) {
207: Main.usage();
208: } else if (i == args.length - 1) {
209: final File f = new File(args[i]);
210:
211: if (f.exists() && !f.isDirectory()) {
212: System.err.println("No such directory: "
213: + f.getPath());
214: System.exit(2);
215: }
216:
217: if (!f.exists()) {
218: f.mkdirs();
219: }
220:
221: if (!f.exists()) {
222: System.err
223: .println("Couldn't create directory: "
224: + f.getPath());
225: System.exit(2);
226: }
227:
228: Main.loader.setOutputDir(f);
229: gotdir = true;
230: } else {
231: classes.add(args[i]);
232: }
233: }
234:
235: if (!gotdir) {
236: Main.usage();
237: }
238:
239: if (classes.size() == 0) {
240: Main.usage();
241: }
242:
243: boolean errors = false;
244:
245: final Iterator iter = classes.iterator();
246:
247: while (iter.hasNext()) {
248: final String name = (String) iter.next();
249:
250: try {
251: Main.loader.loadClass(name);
252: } catch (final ClassNotFoundException ex) {
253: System.err.println("Couldn't find class: "
254: + ex.getMessage());
255: errors = true;
256: }
257: }
258:
259: if (errors) {
260: System.exit(1);
261: }
262:
263: Main.context = new CachingBloatContext(Main.loader,
264: classes, Main.CLOSURE);
265:
266: if (!Main.CLOSURE) {
267: final Iterator e = classes.iterator();
268:
269: while (e.hasNext()) {
270: final String name = (String) e.next();
271: Main.editClass(name);
272: }
273: } else {
274: classes = null;
275:
276: final Iterator e = Main.context.getHierarchy()
277: .classes().iterator();
278:
279: while (e.hasNext()) {
280: final Type t = (Type) e.next();
281:
282: if (t.isObject()) {
283: Main.editClass(t.className());
284: }
285: }
286: }
287: } catch (final ExceptionInInitializerError ex) {
288: ex.printStackTrace();
289: System.out.println(ex.getException());
290: }
291: }
292:
293: private static void usage() {
294: System.err
295: .println("Usage: java EDU.purdue.cs.bloat.optimize.Main"
296: + "\n [-options] classes dir"
297: + "\n"
298: + "\nwhere options include:"
299: + "\n -help print out this message"
300: + "\n -v -verbose turn on verbose mode"
301: + "\n -debug display a hideous amount of debug info"
302: + "\n -classpath <directories separated by colons>"
303: + "\n list directories in which to look for classes"
304: + "\n -f optimize files even if up-to-date"
305: + "\n -closure recursively optimize referenced classes"
306: + "\n -relax-loading don't report errors if a class is not found"
307: + "\n -skip <class|package.*>"
308: + "\n skip the given class or package"
309: + "\n -only <class|package.*>"
310: + "\n skip all but the given class or package"
311: + "\n -preserve-debug try to preserve debug information"
312: + "\n -[no]anno insert an annotation in the contant pool"
313: + "\n -[no]stack-alloc try to push locals onto the operand stack"
314: + "\n -peel-loops <n|all>"
315: + "\n peel innermost loops to enable code hoisting"
316: + "\n (n >= 0 is the maximum loop level to peel)"
317: + "\n -[no]pre perform partial redundency elimination"
318: + "\n -[no]dce perform dead code elimination"
319: + "\n -[no]prop perform copy and constant propagation"
320: + "");
321: System.exit(0);
322: }
323:
324: private static void editClass(final String className) {
325: ClassFile classFile;
326:
327: try {
328: classFile = (ClassFile) Main.loader.loadClass(className);
329: } catch (final ClassNotFoundException ex) {
330: System.err.println("Couldn't find class: "
331: + ex.getMessage());
332: return;
333: }
334:
335: if (!Main.FORCE) {
336: final File source = classFile.file();
337: final File target = classFile.outputFile();
338:
339: if ((source != null) && (target != null) && source.exists()
340: && target.exists()
341: && (source.lastModified() < target.lastModified())) {
342:
343: if (Main.VERBOSE) {
344: System.out.println(classFile.name()
345: + " is up to date");
346: }
347:
348: return;
349: }
350: }
351:
352: if (Main.DEBUG) {
353: classFile.print(System.out);
354: }
355:
356: final ClassEditor c = Main.context.editClass(classFile);
357:
358: boolean skip = false;
359:
360: final String name = c.type().className();
361: final String qual = c.type().qualifier() + "/*";
362:
363: // Edit only classes explicitly mentioned.
364: if (Main.ONLY.size() > 0) {
365: skip = true;
366:
367: // Only edit classes we explicitly don't name.
368: for (int i = 0; i < Main.ONLY.size(); i++) {
369: final String pkg = (String) Main.ONLY.get(i);
370:
371: if (name.equals(pkg) || qual.equals(pkg)) {
372: skip = false;
373: break;
374: }
375: }
376: }
377:
378: // Don't edit classes we explicitly skip.
379: if (!skip) {
380: for (int i = 0; i < Main.SKIP.size(); i++) {
381: final String pkg = (String) Main.SKIP.get(i);
382:
383: if (name.equals(pkg) || qual.equals(pkg)) {
384: skip = true;
385: break;
386: }
387: }
388: }
389:
390: if (skip) {
391: if (Main.VERBOSE) {
392: System.out.println("Skipping " + c.type().className());
393: }
394:
395: Main.context.release(classFile);
396: return;
397: }
398:
399: if (Main.VERBOSE) {
400: System.out.println("Optimizing " + c.type().className());
401: }
402:
403: final MethodInfo[] methods = c.methods();
404:
405: for (int j = 0; j < methods.length; j++) {
406: final MethodEditor m;
407:
408: try {
409: m = Main.context.editMethod(methods[j]);
410: } catch (final ClassFormatException ex) {
411: System.err.println(ex.getMessage());
412: continue;
413: }
414:
415: if ((Main.METHOD != null) && !m.name().equals(Main.METHOD)) {
416: Main.context.release(methods[j]);
417: continue;
418: }
419:
420: if (Main.DEBUG) {
421: m.print(System.out);
422: }
423:
424: if (m.isNative() || m.isAbstract()) {
425: Main.context.release(methods[j]);
426: continue;
427: }
428:
429: if (Main.COMPACT_ARRAY_INIT) {
430: CompactArrayInitializer.transform(m);
431:
432: if (Main.DEBUG) {
433: System.out.println("---------- After compaction:");
434: m.print(System.out);
435: System.out.println("---------- end print");
436: }
437: }
438:
439: FlowGraph cfg;
440:
441: try {
442: cfg = new FlowGraph(m);
443: } catch (final ClassFormatException ex) {
444: System.err.println(ex.getMessage());
445: Main.context.release(methods[j]);
446: continue;
447: }
448:
449: SSA.transform(cfg);
450:
451: if (FlowGraph.DEBUG) {
452: System.out.println("---------- After SSA:");
453: cfg.print(System.out);
454: System.out.println("---------- end print");
455: }
456:
457: if (Main.DEBUG) {
458: cfg.visit(new VerifyCFG(false));
459: }
460:
461: // Do copy propagation first to get rid of all the extra copies
462: // inserted for dups. If they're left it, it really slows down
463: // value numbering.
464: if (Main.PROP) {
465: if (Main.DEBUG) {
466: System.out
467: .println("-------Before Copy Propagation-------");
468: }
469:
470: final ExprPropagation copy = new ExprPropagation(cfg);
471: copy.transform();
472:
473: if (Main.DEBUG) {
474: cfg.visit(new VerifyCFG(false));
475: }
476:
477: if (Main.DEBUG) {
478: System.out
479: .println("--------After Copy Propagation-------");
480: cfg.print(System.out);
481: }
482: }
483:
484: if (Main.DCE) {
485: if (Main.DEBUG) {
486: System.out
487: .println("-----Before Dead Code Elimination----");
488: }
489:
490: final DeadCodeElimination dce = new DeadCodeElimination(
491: cfg);
492: dce.transform();
493:
494: if (Main.DEBUG) {
495: cfg.visit(new VerifyCFG(false));
496: }
497:
498: if (Main.DEBUG) {
499: System.out
500: .println("-----After Dead Code Elimination-----");
501: cfg.print(System.out);
502: }
503: }
504:
505: if (Main.DEBUG) {
506: System.out
507: .println("---------Doing type inference--------");
508: }
509:
510: TypeInference.transform(cfg, Main.context.getHierarchy());
511:
512: if (Main.DEBUG) {
513: System.out
514: .println("--------Doing value numbering--------");
515: }
516:
517: (new ValueNumbering()).transform(cfg);
518:
519: if (Main.FOLD) {
520: if (Main.DEBUG) {
521: System.out
522: .println("--------Before Value Folding---------");
523: }
524:
525: (new ValueFolding()).transform(cfg);
526:
527: if (Main.DEBUG) {
528: cfg.visit(new VerifyCFG());
529: }
530:
531: if (Main.DEBUG) {
532: System.out
533: .println("---------After Value Folding---------");
534: cfg.print(System.out);
535: }
536: }
537:
538: if (Main.PRE) {
539: if (Main.DEBUG) {
540: System.out
541: .println("-------------Before SSAPRE-----------");
542: }
543:
544: final SSAPRE pre = new SSAPRE(cfg, Main.context);
545: pre.transform();
546:
547: if (Main.DEBUG) {
548: cfg.visit(new VerifyCFG());
549: }
550:
551: if (Main.DEBUG) {
552: System.out
553: .println("-------------After SSAPRE------------");
554: cfg.print(System.out);
555: }
556: }
557:
558: if (Main.FOLD) {
559: if (Main.DEBUG) {
560: System.out
561: .println("--------Before Value Folding---------");
562: }
563:
564: (new ValueFolding()).transform(cfg);
565:
566: if (Main.DEBUG) {
567: cfg.visit(new VerifyCFG());
568: }
569:
570: if (Main.DEBUG) {
571: System.out
572: .println("---------After Value Folding---------");
573: cfg.print(System.out);
574: }
575: }
576:
577: if (Main.PROP) {
578: if (Main.DEBUG) {
579: System.out
580: .println("-------Before Copy Propagation-------");
581: }
582:
583: final ExprPropagation copy = new ExprPropagation(cfg);
584: copy.transform();
585:
586: if (Main.DEBUG) {
587: cfg.visit(new VerifyCFG());
588: }
589:
590: if (Main.DEBUG) {
591: System.out
592: .println("--------After Copy Propagation-------");
593: cfg.print(System.out);
594: }
595: }
596:
597: if (Main.DCE) {
598: if (Main.DEBUG) {
599: System.out
600: .println("-----Before Dead Code Elimination----");
601: }
602:
603: final DeadCodeElimination dce = new DeadCodeElimination(
604: cfg);
605: dce.transform();
606:
607: if (Main.DEBUG) {
608: cfg.visit(new VerifyCFG());
609: }
610:
611: if (Main.DEBUG) {
612: System.out
613: .println("-----After Dead Code Elimination-----");
614: cfg.print(System.out);
615: }
616: }
617:
618: (new PersistentCheckElimination()).transform(cfg);
619: (new InductionVarAnalyzer()).transform(cfg);
620:
621: /*
622: * if (STACK_ALLOC) { if (DEBUG) {
623: * System.out.println("------------Before StackPRE----------"); }
624: *
625: * StackPRE pre = new StackPRE(cfg); pre.transform();
626: *
627: * if (DEBUG) { cfg.visit(new VerifyCFG()); }
628: *
629: * if (DEBUG) { System.out.println("------------After
630: * StackPRE-----------"); cfg.print(System.out); } }
631: */
632:
633: cfg.commit();
634:
635: Peephole.transform(m);
636:
637: Main.context.commit(methods[j]);
638: }
639:
640: if (Main.ANNO) {
641: String s = "Optimized with: EDU.purdue.cs.bloat.diva.Main";
642:
643: for (int i = 0; i < Main.ARGS.length; i++) {
644: if ((Main.ARGS[i].indexOf(' ') >= 0)
645: || (Main.ARGS[i].indexOf('\t') >= 0)
646: || (Main.ARGS[i].indexOf('\r') >= 0)
647: || (Main.ARGS[i].indexOf('\n') >= 0)) {
648: s += " '" + Main.ARGS[i] + "'";
649: } else {
650: s += " " + Main.ARGS[i];
651: }
652: }
653:
654: System.out.println(s);
655: // c.constants().addConstant(Constant.UTF8, s);
656: }
657:
658: Main.context.commit(classFile);
659: }
660: }
|