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.context;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import EDU.purdue.cs.bloat.editor.*;
027: import EDU.purdue.cs.bloat.file.*;
028: import EDU.purdue.cs.bloat.inline.*;
029: import EDU.purdue.cs.bloat.reflect.*;
030:
031: /**
032: * This abstract class is a central repository for all things that are necessary
033: * for a BLOATing sessions. Its subclasses implement certain schemes for
034: * managing BLOAT data structures such as editors and control flow graphs.
035: */
036: public abstract class BloatContext implements InlineContext {
037: public static boolean DEBUG = Boolean
038: .getBoolean("BloatContext.DEBUG");
039:
040: protected InlineStats inlineStats;
041:
042: // Ignore stuff for inlining
043: protected Set ignorePackages = new HashSet();
044:
045: protected Set ignoreClasses = new HashSet();
046:
047: protected Set ignoreMethods = new HashSet();
048:
049: protected Set ignoreFields = new HashSet();
050:
051: protected boolean ignoreSystem = false;
052:
053: protected CallGraph callGraph;
054:
055: protected Set roots; // Root methods of call graph
056:
057: protected static void db(final String s) {
058: if (BloatContext.DEBUG) {
059: System.out.println(s);
060: }
061: }
062:
063: protected ClassInfoLoader loader;
064:
065: /**
066: * Constructor. Each <tt>BloatContext</tt> needs to know about a
067: * <tt>ClassInfoLoader</tt>.
068: */
069: public BloatContext(final ClassInfoLoader loader) {
070: this .loader = loader;
071: }
072:
073: private static ClassLoader systemCL;
074: static {
075: final String s = "";
076: BloatContext.systemCL = s.getClass().getClassLoader();
077: }
078:
079: /**
080: * Returns <tt>true</tt> if the give type is a system class (that is, has
081: * the same class loader as java.lang.String).
082: */
083: public static boolean isSystem(final Type type) {
084: Class c = null;
085: try {
086: c = Class.forName(type.className().replace('/', '.'));
087:
088: } catch (final ClassNotFoundException ex) {
089: System.err.println("** Could not find class "
090: + type.className());
091: ex.printStackTrace(System.err);
092: System.exit(1);
093: }
094:
095: // Have to use == because class loader might be null
096: return (c.getClassLoader() == BloatContext.systemCL);
097: }
098:
099: public void setRootMethods(final Set roots) {
100: if (this .callGraph != null) {
101: // Can't set the call graph roots after its been created
102: throw new IllegalStateException("Cannot set roots after "
103: + "call graph has been created");
104: }
105:
106: this .roots = roots;
107: }
108:
109: public CallGraph getCallGraph() {
110: if (this .callGraph == null) {
111: // Create a new CallGraph
112: this .callGraph = new CallGraph(this , this .roots);
113: }
114: return (this .callGraph);
115: }
116:
117: public InlineStats getInlineStats() {
118: if (inlineStats == null) {
119: inlineStats = new InlineStats();
120: }
121: return (inlineStats);
122: }
123:
124: public void addIgnorePackage(String name) {
125: name = name.replace('.', '/');
126: ignorePackages.add(name);
127: }
128:
129: public void addIgnoreClass(final Type type) {
130: ignoreClasses.add(type);
131: }
132:
133: public void addIgnoreMethod(final MemberRef method) {
134: ignoreMethods.add(method);
135: }
136:
137: public void addIgnoreField(final MemberRef field) {
138: ignoreFields.add(field);
139: }
140:
141: public void setIgnoreSystem(final boolean ignore) {
142: this .ignoreSystem = ignore;
143: }
144:
145: public boolean ignoreClass(final Type type) {
146: // First, check to see if we explicitly ignore it. If not, check
147: // to see if we ignore its package. The ladies always seem to
148: // ignore my package.
149: if (ignoreClasses.contains(type)) {
150: return (true);
151:
152: } else if (type.isPrimitive()) {
153: addIgnoreClass(type);
154: return (true);
155:
156: } else {
157: if (this .ignoreSystem) {
158: if (BloatContext.isSystem(type)) {
159: addIgnoreClass(type);
160: return (true);
161: }
162: }
163:
164: String packageName = type.className();
165: final int lastSlash = packageName.lastIndexOf('/');
166:
167: if (lastSlash == -1) {
168: return (false);
169: }
170:
171: packageName = packageName.substring(0, lastSlash);
172:
173: // If any ignore package is a prefix of the class's package,
174: // then ignore it. This makes our lives easier.
175: final Iterator packages = ignorePackages.iterator();
176: while (packages.hasNext()) {
177: final String s = (String) packages.next();
178: if (type.className().startsWith(s)) {
179: addIgnoreClass(type);
180: return (true);
181: }
182: }
183:
184: return (false);
185: }
186: }
187:
188: public boolean ignoreMethod(final MemberRef method) {
189: if (ignoreMethods.contains(method)) {
190: return (true);
191:
192: } else if (ignoreClass(method.declaringClass())) {
193: addIgnoreMethod(method);
194: return (true);
195: }
196: return (false);
197: }
198:
199: public boolean ignoreField(final MemberRef field) {
200: if (ignoreMethods.contains(field)) {
201: return (true);
202:
203: } else if (ignoreClass(field.declaringClass())) {
204: addIgnoreField(field);
205: return (true);
206: }
207: return (false);
208: }
209:
210: /**
211: * Commits all classes, methods, and fields, that have been modified.
212: */
213: public abstract void commitDirty();
214:
215: /**
216: * Test the ignore stuff.
217: */
218: public static void main(final String[] args) {
219: final PrintWriter out = new PrintWriter(System.out, true);
220: final PrintWriter err = new PrintWriter(System.err, true);
221:
222: final BloatContext context = new CachingBloatContext(
223: new ClassFileLoader(), new ArrayList(), false);
224:
225: final List types = new ArrayList();
226:
227: for (int i = 0; i < args.length; i++) {
228: if (args[i].equals("-ip")) {
229: if (++i >= args.length) {
230: err.println("** Missing package name");
231: System.exit(1);
232: }
233:
234: out.println("Ignoring package " + args[i]);
235: context.addIgnorePackage(args[i]);
236:
237: } else if (args[i].equals("-ic")) {
238: if (++i >= args.length) {
239: err.println("** Missing class name");
240: System.exit(1);
241: }
242:
243: out.println("Ignoring class " + args[i]);
244: final String type = args[i].replace('.', '/');
245: context.addIgnoreClass(Type.getType("L" + type + ";"));
246:
247: } else {
248: // A type
249: final String type = args[i].replace('.', '/');
250: types.add(Type.getType("L" + type + ";"));
251: }
252: }
253:
254: out.println("");
255:
256: final Iterator iter = types.iterator();
257: while (iter.hasNext()) {
258: final Type type = (Type) iter.next();
259: out.println("Ignore " + type + "? "
260: + context.ignoreClass(type));
261: }
262: }
263:
264: }
|