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.shrink;
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:
032: /**
033: * This program just performs array initialization compaction on a class. It
034: * really doesn't seem necessary anymore.
035: */
036: public class Main implements Opcode {
037: private static int VERBOSE = 0;
038:
039: private static boolean FORCE = false;
040:
041: private static boolean CLOSURE = false;
042:
043: private static final List SKIP = new ArrayList();
044:
045: private static final List ONLY = new ArrayList();
046:
047: public static void main(final String[] args) {
048: final ClassFileLoader loader = new ClassFileLoader();
049: List classes = new ArrayList();
050: boolean gotdir = false;
051:
052: for (int i = 0; i < args.length; i++) {
053: if (args[i].equals("-v") || args[i].equals("-verbose")) {
054: Main.VERBOSE++;
055: } else if (args[i].equals("-help")) {
056: Main.usage();
057: } else if (args[i].equals("-classpath/p")) {
058: if (++i >= args.length) {
059: Main.usage();
060: }
061:
062: final String classpath = args[i];
063: loader.prependClassPath(classpath);
064: } else if (args[i].equals("-classpath")) {
065: if (++i >= args.length) {
066: Main.usage();
067: }
068:
069: final String classpath = args[i];
070: loader.setClassPath(classpath);
071: } else if (args[i].equals("-skip")) {
072: if (++i >= args.length) {
073: Main.usage();
074: }
075:
076: final String pkg = args[i].replace('.', '/');
077: Main.SKIP.add(pkg);
078: } else if (args[i].equals("-only")) {
079: if (++i >= args.length) {
080: Main.usage();
081: }
082:
083: final String pkg = args[i].replace('.', '/');
084: Main.ONLY.add(pkg);
085: } else if (args[i].equals("-closure")) {
086: Main.CLOSURE = true;
087: } else if (args[i].equals("-relax-loading")) {
088: ClassHierarchy.RELAX = true;
089: } else if (args[i].equals("-f")) {
090: Main.FORCE = true;
091: } else if (args[i].startsWith("-")) {
092: Main.usage();
093: } else if (i == args.length - 1) {
094: final File f = new File(args[i]);
095:
096: if (f.exists() && !f.isDirectory()) {
097: System.err.println("No such directory: "
098: + f.getPath());
099: System.exit(2);
100: }
101:
102: loader.setOutputDir(f);
103: gotdir = true;
104: } else {
105: classes.add(args[i]);
106: }
107: }
108:
109: if (!gotdir) {
110: Main.usage();
111: }
112:
113: if (classes.size() == 0) {
114: Main.usage();
115: }
116:
117: if (Main.VERBOSE > 3) {
118: ClassFileLoader.DEBUG = true;
119: CompactArrayInitializer.DEBUG = true;
120: ClassEditor.DEBUG = true;
121: }
122:
123: boolean errors = false;
124:
125: final Iterator iter = classes.iterator();
126:
127: while (iter.hasNext()) {
128: final String name = (String) iter.next();
129:
130: try {
131: loader.loadClass(name);
132: } catch (final ClassNotFoundException ex) {
133: System.err.println("Couldn't find class: "
134: + ex.getMessage());
135: errors = true;
136: }
137: }
138:
139: if (errors) {
140: System.exit(1);
141: }
142:
143: final BloatContext context = new CachingBloatContext(loader,
144: classes, Main.CLOSURE);
145:
146: if (!Main.CLOSURE) {
147: final Iterator e = classes.iterator();
148:
149: while (e.hasNext()) {
150: final String name = (String) e.next();
151: try {
152: final ClassInfo info = loader.loadClass(name);
153: Main.editClass(context, info);
154: } catch (final ClassNotFoundException ex) {
155: System.err.println("Couldn't find class: "
156: + ex.getMessage());
157: System.exit(1);
158: }
159: }
160: } else {
161: classes = null;
162:
163: final ClassHierarchy hier = context.getHierarchy();
164:
165: final Iterator e = hier.classes().iterator();
166:
167: while (e.hasNext()) {
168: final Type t = (Type) e.next();
169:
170: if (t.isObject()) {
171: try {
172: final ClassInfo info = loader.loadClass(t
173: .className());
174: Main.editClass(context, info);
175: } catch (final ClassNotFoundException ex) {
176: System.err.println("Couldn't find class: "
177: + ex.getMessage());
178: System.exit(1);
179: }
180: }
181: }
182: }
183: }
184:
185: private static void usage() {
186: System.err
187: .println("Usage: java EDU.purdue.cs.bloat.shrink.Main "
188: + "\n [-options] classes output_dir"
189: + "\n"
190: + "\nwhere options include:"
191: + "\n -help print out this message"
192: + "\n -v -verbose turn on verbose mode "
193: + "(can be given multiple times)"
194: + "\n -classpath <directories separated by colons>"
195: + "\n list directories in which to look for classes"
196: + "\n -f decorate files even if up-to-date"
197: + "\n -closure recursively decorate referenced classes"
198: + "\n -relax-loading don't report errors if a class is not found"
199: + "\n -skip <class|package.*>"
200: + "\n skip the given class or package"
201: + "\n (this option can be given more than once)"
202: + "\n -only <class|package.*>"
203: + "\n skip all but the given class or package"
204: + "\n (this option can be given more than once)");
205: System.exit(0);
206: }
207:
208: private static void editClass(final EditorContext editor,
209: final ClassInfo info) {
210: final ClassFile classFile = (ClassFile) info;
211:
212: if (!Main.FORCE) {
213: final File source = classFile.file();
214: final File target = classFile.outputFile();
215:
216: if ((source != null) && (target != null) && source.exists()
217: && target.exists()
218: && (source.lastModified() < target.lastModified())) {
219:
220: if (Main.VERBOSE > 1) {
221: System.out.println(classFile.name()
222: + " is up to date");
223: }
224:
225: return;
226: }
227: }
228:
229: if (Main.VERBOSE > 2) {
230: classFile.print(System.out);
231: }
232:
233: final ClassEditor c = editor.editClass(info);
234:
235: boolean skip = false;
236:
237: final String name = c.type().className();
238: final String qual = c.type().qualifier() + "/*";
239:
240: // Edit only classes explicitly mentioned.
241: if (Main.ONLY.size() > 0) {
242: skip = true;
243:
244: // Only edit classes we explicitly don't name.
245: for (int i = 0; i < Main.ONLY.size(); i++) {
246: final String pkg = (String) Main.ONLY.get(i);
247:
248: if (name.equals(pkg) || qual.equals(pkg)) {
249: skip = false;
250: break;
251: }
252: }
253: }
254:
255: // Don't edit classes we explicitly skip.
256: if (!skip) {
257: for (int i = 0; i < Main.SKIP.size(); i++) {
258: final String pkg = (String) Main.SKIP.get(i);
259:
260: if (name.equals(pkg) || qual.equals(pkg)) {
261: skip = true;
262: break;
263: }
264: }
265: }
266:
267: if (skip) {
268: if (Main.VERBOSE > 0) {
269: System.out.println("Skipping " + c.type().className());
270: }
271:
272: editor.release(info);
273: return;
274: }
275:
276: if (Main.VERBOSE > 0) {
277: System.out.println("Decorating class "
278: + c.type().className());
279: }
280:
281: if (Main.VERBOSE > 2) {
282: ((ClassFile) info).print(System.out);
283: }
284:
285: boolean changed = false;
286:
287: final MethodInfo[] methods = c.methods();
288:
289: for (int j = 0; j < methods.length; j++) {
290: MethodEditor m;
291:
292: try {
293: m = editor.editMethod(methods[j]);
294: } catch (final ClassFormatException ex) {
295: System.err.println(ex.getMessage());
296: continue;
297: }
298:
299: if (CompactArrayInitializer.transform(m)) {
300: changed = true;
301:
302: if (Main.VERBOSE > 2) {
303: System.out.println("commit " + m.name() + " "
304: + m.type());
305: }
306:
307: editor.commit(methods[j]);
308: } else {
309: if (Main.VERBOSE > 2) {
310: System.out.println("release " + m.name() + " "
311: + m.type());
312: }
313:
314: editor.release(methods[j]);
315: }
316: }
317:
318: if (changed) {
319: editor.commit(info);
320: }
321: }
322: }
|