/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package EDU.purdue.cs.bloat.context;
import java.io.*;
import java.util.*;
import EDU.purdue.cs.bloat.editor.*;
import EDU.purdue.cs.bloat.file.*;
import EDU.purdue.cs.bloat.inline.*;
import EDU.purdue.cs.bloat.reflect.*;
/**
* This abstract class is a central repository for all things that are necessary
* for a BLOATing sessions. Its subclasses implement certain schemes for
* managing BLOAT data structures such as editors and control flow graphs.
*/
public abstract class BloatContext implements InlineContext {
public static boolean DEBUG = Boolean.getBoolean("BloatContext.DEBUG");
protected InlineStats inlineStats;
// Ignore stuff for inlining
protected Set ignorePackages = new HashSet();
protected Set ignoreClasses = new HashSet();
protected Set ignoreMethods = new HashSet();
protected Set ignoreFields = new HashSet();
protected boolean ignoreSystem = false;
protected CallGraph callGraph;
protected Set roots; // Root methods of call graph
protected static void db(final String s) {
if (BloatContext.DEBUG) {
System.out.println(s);
}
}
protected ClassInfoLoader loader;
/**
* Constructor. Each <tt>BloatContext</tt> needs to know about a
* <tt>ClassInfoLoader</tt>.
*/
public BloatContext(final ClassInfoLoader loader) {
this.loader = loader;
}
private static ClassLoader systemCL;
static {
final String s = "";
BloatContext.systemCL = s.getClass().getClassLoader();
}
/**
* Returns <tt>true</tt> if the give type is a system class (that is, has
* the same class loader as java.lang.String).
*/
public static boolean isSystem(final Type type) {
Class c = null;
try {
c = Class.forName(type.className().replace('/', '.'));
} catch (final ClassNotFoundException ex) {
System.err.println("** Could not find class " + type.className());
ex.printStackTrace(System.err);
System.exit(1);
}
// Have to use == because class loader might be null
return (c.getClassLoader() == BloatContext.systemCL);
}
public void setRootMethods(final Set roots) {
if (this.callGraph != null) {
// Can't set the call graph roots after its been created
throw new IllegalStateException("Cannot set roots after "
+ "call graph has been created");
}
this.roots = roots;
}
public CallGraph getCallGraph() {
if (this.callGraph == null) {
// Create a new CallGraph
this.callGraph = new CallGraph(this, this.roots);
}
return (this.callGraph);
}
public InlineStats getInlineStats() {
if (inlineStats == null) {
inlineStats = new InlineStats();
}
return (inlineStats);
}
public void addIgnorePackage(String name) {
name = name.replace('.', '/');
ignorePackages.add(name);
}
public void addIgnoreClass(final Type type) {
ignoreClasses.add(type);
}
public void addIgnoreMethod(final MemberRef method) {
ignoreMethods.add(method);
}
public void addIgnoreField(final MemberRef field) {
ignoreFields.add(field);
}
public void setIgnoreSystem(final boolean ignore) {
this.ignoreSystem = ignore;
}
public boolean ignoreClass(final Type type) {
// First, check to see if we explicitly ignore it. If not, check
// to see if we ignore its package. The ladies always seem to
// ignore my package.
if (ignoreClasses.contains(type)) {
return (true);
} else if (type.isPrimitive()) {
addIgnoreClass(type);
return (true);
} else {
if (this.ignoreSystem) {
if (BloatContext.isSystem(type)) {
addIgnoreClass(type);
return (true);
}
}
String packageName = type.className();
final int lastSlash = packageName.lastIndexOf('/');
if (lastSlash == -1) {
return (false);
}
packageName = packageName.substring(0, lastSlash);
// If any ignore package is a prefix of the class's package,
// then ignore it. This makes our lives easier.
final Iterator packages = ignorePackages.iterator();
while (packages.hasNext()) {
final String s = (String) packages.next();
if (type.className().startsWith(s)) {
addIgnoreClass(type);
return (true);
}
}
return (false);
}
}
public boolean ignoreMethod(final MemberRef method) {
if (ignoreMethods.contains(method)) {
return (true);
} else if (ignoreClass(method.declaringClass())) {
addIgnoreMethod(method);
return (true);
}
return (false);
}
public boolean ignoreField(final MemberRef field) {
if (ignoreMethods.contains(field)) {
return (true);
} else if (ignoreClass(field.declaringClass())) {
addIgnoreField(field);
return (true);
}
return (false);
}
/**
* Commits all classes, methods, and fields, that have been modified.
*/
public abstract void commitDirty();
/**
* Test the ignore stuff.
*/
public static void main(final String[] args) {
final PrintWriter out = new PrintWriter(System.out, true);
final PrintWriter err = new PrintWriter(System.err, true);
final BloatContext context = new CachingBloatContext(
new ClassFileLoader(), new ArrayList(), false);
final List types = new ArrayList();
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-ip")) {
if (++i >= args.length) {
err.println("** Missing package name");
System.exit(1);
}
out.println("Ignoring package " + args[i]);
context.addIgnorePackage(args[i]);
} else if (args[i].equals("-ic")) {
if (++i >= args.length) {
err.println("** Missing class name");
System.exit(1);
}
out.println("Ignoring class " + args[i]);
final String type = args[i].replace('.', '/');
context.addIgnoreClass(Type.getType("L" + type + ";"));
} else {
// A type
final String type = args[i].replace('.', '/');
types.add(Type.getType("L" + type + ";"));
}
}
out.println("");
final Iterator iter = types.iterator();
while (iter.hasNext()) {
final Type type = (Type) iter.next();
out.println("Ignore " + type + "? " + context.ignoreClass(type));
}
}
}