import org.apache.bcel.classfile.*;
import org.apache.bcel.util.*;
+ // SecurityManager hacks to avoid java.security?
+ // URL and all descendents? Probably impossible.
+ // ObjectInput/ObjectOutput? Serialization?
+
+ // superprune: URLClassLoader, convert.In/Output other than needed, unneeded locales
+ // reflective metadata is killing us...
+
// Reachability rules:
// - a constructor is reachable iff it is called
public class BytecodePruner {
public static final boolean deleteMethods = false;
-
- // FIXME
public static SyntheticRepository repo = null;
-
public static HashSet dest = new HashSet();
-
public static String outdir = ".";
public void loadAllMethods(String classname) throws Exception {
Method[] meths = getMethods(repo.loadClass(classname));
for(int i=0; i<meths.length; i++) visitJavaMethod(repo.loadClass(classname), meths[i]);
}
+
public void loadMethod(String classAndMethodName) throws Exception {
String classname = classAndMethodName.substring(0, classAndMethodName.lastIndexOf('.'));
String methodname = classAndMethodName.substring(classAndMethodName.lastIndexOf('.') + 1);
+ if (classname.endsWith("." + methodname)) methodname = "<init>";
visitJavaClass(repo.loadClass(classname));
Method[] meths = getMethods(repo.loadClass(classname));
for(int i=0; i<meths.length; i++)
if (meths[i].getName().equals(methodname))
visitJavaMethod(repo.loadClass(classname), meths[i]);
}
+
public static void main(String[] s) throws Exception {
+ BytecodePruner bcp = new BytecodePruner();
int start = 1;
if (s.length >= 3 && s[1].equals("-o")) { outdir = s[2]; start += 2; }
repo = SyntheticRepository.getInstance(new ClassPath(s[0]));
+ for(int i=start; i<s.length; i++)
+ if (s[i].endsWith(".class")) bcp.visitJavaClass(repo.loadClass(s[i].substring(0, s[i].length() - 6)));
+ else bcp.loadMethod(s[i]);
- BytecodePruner bcp = new BytecodePruner();
- for(int i=start; i<s.length; i++) {
- try {
- if (s[i].endsWith(".class")) {
- bcp.visitJavaClass(repo.loadClass(s[i].substring(0, s[i].length() - 6)));
- } else {
- JavaClass cl = repo.loadClass(s[i].substring(0, s[i].lastIndexOf('.')));;
- bcp.visitJavaClass(cl);
- Method[] meths = getMethods(cl);
- for(int j=0; j<meths.length; j++) {
- if (meths[j].getName().equals(s[i].substring(s[i].lastIndexOf('.') + 1)))
- bcp.visitJavaMethod(cl, meths[j]);
- }
- }
- } catch (Exception e) {
- System.out.println("WARNING: couldn't load class for " + s[i]);
- }
- }
-
- System.out.println("\n\n======================================================================\n");
-
- // we call start(), but the VM calls run()...
- bcp.loadMethod("java.lang.Thread.run");
+ bcp.loadMethod("java.lang.Thread.run"); // we call start(), but the VM calls run()...
+ bcp.loadAllMethods("gnu.gcj.runtime.StringBuffer"); // the compiler emits calls directly to this class
bcp.loadAllMethods("java.lang.SecurityContext");
+ bcp.loadAllMethods("java.lang.ThreadDeath");
bcp.visitJavaClass(repo.loadClass("java.awt.AWTPermission"));
bcp.visitJavaClass(repo.loadClass("gnu.classpath.Configuration"));
- bcp.loadAllMethods("java.lang.ThreadDeath");
-
bcp.loadAllMethods("java.util.Hashtable$HashIterator");
bcp.loadMethod("java.util.SimpleTimeZone.useDaylightTime");
- /*
- bcp.loadAllMethods("java.lang.Throwable");
- bcp.loadAllMethods("java.io.PrintStream");
- bcp.loadAllMethods("java.util.PropertyPermission");
- bcp.loadAllMethods("java.security.cert.Certificate");
- bcp.loadAllMethods("java.security.cert.CertificateEncodingException");
- bcp.loadMethod("java.util.TimeZone.getAvailableIDs");
- bcp.loadMethod("java.util.TimeZone.getDefaultTimeZoneId");
- bcp.loadAllMethods("gnu.gcj.runtime.StringBuffer");
- bcp.loadAllMethods("gnu.gcj.runtime.VMClassLoader");
- bcp.visitJavaClass(repo.loadClass("gnu.gcj.runtime.JNIWeakRef"));
- */
- /*
- bcp.visitJavaClass(repo.loadClass("gnu.gcj.protocol.http.Handler"));
- bcp.visitJavaClass(repo.loadClass("gnu.gcj.protocol.file.Handler"));
- bcp.visitJavaClass(repo.loadClass("gnu.gcj.protocol.jar.Handler"));
- bcp.visitJavaClass(repo.loadClass("gnu.gcj.protocol.core.Handler"));
- */
bcp.visitJavaClass(repo.loadClass("gnu.gcj.runtime.FinalizerThread"));
bcp.visitJavaClass(repo.loadClass("gnu.gcj.runtime.FirstThread"));
- // SecurityManager hacks to avoid java.security?
- // URL and all descendents? Probably impossible.
- // ObjectInput/ObjectOutput? Serialization?
-
- // often called from native subclasses....
- bcp.loadAllMethods("org.ibex.Surface");
- bcp.loadAllMethods("org.ibex.Template$TemplateHelper$1");
- bcp.loadAllMethods("org.ibex.Surface$DoubleBufferedSurface");
- bcp.loadAllMethods("org.ibex.Surface$3");
- bcp.loadAllMethods("org.ibex.Surface$2");
- bcp.loadAllMethods("org.ibex.Picture");
- bcp.loadAllMethods("org.ibex.PixelBuffer");
- bcp.loadAllMethods("org.ibex.Platform");
- bcp.loadAllMethods("org.ibex.Scheduler");
- bcp.loadAllMethods("org.ibex.plat.X11");
- bcp.loadAllMethods("org.ibex.plat.X11$X11Picture");
- bcp.loadAllMethods("org.ibex.plat.X11$X11PixelBuffer");
- bcp.loadAllMethods("org.ibex.plat.X11$X11Surface");
- bcp.loadAllMethods("org.ibex.XMLRPC");
-
- bcp.loadAllMethods("java.util.Date");
- bcp.loadAllMethods("java.text.DateFormat");
- bcp.loadAllMethods("java.text.NumberFormat");
-
-
- Method[] meths = getMethods(repo.loadClass("org.ibex.plat.Linux"));
- for(int i=0; i<meths.length; i++) {
- if (meths[i].getName().equals("main"))
- bcp.visitJavaMethod(repo.loadClass("org.ibex.plat.Linux"), meths[i]);
- }
- System.out.println();
-
- System.out.println("Dumping...");
-
- StringTokenizer st = new StringTokenizer(s[0], ":");
+ StringTokenizer st = new StringTokenizer(s[0], ":");
while(st.hasMoreTokens()) {
ZipFile zf = new ZipFile(st.nextToken());
Enumeration e = zf.entries();
ConstantPoolGen newcpg = new ConstantPoolGen(clazz.getConstantPool());
ClassGen cg = new ClassGen(clazz);
+ cg.setConstantPool(newcpg);
InstructionFactory factory = new InstructionFactory(cg, newcpg);
cg.setMajor(46);
cg.setMinor(0);
- cg.setConstantPool(newcpg);
+
Field[] fields = clazz.getFields();
int numFields = 0;
for(int i=0; i<fields.length; i++)
fields[i] = null;
} else numFields++;
- // superprune: URLClassLoader, convert.In/Output other than needed, unneeded locales
- // reflective metadata is killing us...
-
Method[] methods = getMethods(clazz);
int numMethods = 0;
boolean good = false;
for(int i=0; i<methods.length; i++)
- if (clazz.getClassName().startsWith("gnu.gcj.runtime.")
- || clazz.getClassName().startsWith("java.io.FileDescriptor")
- || clazz.getClassName().startsWith("org.ibex.")
- || clazz.getClassName().startsWith("java.lang.")) {
+ if (clazz.getClassName().startsWith("java.io.FileDescriptor")) {
good = true;
} else if (dest.contains(methods[i])) {
if (!methods[i].getName().equals("<clinit>")) good = true;
dest.add(method);
level += 2;
for(int i=0; i<level; i++) System.out.print(" ");
- ConstantPoolGen cpg = new ConstantPoolGen(method.getConstantPool());
+ ConstantPool cp = method.getConstantPool();
+ ConstantPoolGen cpg = new ConstantPoolGen(cp);
System.out.println(jc.getClassName() + "." + getMethodSignature(method, cpg));
markMethodInSubclasses(jc, method, cpg);
if (method.getCode() == null) { level -= 2; return; }
String[] exntypes = method.getExceptionTable().getExceptionNames();
for(int i=0; i<exntypes.length; i++) load(exntypes[i]);
}
+ if (method.getCode() != null && method.getCode().getExceptionTable() != null) {
+ CodeException[] exntypes = method.getCode().getExceptionTable();
+
+ for(int i=0; i<exntypes.length; i++) {
+ int index = exntypes[i].getCatchType();
+ if (index == 0) continue;
+ load(Utility.compactClassName(cp.getConstantString(index, Constants.CONSTANT_Class), false));
+ }
+ }
}
public void visitJavaField(Field field) throws Exception {
System.out.println(clazz.getClassName() + ".class");
JavaClass superclass = clazz.getSuperClass();
- JavaClass[] interfaces = clazz.getAllInterfaces();
- for(JavaClass sup = superclass; sup != null; sup = sup.getSuperClass()) {
- if (subclasses.get(sup) == null) subclasses.put(sup, new HashSet());
- ((HashSet)subclasses.get(sup)).add(clazz);
- }
- for(int i=0; i<interfaces.length; i++) {
- if (subclasses.get(interfaces[i]) == null) subclasses.put(interfaces[i], new HashSet());
- ((HashSet)subclasses.get(interfaces[i])).add(clazz);
+ for(JavaClass sup = clazz; sup != null; sup = sup.getSuperClass()) {
+ if (sup != clazz) {
+ if (subclasses.get(sup) == null) subclasses.put(sup, new HashSet());
+ ((HashSet)subclasses.get(sup)).add(clazz);
+ }
+ JavaClass[] interfaces = sup.getAllInterfaces();
+ for(int i=0; i<interfaces.length; i++) {
+ if (subclasses.get(interfaces[i]) == null) subclasses.put(interfaces[i], new HashSet());
+ ((HashSet)subclasses.get(interfaces[i])).add(clazz);
+ }
}
- if (clazz.getClassName().startsWith("org.ibex."))
- loadAllMethods(clazz.getClassName());
+ if (clazz.getClassName().startsWith("org.ibex.")) loadAllMethods(clazz.getClassName());
- for(JavaClass sup = superclass; sup != null; sup = sup.getSuperClass()) {
- visitJavaClass(sup);
- remarkMethods(sup, clazz, cpg);
- }
- for(int i=0; i<interfaces.length; i++) {
- visitJavaClass(interfaces[i]);
- remarkMethods(interfaces[i], clazz, cpg);
+ for(JavaClass sup = clazz; sup != null; sup = sup.getSuperClass()) {
+ if (sup != clazz) {
+ visitJavaClass(sup);
+ remarkMethods(sup, clazz, cpg);
+ }
+ JavaClass[] interfaces = sup.getAllInterfaces();
+ for(int i=0; i<interfaces.length; i++) {
+ visitJavaClass(interfaces[i]);
+ remarkMethods(interfaces[i], clazz, cpg);
+ }
}
Field[] fields = clazz.getFields();
String sig = getMethodSignature(m, cpg);
Method[] submethods = getMethods(subclass);
for(int j=0; j<submethods.length; j++)
- if (getMethodSignature(submethods[j], cpg).equals(sig))
+ //if (getMethodSignature(submethods[j], cpg).equals(sig))
+ if (submethods[j].getName().equals(m.getName()))
visitJavaMethod(subclass, submethods[j]);
}
public void markMethodInSubclasses(JavaClass c, Method m, ConstantPoolGen cpg) throws Exception {