# HG changeset patch # User Jaroslav Tulach # Date 1353047792 -3600 # Node ID 70e7710a65dc4170f7032149a2214143b40bdd53 # Parent 978301fdb4ec53724f1c1aaa8c00fe30004de7fa Eliminating references to java.util classes that have too huge transitive closure. diff -r 978301fdb4ec -r 70e7710a65dc vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Nov 15 08:12:52 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri Nov 16 07:36:32 2012 +0100 @@ -19,9 +19,6 @@ import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import org.apidesign.bck2brwsr.core.ExtraJavaScript; import org.apidesign.bck2brwsr.core.JavaScriptBody; import sun.tools.javap.AnnotationParser; @@ -34,63 +31,57 @@ * * @author Jaroslav Tulach */ -public final class ByteCodeToJavaScript { - private final ClassData jc; +public abstract class ByteCodeToJavaScript { + private ClassData jc; private final Appendable out; - private final Collection references; - private ByteCodeToJavaScript( - ClassData jc, Appendable out, Collection references - ) { - this.jc = jc; + protected ByteCodeToJavaScript(Appendable out) { this.out = out; - this.references = references; } + + /* Collects additional required resources. + * + * @param internalClassName classes that were referenced and should be loaded in order the + * generated JavaScript code works properly. The names are in internal + * JVM form so String is java/lang/String. + */ + protected abstract boolean requireReference(String internalClassName); + + /* + * @param resourcePath name of resources to read + */ + protected abstract void requireScript(String resourcePath); /** * Converts a given class file to a JavaScript version. * * @param classFile input stream with code of the .class file - * @param out a {@link StringBuilder} or similar to generate the output to - * @param references a write only collection where the system adds list of - * other classes that were referenced and should be loaded in order the - * generated JavaScript code works properly. The names are in internal - * JVM form so String is java/lang/String. Can be null - * if one is not interested in knowing references - * @param scripts write only collection with names of resources to read * @return the initialization code for this class, if any. Otherwise null * * @throws IOException if something goes wrong during read or write or translating */ - public static String compile( - InputStream classFile, Appendable out, - Collection references, - Collection scripts - ) throws IOException { - ClassData jc = new ClassData(classFile); + public String compile(InputStream classFile) throws IOException { + this.jc = new ClassData(classFile); byte[] arrData = jc.findAnnotationData(true); String[] arr = findAnnotation(arrData, jc, ExtraJavaScript.class.getName(), "resource", "processByteCode"); if (arr != null) { - scripts.add(arr[0]); + requireScript(arr[0]); if ("0".equals(arr[1])) { return null; } } - ByteCodeToJavaScript compiler = new ByteCodeToJavaScript( - jc, out, references - ); - List toInitilize = new ArrayList(); + StringArray toInitilize = new StringArray(); for (MethodData m : jc.getMethods()) { if (m.isStatic()) { - compiler.generateStaticMethod(m, toInitilize); + generateStaticMethod(m, toInitilize); } else { - compiler.generateInstanceMethod(m); + generateInstanceMethod(m); } } for (FieldData v : jc.getFields()) { if (v.isStatic()) { - compiler.generateStaticField(v); + generateStaticField(v); } } @@ -119,7 +110,7 @@ } for (MethodData m : jc.getMethods()) { if (!m.getName().contains("") && !m.getName().contains("")) { - compiler.generateMethodReference("\n p.", m); + generateMethodReference("\n p.", m); } } out.append("\n p.$instOf_").append(className).append(" = true;"); @@ -130,12 +121,12 @@ out.append("\n}"); out.append("\n").append(className).append("_proto();"); StringBuilder sb = new StringBuilder(); - for (String init : toInitilize) { + for (String init : toInitilize.toArray()) { sb.append("\n").append(init).append("();"); } return sb.toString(); } - private void generateStaticMethod(MethodData m, List toInitilize) throws IOException { + private void generateStaticMethod(MethodData m, StringArray toInitilize) throws IOException { if (javaScriptBody(m, true)) { return; } @@ -952,10 +943,8 @@ } private void addReference(String cn) throws IOException { - if (references != null) { - if (references.add(cn)) { - out.append(" /* needs ").append(cn).append(" */"); - } + if (requireReference(cn)) { + out.append(" /* needs ").append(cn).append(" */"); } } diff -r 978301fdb4ec -r 70e7710a65dc vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java Thu Nov 15 08:12:52 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java Fri Nov 16 07:36:32 2012 +0100 @@ -20,49 +20,33 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; /** Generator of JavaScript from bytecode of classes on classpath of the VM. * * @author Jaroslav Tulach */ -final class GenJS { - private GenJS() {} +final class GenJS extends ByteCodeToJavaScript { + public GenJS(Appendable out) { + super(out); + } static void compile(Appendable out, String... names) throws IOException { - compile(out, Arrays.asList(names)); + compile(out, StringArray.asList(names)); } - static void compile(Appendable out, List names) throws IOException { + static void compile(Appendable out, StringArray names) throws IOException { compile(GenJS.class.getClassLoader(), out, names); } - static void compile(ClassLoader l, Appendable out, List names) throws IOException { - final Map processed = new HashMap(); - for (String baseClass : names) { - LinkedHashSet toProcess = new LinkedHashSet() { - @Override - public boolean add(String e) { - if (processed.containsKey(e)) { - return false; - } - return super.add(e); - } - }; - toProcess.add(baseClass); + static void compile(ClassLoader l, Appendable out, StringArray names) throws IOException { + StringArray processed = new StringArray(); + StringArray initCode = new StringArray(); + for (String baseClass : names.toArray()) { + GenJS js = new GenJS(out); + js.references.add(baseClass); for (;;) { String name = null; - Iterator it = toProcess.iterator(); - while (it.hasNext() && name == null) { - String n = it.next(); - if (processed.get(n) != null) { + for (String n : js.references.toArray()) { + if (processed.contains(n)) { continue; } name = n; @@ -70,18 +54,14 @@ if (name == null) { break; } - if (name.startsWith("sun/")) { - processed.put(name, ""); - continue; - } InputStream is = loadClass(l, name); if (is == null) { throw new IOException("Can't find class " + name); } - LinkedList scripts = new LinkedList(); try { - String initCode = ByteCodeToJavaScript.compile(is, out, toProcess, scripts); - processed.put(name, initCode == null ? "" : initCode); + String ic = js.compile(is); + processed.add(name); + initCode.add(ic == null ? "" : ic); } catch (RuntimeException ex) { if (out instanceof CharSequence) { CharSequence seq = (CharSequence)out; @@ -100,7 +80,7 @@ ); } } - for (String resource : scripts) { + for (String resource : js.scripts.toArray()) { while (resource.startsWith("/")) { resource = resource.substring(1); } @@ -112,14 +92,14 @@ } } - List toInit = new ArrayList(toProcess); - Collections.reverse(toInit); + StringArray toInit = StringArray.asList(js.references.toArray()); + toInit.reverse(); - for (String clazz : toInit) { - String initCode = processed.get(clazz); - if (initCode != null && !initCode.isEmpty()) { - out.append(initCode).append("\n"); - processed.put(clazz, ""); + for (String ic : toInit.toArray()) { + int indx = processed.indexOf(ic); + if (indx >= 0) { + out.append(initCode.toArray()[indx]).append("\n"); + initCode.toArray()[indx] = ""; } } @@ -180,6 +160,9 @@ if (u == null) { throw new IOException("Can't find " + name); } + if (u.toExternalForm().contains("rt.jar!")) { + throw new IOException("No emulation for " + u); + } return u.openStream(); } @@ -188,4 +171,21 @@ compile(sb, name); return sb.toString().toString(); } + + private StringArray scripts = new StringArray(); + private StringArray references = new StringArray(); + + @Override + protected boolean requireReference(String cn) { + if (references.contains(cn)) { + return false; + } + references.add(cn); + return true; + } + + @Override + protected void requireScript(String resourcePath) { + scripts.add(resourcePath); + } } diff -r 978301fdb4ec -r 70e7710a65dc vm/src/main/java/org/apidesign/vm4brwsr/Main.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Thu Nov 15 08:12:52 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Fri Nov 16 07:36:32 2012 +0100 @@ -21,8 +21,6 @@ import java.io.FileWriter; import java.io.IOException; import java.io.Writer; -import java.util.Arrays; -import java.util.List; /** Generator of JavaScript from bytecode of classes on classpath of the VM * with a Main method. @@ -39,7 +37,8 @@ } Writer w = new BufferedWriter(new FileWriter(args[0])); - List classes = Arrays.asList(args).subList(1, args.length); + StringArray classes = StringArray.asList(args); + classes.delete(0); GenJS.compile(w, classes); w.close(); } diff -r 978301fdb4ec -r 70e7710a65dc vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Fri Nov 16 07:36:32 2012 +0100 @@ -0,0 +1,84 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.vm4brwsr; + +/** + * + * @author Jaroslav Tulach + */ +class StringArray { + private String[] arr; + + public StringArray() { + } + + private StringArray(String[] arr) { + this.arr = arr; + } + + public void add(String s) { + if (arr == null) { + arr = new String[1]; + } else { + String[] tmp = new String[arr.length + 1]; + for (int i = 0; i < arr.length; i++) { + tmp[i] = arr[i]; + } + arr = tmp; + } + arr[arr.length - 1] = s; + } + + public String[] toArray() { + return arr == null ? new String[0] : arr; + } + + static StringArray asList(String[] names) { + return new StringArray(names); + } + + void reverse() { + for (int i = 0, j = arr.length; i < j; i++) { + String s = arr[i]; + arr[i] = arr[--j]; + arr[j] = s; + } + } + + boolean contains(String n) { + if (arr == null) { + return false; + } + for (int i = 0; i < arr.length; i++) { + if (n.equals(arr[i])) { + return true; + } + } + return false; + } + + void delete(int indx) { + if (arr == null) { + return; + } + String[] tmp = new String[arr.length - 1]; + for (int i = 0, j = 0; i < arr.length; i++) { + tmp[j] = arr[i]; + if (j == indx) { + continue; + } + } + } + + int indexOf(String ic) { + for (int i = 0; i < arr.length; i++) { + if (ic.equals(arr[i])) { + return i; + } + } + return -1; + } + +}