"java.security.*"
};
+ private static final String[] IGNORED_FIELDS = {
+ "java.io.ObjectInputStream.SUBCLASS_IMPLEMENTATION_PERMISSION"
+ };
+
private static final String[] NO_OUTPUT = { "java", "javax", "sun", "com.sun", "apple", "com.apple" };
System.exit(1);
}
GCClass gc = new GCClass(args[0]);
- for(int i=2;i<args.length;i++) gc.referenceMethod(args[i]);
+ for(int i=2;i<args.length;i++) {
+ if(args[i].startsWith("hint:"))
+ gc.parseHint(args[i].substring(5));
+ else
+ gc.referenceMethod(args[i]);
+ }
gc.go();
gc.dump(new File(args[1]));
}
private final Hashtable completed = new Hashtable();
private final Hashtable references = new Hashtable();
private final Hashtable instansiated = new Hashtable();
+ private final Hashtable hints = new Hashtable();
public GCClass(String classpath) throws ClassNotFoundException {
if(classpath.startsWith("="))
}
}
}
+
+ public void parseHint(String s) throws ClassNotFoundException {
+ int p = s.indexOf(':');
+ if(p == -1) throw new IllegalArgumentException("invalid hint");
+ String cms = s.substring(0,p);
+ String hint = s.substring(p+1);
+ p = cms.lastIndexOf('.');
+ if(p == -1) throw new IllegalArgumentException("invalid hint");
+ String cs = cms.substring(0,p);
+ String ms = cms.substring(p+1);
+
+ JavaClass c = repoGet(cs);
+ Method[] methods = c.getMethods();
+ for(int i=0;i<methods.length;i++) {
+ if(ms.equals("*") || methods[i].getName().equals(ms)) {
+ MethodRef mr = new MethodRef(c,methods[i]);
+ Vector v = (Vector) hints.get(mr);
+ if(v == null) hints.put(mr,v=new Vector());
+ v.add(hint);
+ }
+ }
+ }
private final void referenceMethod(MethodRef m) {
if(completed.get(m) != null) return;
for(int i=0;i<m.args.length;i++) referenceClass(m.args[i]);
}
- private final void referenceField(FieldRef f) {
+ private final void referenceField(FieldRef f) throws ClassNotFoundException {
+ if(completed.get(f) != null) return;
+
Hashtable h = classRefHash(f.c);
h.put(f,Boolean.TRUE);
+
+ // process(FieldRef) doesn't create much work so we don't bother queuing it
+ process(f);
+
referenceClass(f.ftype);
}
}
}
}
-
+
private void fixup() throws ClassNotFoundException {
for(Enumeration e = references.keys(); e.hasMoreElements(); ) {
ObjectType t = (ObjectType) e.nextElement();
JavaClass c = repoGet(t);
- if(c == null) continue;
-
Hashtable refs = (Hashtable) references.get(t);
- // add a ref to clinit is any fields/methods are referenced
+
+ if(c == null) continue;
+
+ // add a ref to clinit if any fields/methods are referenced
if(refs.size() != 0) {
MethodRef clinit = new MethodRef(t,"<clinit>",Type.VOID,Type.NO_ARGS);
if(findMethod(c,clinit) != null) referenceMethod(clinit);
else if(i instanceof InvokeInstruction) // INVOKESTATIC, INVOKEVIRTUAL, INVOKESPECIAL
referenceMethod(new MethodRef((InvokeInstruction)i,cpg,mr));
}
+
+ if(hints.get(mr) != null) {
+ Vector v = (Vector) hints.get(mr);
+ for(int i=0;i<v.size();i++) referenceMethod((String) v.elementAt(i));
+ }
+ }
+
+ private void process(FieldRef fr) throws ClassNotFoundException {
+ if(completed.get(fr) != null) return;
+ completed.put(fr,Boolean.TRUE);
+
+ JavaClass c = repoGet(fr.c.toString());
+ Field f = findField(c,fr);
+ if(f == null) {
+ JavaClass supers[] = c.getSuperClasses();
+ for(int i=0;i<supers.length;i++) {
+ f = findField(supers[i],fr);
+ if(f != null) { referenceField(new FieldRef(supers[i],f)); return; }
+ }
+ String sig = fr.toString();
+ for(int i=0;i<IGNORED_FIELDS.length;i++) {
+ String pat = IGNORED_FIELDS[i];
+ if(pat.endsWith("*") ? sig.startsWith(pat.substring(0,pat.length()-1)) : sig.equals(pat)) return;
+ }
+ throw new ClassNotFoundException("" + fr + " not found (but the class was)");
+ }
+ /* nothing to do */
}
private static Method findMethod(JavaClass c, MethodRef mr) {
return null;
}
+ private static Field findField(JavaClass c, FieldRef fr) {
+ Field[] fs = c.getFields();
+ for(int i=0;i<fs.length;i++) {
+ Field f = fs[i];
+ if(f.getName().equals(fr.name) && f.getType().equals(fr.ftype))
+ return f;
+ }
+ return null;
+ }
+
public void dump(File outdir) throws IOException, ClassNotFoundException {
if(!outdir.isDirectory()) throw new IOException("" + outdir + " is not a directory");
OUTER: for(Enumeration e = references.keys(); e.hasMoreElements(); ) {