X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Futil%2FNanoGoat.java;fp=src%2Forg%2Fibex%2Futil%2FBytecodePruner.java;h=7f1a50e108bf3e0511260ee4cdf121a825438f27;hp=a61c84db8591ac53628e6ccff57b577d1f168e32;hb=a41252ba1e0f5dd90100aa2064c011268809c038;hpb=a6c4f7b784acf2269c33188982b0d479cc11a0f4 diff --git a/src/org/ibex/util/BytecodePruner.java b/src/org/ibex/util/NanoGoat.java similarity index 64% rename from src/org/ibex/util/BytecodePruner.java rename to src/org/ibex/util/NanoGoat.java index a61c84d..7f1a50e 100644 --- a/src/org/ibex/util/BytecodePruner.java +++ b/src/org/ibex/util/NanoGoat.java @@ -7,16 +7,19 @@ import org.apache.bcel.generic.*; import org.apache.bcel.classfile.*; import org.apache.bcel.util.*; -public class BytecodePruner { +public class NanoGoat { public static final boolean deleteMethods = false; public static SyntheticRepository repo = null; public static HashSet dest = new HashSet(); + public static HashSet constructed = new HashSet(); public static String outdir = "."; public static Hashtable subclasses = new Hashtable(); + public static Hashtable uponconstruction = new Hashtable(); + public static Hashtable mark_if_constructed = new Hashtable(); public static int level = 0; - public BytecodePruner() { } + public NanoGoat() { } public void loadAllMethods(String classname) throws Exception { visitJavaClass(repo.loadClass(classname)); @@ -25,16 +28,13 @@ public class BytecodePruner { visitJavaMethod(repo.loadClass(classname), meths[i]); } - public void loadField(String classAndMethodName) throws Exception { - String classname = classAndMethodName.substring(0, classAndMethodName.lastIndexOf('.')); - String methodname = classAndMethodName.substring(classAndMethodName.lastIndexOf('.') + 1); + public void loadAllStaticMethods(String classname) throws Exception { visitJavaClass(repo.loadClass(classname)); - Field[] meths = repo.loadClass(classname).getFields(); + Method[] meths = getMethods(repo.loadClass(classname)); for(int i=0; i= 3 && s[1].equals("-o")) { outdir = s[2]; start += 2; } repo = SyntheticRepository.getInstance(new ClassPath(s[0])); - BytecodePruner bcp = new BytecodePruner(); + NanoGoat bcp = new NanoGoat(); for(int i=start; i")) - constructed = true; + isconstructed = true; // we can only prune static fields (to avoid altering object layout, which is hardcoded into // CNI code), but that's okay since instance fields don't contribute to binary size Field[] fields = clazz.getFields(); for(int i=0; i")) good = true; + if (dest.contains(methods[i]) && (isconstructed || methods[i].isStatic())) { + good = true; } else { if (methods[i].getCode() == null) { System.out.println(" empty codeblock: " + clazz.getClassName() + "." + methods[i].getName()); } else { - System.out.println(" pruning " +(constructed?"":"unconstructed")+ " method " + + System.out.println(" pruning " +(isconstructed?"":"unconstructed")+ " method " + clazz.getClassName() + "." + methods[i].getName()); - // FIXME: try deleteMethods if (deleteMethods) { cg.removeMethod(methods[i]); continue; } MethodGen mg = new MethodGen(methods[i], clazz.getClassName(), newcpg); mg.removeExceptions(); @@ -186,7 +201,12 @@ public class BytecodePruner { } } - if (!good) { + // FIXME: chain up to superclass' ... that might remove the need for this hack + // FIXME: gcj compiling in jar-at-a-time mode can't be convinced to let classes outside the jar override + // the ones inside the jar + good = true; + + if (!good && !clazz.isAbstract() && !clazz.isInterface()) { System.out.println("DROPPING " + clazz.getClassName()); JavaClass[] ifaces = clazz.getInterfaces(); String[] ifacestrings = new String[ifaces.length]; @@ -200,8 +220,10 @@ public class BytecodePruner { } else { System.out.println("dumping " + clazz.getClassName()); } - new File(outdir + "/" + new File(clazz.getClassName().replace('.', '/')).getParent()).mkdirs(); - cg.getJavaClass().dump(outdir + "/" + clazz.getClassName().replace('.', '/') + ".class"); + FilterOutputStream noclose = new FilterOutputStream(zos) { public void close() throws IOException { flush(); } }; + zos.putNextEntry(new ZipEntry(clazz.getClassName().replace('.', '/')+".class")); + cg.getJavaClass().dump(noclose); + noclose.flush(); } public JavaClass sig2class(String sig) throws Exception { @@ -245,38 +267,73 @@ public class BytecodePruner { visitJavaClass(jc); if (jc.getClassName().indexOf("SharedLib") != -1) return; if (jc.getClassName().indexOf("Datagram") != -1) return; + if (jc.getClassName().startsWith("java.io.Object")) return; + if (jc.getClassName().startsWith("java.util.jar.")) return; + if (jc.getClassName().startsWith("java.net.Inet6")) return; // gcj bug; gcj can't compile this method from a .class file input; I have no idea why if (jc.getClassName().equals("java.lang.System") && method.getName().equals("runFinalizersOnExit")) return; + // we know these can't be constructed + if (method.getName().equals("") && jc.getClassName().startsWith("java.lang.reflect.")) return; + if (dest.contains(method)) return; dest.add(method); - if (method.isStatic()) loadMethod(jc.getClassName() + "."); + if (method.getName().equals("") && jc.getSuperClass() != null) + loadMethod(jc.getSuperClass().getClassName() + "."); + + if (method.isStatic() || method.getName().equals("")) loadMethod(jc.getClassName() + "."); + if (method.getName().equals("")) { + // FIXME: generalize to all perinstancemethods + constructed.add(jc); + HashSet hs = (HashSet)uponconstruction.get(jc); + if (hs != null) { + Iterator it = hs.iterator(); + while(it.hasNext()) visitJavaMethod(jc, (Method)it.next()); + } + loadMethod(jc.getClassName() + ".equals"); + loadMethod(jc.getClassName() + ".hashCode"); + loadMethod(jc.getClassName() + ".toString"); + loadMethod(jc.getClassName() + ".finalize"); + loadMethod(jc.getClassName() + ".clone"); + } + + ConstantPoolGen cpg = new ConstantPoolGen(method.getConstantPool()); + if (!method.isStatic() && !constructed.contains(jc)) { + HashSet hs = (HashSet)uponconstruction.get(jc); + if (hs == null) uponconstruction.put(jc, hs = new HashSet()); + hs.add(method); + markMethodInSubclasses(jc, method, cpg); + dest.remove(method); + return; + } level += 2; for(int i=0; i"); } if (instr instanceof CPInstruction) load(((CPInstruction)instr).getType(cpg)); - if (instr instanceof TypedInstruction) { - try { load(((TypedInstruction)instr).getType(cpg)); } catch (Exception e) { /* DELIBERATE */ } - } - if (instr instanceof NEW) { - for(int j=0; j"); - } + if (instr instanceof TypedInstruction) load(((TypedInstruction)instr).getType(cpg)); + if (instr instanceof NEW) loadMethod(((NEW)instr).getLoadClassType(cpg).getClassName() + "."); if (instr instanceof org.apache.bcel.generic.FieldOrMethod) load(((org.apache.bcel.generic.FieldOrMethod)instr).getClassType(cpg)); if (instr instanceof org.apache.bcel.generic.FieldInstruction) { @@ -286,7 +343,7 @@ public class BytecodePruner { JavaClass jc2 = repo.loadClass(((ObjectType)((org.apache.bcel.generic.FieldInstruction)instr). getLoadClassType(cpg)).getClassName()); Field[] fields = jc2.getFields(); - for(int j=0; j"); } public void visitJavaClass(JavaClass clazz) throws Exception { @@ -326,6 +383,8 @@ public class BytecodePruner { dest.add(clazz); ConstantPoolGen cpg = new ConstantPoolGen(clazz.getConstantPool()); + level += 2; + for(int i=0; i")) visitJavaMethod(clazz, methods[i]); - if (methods[i].getName().equals("equals")) visitJavaMethod(clazz, methods[i]); - if (methods[i].getName().equals("hashCode")) visitJavaMethod(clazz, methods[i]); - if (methods[i].getName().equals("finalize")) visitJavaMethod(clazz, methods[i]); - if (methods[i].getName().equals("clone")) visitJavaMethod(clazz, methods[i]); - if (methods[i].getName().equals("toString")) visitJavaMethod(clazz, methods[i]); - } + level -= 2; } public void markMethodInSubclasses(JavaClass c, Method m, JavaClass subclass, ConstantPoolGen cpg) throws Exception { if (m.isStatic()) return; + if (m.getName().equals("")) return; + if (m.getName().equals("equals")) return; + if (m.getName().equals("hashCode")) return; + if (m.getName().equals("clone")) return; + if (m.getName().equals("finalize")) return; + if (m.getName().equals("toString")) return; String sig = getMethodSignature(m, cpg); Method[] submethods = getMethods(subclass); for(int j=0; j")) return; HashSet s = (HashSet)subclasses.get(c); if (s == null) return; Object[] subclasses = s.toArray(); @@ -390,12 +447,18 @@ public class BytecodePruner { public void remarkMethods(JavaClass c, ConstantPoolGen cpg) throws Exception { Method[] meths =getMethods(c); - for(int j=0; j