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.decorate;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import EDU.purdue.cs.bloat.context.*;
027: import EDU.purdue.cs.bloat.editor.*;
028: import EDU.purdue.cs.bloat.file.*;
029: import EDU.purdue.cs.bloat.reflect.*;
030: import EDU.purdue.cs.bloat.trans.*;
031: import EDU.purdue.cs.bloat.util.*;
032:
033: /**
034: * Inserts residency, update, or swizzle checks into the methods of the classes
035: * specified on the command line.
036: *
037: * Usage: java EDU.purdue.cs.bloat.decorate.Main [-options] classes output_dir
038: *
039: * where options include: -help print out this message -v -verbose turn on
040: * verbose mode (can be given multiple times) -classpath <directories separated
041: * by colons list directories in which to look for classes -f decorate files
042: * even if up-to-date -closure recursively decorate referenced classes
043: * -relax-loading don't report errors if a class is not found -skip
044: * <class|package.*> skip the given class or package (this option can be given
045: * more than once) -only <class|package.*> skip all but the given class or
046: * package (this option can be given more than once) -rc insert residency checks
047: * (default) -norc don't insert residency checks -uc insert update checks
048: * (default) -sc insert array swizzle checks (default) -nosc don't insert array
049: * swizzle checkso
050: *
051: */
052: public class Main implements Opcode {
053: private static int VERBOSE = 0; // The level of verbosity
054:
055: private static boolean FORCE = false;
056:
057: private static boolean CLOSURE = false;
058:
059: private static boolean RC = true; // Insert residency checks?
060:
061: private static boolean UC = true; // Insert update checks?
062:
063: private static boolean SC = true; // Insert swizzle checks?
064:
065: private static final List SKIP = new ArrayList();
066:
067: private static final List ONLY = new ArrayList();
068:
069: private static final int NONE = 0;
070:
071: private static final int POINTER = 1;
072:
073: private static final int SCALAR = 2;
074:
075: /**
076: * Parse the command line. Inserts residency, update, and swizzle checks
077: * into the bytecode of the methods of the specified classes.
078: */
079: public static void main(final String[] args) {
080: final ClassFileLoader loader = new ClassFileLoader();
081: List classes = new ArrayList(); // Names of classes from command line
082: boolean gotdir = false; // Did user specify an output dir?
083:
084: for (int i = 0; i < args.length; i++) {
085: if (args[i].equals("-v") || args[i].equals("-verbose")) {
086: Main.VERBOSE++;
087: } else if (args[i].equals("-help")) {
088: Main.usage();
089: } else if (args[i].equals("-classpath")) {
090: if (++i >= args.length) {
091: Main.usage();
092: }
093:
094: final String classpath = args[i];
095: loader.setClassPath(classpath);
096: } else if (args[i].equals("-skip")) {
097: if (++i >= args.length) {
098: Main.usage();
099: }
100:
101: final String pkg = args[i].replace('.', '/');
102: Main.SKIP.add(pkg);
103: } else if (args[i].equals("-only")) {
104: if (++i >= args.length) {
105: Main.usage();
106: }
107:
108: final String pkg = args[i].replace('.', '/');
109: Main.ONLY.add(pkg);
110: } else if (args[i].equals("-closure")) {
111: Main.CLOSURE = true;
112: } else if (args[i].equals("-relax-loading")) {
113: ClassHierarchy.RELAX = true;
114: } else if (args[i].equals("-f")) {
115: Main.FORCE = true;
116: } else if (args[i].equals("-norc")) {
117: Main.RC = false;
118: } else if (args[i].equals("-rc")) {
119: Main.RC = true;
120: } else if (args[i].equals("-nouc")) {
121: Main.UC = false;
122: } else if (args[i].equals("-uc")) {
123: Main.UC = true;
124: } else if (args[i].equals("-nosc")) {
125: Main.SC = false;
126: } else if (args[i].equals("-sc")) {
127: Main.SC = true;
128: } else if (args[i].startsWith("-")) {
129: Main.usage();
130: } else if (i == args.length - 1) {
131: // Last argument is the name of the outpu directory
132: final File f = new File(args[i]);
133:
134: if (f.exists() && !f.isDirectory()) {
135: System.err.println("No such directory: "
136: + f.getPath());
137: System.exit(2);
138: }
139:
140: loader.setOutputDir(f);
141: gotdir = true;
142: } else {
143: classes.add(args[i]);
144: }
145: }
146:
147: if (!gotdir) {
148: Main.usage();
149: }
150:
151: if (classes.size() == 0) {
152: Main.usage();
153: }
154:
155: if (Main.VERBOSE > 3) {
156: ClassFileLoader.DEBUG = true;
157: ClassEditor.DEBUG = true;
158: }
159:
160: boolean errors = false;
161:
162: final Iterator iter = classes.iterator();
163:
164: // Load each class specified on the command line
165: while (iter.hasNext()) {
166: final String name = (String) iter.next();
167:
168: try {
169: loader.loadClass(name);
170: } catch (final ClassNotFoundException ex) {
171: System.err.println("Couldn't find class: "
172: + ex.getMessage());
173: errors = true;
174: }
175: }
176:
177: if (errors) {
178: System.exit(1);
179: }
180:
181: final BloatContext context = new CachingBloatContext(loader,
182: classes, Main.CLOSURE);
183:
184: if (!Main.CLOSURE) {
185: final Iterator e = classes.iterator();
186:
187: while (e.hasNext()) {
188: final String name = (String) e.next();
189: try {
190: final ClassInfo info = loader.loadClass(name);
191: Main.decorateClass(context, info);
192: } catch (final ClassNotFoundException ex) {
193: System.err.println("Couldn't find class: "
194: + ex.getMessage());
195: System.exit(1);
196: }
197: }
198: } else {
199: classes = null;
200:
201: final ClassHierarchy hier = context.getHierarchy();
202:
203: final Iterator e = hier.classes().iterator();
204:
205: while (e.hasNext()) {
206: final Type t = (Type) e.next();
207:
208: if (t.isObject()) {
209: try {
210: final ClassInfo info = loader.loadClass(t
211: .className());
212: Main.decorateClass(context, info);
213: } catch (final ClassNotFoundException ex) {
214: System.err.println("Couldn't find class: "
215: + ex.getMessage());
216: System.exit(1);
217: }
218: }
219: }
220: }
221: }
222:
223: private static void usage() {
224: System.err
225: .println("Usage: java EDU.purdue.cs.bloat.decorate.Main "
226: + "\n [-options] classes output_dir"
227: + "\n"
228: + "\nwhere options include:"
229: + "\n -help print out this message"
230: + "\n -v -verbose turn on verbose mode "
231: + "(can be given multiple times)"
232: + "\n -classpath <directories separated by colons>"
233: + "\n list directories in which to look for classes"
234: + "\n -f decorate files even if up-to-date"
235: + "\n -closure recursively decorate referenced classes"
236: + "\n -relax-loading don't report errors if a class is not found"
237: + "\n -skip <class|package.*>"
238: + "\n skip the given class or package"
239: + "\n (this option can be given more than once)"
240: + "\n -only <class|package.*>"
241: + "\n skip all but the given class or package"
242: + "\n (this option can be given more than once)"
243: + "\n -rc insert residency checks (default)"
244: + "\n -norc don't insert residency checks"
245: + "\n -uc insert update checks (default)"
246: + "\n -sc insert array swizzle checks (default)"
247: + "\n -nosc don't insert array swizzle checks");
248: System.exit(0);
249: }
250:
251: /**
252: * Adds residency/update/swizzle checks to all of the methods in a given
253: * class.
254: *
255: * @param context
256: * Information about all the classes we're dealing with
257: * @param info
258: * Information about the class we're decorating
259: */
260: private static void decorateClass(final EditorContext context,
261: final ClassInfo info) {
262: final ClassFile classFile = (ClassFile) info;
263:
264: // Check to see if the class file is up-to-date
265: if (!Main.FORCE) {
266: final File source = classFile.file();
267: final File target = classFile.outputFile();
268:
269: if ((source != null) && (target != null) && source.exists()
270: && target.exists()
271: && (source.lastModified() < target.lastModified())) {
272:
273: if (Main.VERBOSE > 1) {
274: System.out.println(classFile.name()
275: + " is up to date");
276: }
277:
278: return;
279: }
280: }
281:
282: if (Main.VERBOSE > 2) {
283: classFile.print(System.out);
284: }
285:
286: final ClassEditor c = context.editClass(info);
287:
288: boolean skip = false;
289:
290: final String name = c.type().className();
291: final String qual = c.type().qualifier() + "/*";
292:
293: // Edit only classes explicitly mentioned.
294: if (Main.ONLY.size() > 0) {
295: skip = true;
296:
297: // Only edit classes we explicitly don't name.
298: for (int i = 0; i < Main.ONLY.size(); i++) {
299: final String pkg = (String) Main.ONLY.get(i);
300:
301: if (name.equals(pkg) || qual.equals(pkg)) {
302: skip = false;
303: break;
304: }
305: }
306: }
307:
308: // Don't edit classes we explicitly skip.
309: if (!skip) {
310: for (int i = 0; i < Main.SKIP.size(); i++) {
311: final String pkg = (String) Main.SKIP.get(i);
312:
313: if (name.equals(pkg) || qual.equals(pkg)) {
314: skip = true;
315: break;
316: }
317: }
318: }
319:
320: if (skip) {
321: if (Main.VERBOSE > 0) {
322: System.out.println("Skipping " + c.type().className());
323: }
324:
325: context.release(info);
326: return;
327: }
328:
329: if (Main.VERBOSE > 0) {
330: System.out.println("Decorating class "
331: + c.type().className());
332: }
333:
334: if (Main.VERBOSE > 2) {
335: ((ClassFile) info).print(System.out);
336: }
337:
338: final MethodInfo[] methods = c.methods();
339:
340: // Add residency checks (via transform()) to each method in the class
341: for (int j = 0; j < methods.length; j++) {
342: MethodEditor m;
343:
344: try {
345: m = context.editMethod(methods[j]);
346: } catch (final ClassFormatException ex) {
347: System.err.println(ex.getMessage());
348: continue;
349: }
350:
351: Main.transform(m);
352: context.commit(methods[j]);
353: }
354:
355: context.commit(info);
356: }
357:
358: /**
359: * Inserts residency/update/swizzle checks into a method. Iterates over the
360: * bytecodes in the method and inserts the appropriate residency opcode.
361: *
362: * @param method
363: * The method to which to add checks.
364: *
365: * @see MethodEditor#code
366: */
367: private static void transform(final MethodEditor method) {
368: if (Main.VERBOSE > 1) {
369: System.out.println("Decorating method " + method);
370: }
371:
372: // Optimize initialization of arrays to speed things up.
373: CompactArrayInitializer.transform(method);
374:
375: final ListIterator iter = method.code().listIterator();
376:
377: // Go through the code (Instructions and Labels) in the method
378: INST: while (iter.hasNext()) {
379: final Object ce = iter.next();
380:
381: if (Main.VERBOSE > 2) {
382: System.out.println("Examining " + ce);
383: }
384:
385: if (ce instanceof Instruction) {
386: final Instruction inst = (Instruction) ce;
387:
388: int uctype = Main.NONE; // Type of update check (POINTER or
389: // SCALAR)
390: boolean insert_sc = false; // Insert swizzle check (aaload
391: // only)?
392:
393: final int opc = inst.opcodeClass();
394: int depth;
395:
396: switch (opc) {
397: case opcx_arraylength:
398: case opcx_athrow:
399: case opcx_getfield:
400: case opcx_instanceof : {
401: depth = 0;
402: break;
403: }
404: case opcx_iaload:
405: case opcx_laload:
406: case opcx_faload:
407: case opcx_daload:
408: case opcx_baload:
409: case opcx_caload:
410: case opcx_saload: {
411: depth = 1;
412: break;
413: }
414: case opcx_aaload: {
415: depth = 1;
416: insert_sc = true;
417: break;
418: }
419: case opcx_iastore:
420: case opcx_fastore:
421: case opcx_aastore:
422: case opcx_bastore:
423: case opcx_castore:
424: case opcx_sastore: {
425: depth = 2;
426: break;
427: }
428: case opcx_lastore:
429: case opcx_dastore: {
430: depth = 3;
431: break;
432: }
433: case opcx_putfield: {
434: final MemberRef ref = (MemberRef) inst.operand();
435: depth = ref.type().stackHeight();
436: if (ref.type().isReference()) {
437: uctype = Main.POINTER;
438: } else {
439: uctype = Main.SCALAR;
440: }
441: break;
442: }
443: case opcx_invokevirtual:
444: case opcx_invokespecial:
445: case opcx_invokeinterface: {
446: final MemberRef ref = (MemberRef) inst.operand();
447: depth = ref.type().stackHeight();
448: break;
449: }
450: case opcx_rc: {
451: // Skip any existing residency checks.
452: iter.remove();
453: continue INST;
454: }
455: case opcx_aupdate: {
456: // Skip any existing update checks.
457: iter.remove();
458: continue INST;
459: }
460: case opcx_supdate: {
461: // Skip any existing update checks.
462: iter.remove();
463: continue INST;
464: }
465: default: {
466: continue INST;
467: }
468: }
469:
470: Instruction addInst;
471:
472: // Insert a residency check...
473: if (Main.RC) {
474: Object t;
475:
476: // //////////////////////////////////
477: // Before...
478: // +-----+------+-----------+
479: // | ... | inst | afterInst |
480: // +-----+------+-----------+
481: // ^prev ^next
482: //
483: // After...
484: // +-----+----+------+-----------+
485: // | ... | RC | inst | afterInst |
486: // +-----+----+------+-----------+
487: // ^prev ^next
488: // //////////////////////////////////
489:
490: // +-----+------+-----------+
491: // | ... | inst | afterInst |
492: // +-----+------+-----------+
493: // ^prev ^next
494:
495: t = iter.previous();
496: Assert.isTrue(t == inst, t + " != " + inst);
497:
498: // +-----+------+-----------+
499: // | ... | inst | afterInst |
500: // +-----+------+-----------+
501: // ^prev ^next
502:
503: addInst = new Instruction(Opcode.opcx_rc,
504: new Integer(depth));
505: iter.add(addInst);
506:
507: // +-----+----+------+-----------+
508: // | ... | RC | inst | afterInst |
509: // +-----+----+------+-----------+
510: // ^prev ^next
511:
512: t = iter.previous();
513: Assert.isTrue(t == addInst, t + " != " + addInst);
514:
515: // +-----+----+------+-----------+
516: // | ... | RC | inst | afterInst |
517: // +-----+----+------+-----------+
518: // ^prev ^next
519:
520: t = iter.next();
521: Assert.isTrue(t == addInst, t + " != " + addInst);
522:
523: // +-----+----+------+-----------+
524: // | ... | RC | inst | afterInst |
525: // +-----+----+------+-----------+
526: // ^prev ^next
527:
528: t = iter.next();
529: Assert.isTrue(t == inst, t + " != " + inst);
530:
531: // +-----+----+------+-----------+
532: // | ... | RC | inst | afterInst |
533: // +-----+----+------+-----------+
534: // ^prev ^next
535:
536: if (Main.VERBOSE > 2) {
537: System.out.println("Inserting " + addInst
538: + " before " + inst);
539: }
540: } else {
541: if (Main.VERBOSE > 2) {
542: System.out.println("Not inserting rc before "
543: + inst);
544: }
545: }
546:
547: // Insert a swizzle check...
548: if (insert_sc) {
549: if (Main.SC) {
550: Object t;
551:
552: // ////////////////////////////////////////////
553: // Before...
554: // +-----+------+-----------+
555: // | ... | inst | afterInst |
556: // +-----+------+-----------+
557: // ^prev ^next
558: //
559: // After...
560: // +-----+------+----------+------+-----------+
561: // | ... | dup2 | aswizzle | inst | afterInst |
562: // +-----+------+----------+------+-----------+
563: // ^prev ^next
564: // /////////////////////////////////////////////
565:
566: // +-----+------+-----------+
567: // | ... | inst | afterInst |
568: // +-----+------+-----------+
569: // ^prev ^next
570:
571: t = iter.previous();
572: Assert.isTrue(t == inst, t + " != " + inst);
573:
574: // +-----+------+-----------+
575: // | ... | inst | afterInst |
576: // +-----+------+-----------+
577: // ^prev ^next
578:
579: addInst = new Instruction(Opcode.opcx_dup2);
580: iter.add(addInst);
581:
582: // +-----+------+------+-----------+
583: // | ... | dup2 | inst | afterInst |
584: // +-----+------+------+-----------+
585: // ^prev ^next
586:
587: t = iter.previous();
588: Assert.isTrue(t == addInst, t + " != "
589: + addInst);
590:
591: // +-----+------+------+-----------+
592: // | ... | dup2 | inst | afterInst |
593: // +-----+------+------+-----------+
594: // ^prev ^next
595:
596: t = iter.next();
597: Assert.isTrue(t == addInst, t + " != "
598: + addInst);
599:
600: // +-----+------+------+-----------+
601: // | ... | dup2 | inst | afterInst |
602: // +-----+------+------+-----------+
603: // ^prev ^next
604:
605: addInst = new Instruction(Opcode.opcx_aswizzle);
606: iter.add(addInst);
607:
608: // +-----+------+----------+------+-----------+
609: // | ... | dup2 | aswizzle | inst | afterInst |
610: // +-----+------+----------+------+-----------+
611: // ^prev ^next
612:
613: t = iter.previous();
614: Assert.isTrue(t == addInst, t + " != "
615: + addInst);
616:
617: // +-----+------+----------+------+-----------+
618: // | ... | dup2 | aswizzle | inst | afterInst |
619: // +-----+------+----------+------+-----------+
620: // ^prev ^next
621:
622: t = iter.next();
623: Assert.isTrue(t == addInst, t + " != "
624: + addInst);
625:
626: // +-----+------+----------+------+-----------+
627: // | ... | dup2 | aswizzle | inst | afterInst |
628: // +-----+------+----------+------+-----------+
629: // ^prev ^next
630:
631: t = iter.next();
632: Assert.isTrue(t == inst, t + " != " + inst);
633:
634: // +-----+------+----------+------+-----------+
635: // | ... | dup2 | aswizzle | inst | afterInst |
636: // +-----+------+----------+------+-----------+
637: // ^prev ^next
638:
639: if (Main.VERBOSE > 2) {
640: System.out
641: .println("Inserting dup2,aswizzle before "
642: + inst);
643: }
644: }
645:
646: else {
647: if (Main.VERBOSE > 2) {
648: System.out
649: .println("Not inserting aswizzle before "
650: + inst);
651: }
652: }
653: }
654:
655: // Insert an update check...
656: if (uctype != Main.NONE) {
657: if (Main.UC) {
658: Object t;
659:
660: // ////////////////////////////////////////////
661: // Before...
662: // +-----+------+-----------+
663: // | ... | inst | afterInst |
664: // +-----+------+-----------+
665: // ^prev ^next
666: //
667: // After...
668: // +-----+---------+------+-----------+
669: // | ... | aupdate | inst | afterInst |
670: // +-----+---------+------+-----------+
671: // ^prev ^next
672: // /////////////////////////////////////////////
673:
674: // +-----+------+-----------+
675: // | ... | inst | afterInst |
676: // +-----+------+-----------+
677: // ^prev ^next
678:
679: t = iter.previous();
680: Assert.isTrue(t == inst, t + " != " + inst);
681:
682: // +-----+------+-----------+
683: // | ... | inst | afterInst |
684: // +-----+------+-----------+
685: // ^prev ^next
686:
687: addInst = new Instruction(Opcode.opcx_aupdate,
688: new Integer(depth));
689: /*
690: * if (uctype == POINTER) { addInst = new
691: * Instruction(opcx_aupdate, new Integer(depth)); } else {
692: * addInst = new Instruction(opcx_supdate, new
693: * Integer(depth)); }
694: */
695:
696: iter.add(addInst);
697:
698: // +-----+---------+------+-----------+
699: // | ... | aupdate | inst | afterInst |
700: // +-----+---------+------+-----------+
701: // ^prev ^next
702:
703: t = iter.previous();
704: Assert.isTrue(t == addInst, t + " != "
705: + addInst);
706:
707: // +-----+---------+------+-----------+
708: // | ... | aupdate | inst | afterInst |
709: // +-----+---------+------+-----------+
710: // ^prev ^next
711:
712: t = iter.next();
713: Assert.isTrue(t == addInst, t + " != "
714: + addInst);
715:
716: // +-----+---------+------+-----------+
717: // | ... | aupdate | inst | afterInst |
718: // +-----+---------+------+-----------+
719: // ^prev ^next
720:
721: t = iter.next();
722: Assert.isTrue(t == inst, t + " != " + inst);
723:
724: // +-----+---------+------+-----------+
725: // | ... | aupdate | inst | afterInst |
726: // +-----+---------+------+-----------+
727: // ^prev ^next
728:
729: if (Main.VERBOSE > 2) {
730: System.out.println("Inserting " + addInst
731: + " before " + inst);
732: }
733: } else if (Main.VERBOSE > 2) {
734: System.out.println("Not inserting uc before "
735: + inst);
736: }
737: }
738: }
739: }
740: }
741: }
|