Partially working extension modules closure
authorLubomir Nerad <lubomir.nerad@oracle.com>
Fri, 26 Apr 2013 18:48:34 +0200
branchclosure
changeset 1029b1fe994d4267
parent 1020 a6bacea2518f
child 1082 977cc6141083
Partially working extension modules
dew/src/main/java/org/apidesign/bck2brwsr/dew/Dew.java
dew/src/main/java/org/apidesign/bck2brwsr/dew/DewLauncher.java
rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java
rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/ExportedSymbols.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java
rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java
rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java
     1.1 --- a/dew/src/main/java/org/apidesign/bck2brwsr/dew/Dew.java	Thu Apr 25 16:17:48 2013 +0200
     1.2 +++ b/dew/src/main/java/org/apidesign/bck2brwsr/dew/Dew.java	Fri Apr 26 18:48:34 2013 +0200
     1.3 @@ -135,9 +135,4 @@
     1.4          byte[] arr = data == null ? null : data.get(r);
     1.5          return arr == null ? null : new ByteArrayInputStream(arr);
     1.6      }
     1.7 -
     1.8 -    @Override
     1.9 -    public String getModule(String resource) throws IOException {
    1.10 -        return null;
    1.11 -    }
    1.12  }
     2.1 --- a/dew/src/main/java/org/apidesign/bck2brwsr/dew/DewLauncher.java	Thu Apr 25 16:17:48 2013 +0200
     2.2 +++ b/dew/src/main/java/org/apidesign/bck2brwsr/dew/DewLauncher.java	Fri Apr 26 18:48:34 2013 +0200
     2.3 @@ -122,11 +122,6 @@
     2.4              }
     2.5              throw new IOException("Can't find " + resource);
     2.6          }
     2.7 -
     2.8 -        @Override
     2.9 -        public String getModule(String resource) throws IOException {
    2.10 -            return null;
    2.11 -        }
    2.12      }
    2.13  
    2.14      private static class VM extends HttpHandler {
     3.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Thu Apr 25 16:17:48 2013 +0200
     3.2 +++ b/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Fri Apr 26 18:48:34 2013 +0200
     3.3 @@ -460,11 +460,6 @@
     3.4              }
     3.5              throw new IOException("Can't find " + resource);
     3.6          }
     3.7 -
     3.8 -        @Override
     3.9 -        public String getModule(String resource) throws IOException {
    3.10 -            return null;
    3.11 -        }
    3.12      }
    3.13  
    3.14      private static class Page extends HttpHandler {
     4.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java	Thu Apr 25 16:17:48 2013 +0200
     4.2 +++ b/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java	Fri Apr 26 18:48:34 2013 +0200
     4.3 @@ -128,10 +128,5 @@
     4.4              }
     4.5              throw new IOException("Can't find " + resource);
     4.6          }
     4.7 -
     4.8 -        @Override
     4.9 -        public String getModule(String resource) throws IOException {
    4.10 -            return null;
    4.11 -        }
    4.12      }
    4.13  }
     5.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Thu Apr 25 16:17:48 2013 +0200
     5.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Fri Apr 26 18:48:34 2013 +0200
     5.3 @@ -57,11 +57,13 @@
     5.4      private final ObfuscationLevel level;
     5.5      private final StringArray classes;
     5.6      private final Resources res;
     5.7 +    private final boolean extension;
     5.8  
     5.9 -    private Bck2Brwsr(ObfuscationLevel level, StringArray classes, Resources resources) {
    5.10 +    private Bck2Brwsr(ObfuscationLevel level, StringArray classes, Resources resources, boolean extension) {
    5.11          this.level = level;
    5.12          this.classes = classes;
    5.13          this.res = resources;
    5.14 +        this.extension = extension;
    5.15      }
    5.16      
    5.17      /** Helper method to generate virtual machine from bytes served by a <code>resources</code>
    5.18 @@ -98,8 +100,10 @@
    5.19       * @since 0.5
    5.20       */
    5.21      public static Bck2Brwsr newCompiler() {
    5.22 -        StringArray arr = StringArray.asList(VM.class.getName().replace('.', '/'));
    5.23 -        return new Bck2Brwsr(ObfuscationLevel.NONE, arr, null);
    5.24 +        StringArray arr = StringArray.asList(
    5.25 +                              Class.class.getName().replace('.', '/'),
    5.26 +                              VM.class.getName().replace('.', '/'));
    5.27 +        return new Bck2Brwsr(ObfuscationLevel.NONE, arr, null, false);
    5.28      }
    5.29  
    5.30      /** Creates new instance of the Bck2Brwsr compiler which inherits
    5.31 @@ -114,7 +118,8 @@
    5.32          if (classes.length == 0) {
    5.33              return this;
    5.34          } else {
    5.35 -            return new Bck2Brwsr(level, this.classes.addAndNew(classes), res);
    5.36 +            return new Bck2Brwsr(level, this.classes.addAndNew(classes), res,
    5.37 +                                 extension);
    5.38          }
    5.39      }
    5.40      
    5.41 @@ -127,7 +132,7 @@
    5.42       * @since 0.5
    5.43       */
    5.44      public Bck2Brwsr obfuscation(ObfuscationLevel level) {
    5.45 -        return new Bck2Brwsr(level, classes, res);
    5.46 +        return new Bck2Brwsr(level, classes, res, extension);
    5.47      }
    5.48      
    5.49      /** A way to change the provider of additional resources (classes) for the 
    5.50 @@ -139,7 +144,11 @@
    5.51       * @since 0.5
    5.52       */
    5.53      public Bck2Brwsr resources(Resources res) {
    5.54 -        return new Bck2Brwsr(level, classes, res);
    5.55 +        return new Bck2Brwsr(level, classes, res, extension);
    5.56 +    }
    5.57 +
    5.58 +    public Bck2Brwsr extension(boolean extension) {
    5.59 +        return new Bck2Brwsr(level, classes, res, extension);
    5.60      }
    5.61  
    5.62      /** A way to change the provider of additional resources (classes) for the 
    5.63 @@ -162,19 +171,23 @@
    5.64       */
    5.65      public void generate(Appendable out) throws IOException {
    5.66          Resources r = res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader());
    5.67 -        if (level != ObfuscationLevel.NONE) {
    5.68 -            try {
    5.69 -                ClosureWrapper.produceTo(out, level, r, classes);
    5.70 -                return;
    5.71 -            } catch (IOException ex) {
    5.72 -                throw ex;
    5.73 -            } catch (Throwable ex) {
    5.74 -                out.append("/* Failed to obfuscate: " + ex.getMessage()
    5.75 -                               + " */\n");
    5.76 -            }
    5.77 +//        if (level != ObfuscationLevel.NONE) {
    5.78 +//            try {
    5.79 +//                ClosureWrapper.produceTo(out, level, r, classes);
    5.80 +//                return;
    5.81 +//            } catch (IOException ex) {
    5.82 +//                throw ex;
    5.83 +//            } catch (Throwable ex) {
    5.84 +//                out.append("/* Failed to obfuscate: " + ex.getMessage()
    5.85 +//                               + " */\n");
    5.86 +//            }
    5.87 +//        }
    5.88 +
    5.89 +        if (extension) {
    5.90 +            VM.compileExtension(r, out, classes);
    5.91 +        } else {
    5.92 +            VM.compileStandalone(r, out, classes);
    5.93          }
    5.94 -
    5.95 -        VM.compile(r, out, classes);
    5.96      }
    5.97      
    5.98      /** Provider of resources (classes and other files). The 
    5.99 @@ -193,7 +206,5 @@
   5.100           *   or the file cannot be found
   5.101           */
   5.102          public InputStream get(String resource) throws IOException;
   5.103 -
   5.104 -        public String getModule(String resource) throws IOException;
   5.105      }
   5.106  }
     6.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Thu Apr 25 16:17:48 2013 +0200
     6.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Fri Apr 26 18:48:34 2013 +0200
     6.3 @@ -28,12 +28,9 @@
     6.4  abstract class ByteCodeToJavaScript {
     6.5      private ClassData jc;
     6.6      final Appendable out;
     6.7 -    final ObfuscationDelegate obfuscationDelegate;
     6.8  
     6.9 -    protected ByteCodeToJavaScript(
    6.10 -            Appendable out, ObfuscationDelegate obfuscationDelegate) {
    6.11 +    protected ByteCodeToJavaScript(Appendable out) {
    6.12          this.out = out;
    6.13 -        this.obfuscationDelegate = obfuscationDelegate;
    6.14      }
    6.15      
    6.16      /* Collects additional required resources.
    6.17 @@ -62,7 +59,9 @@
    6.18          return classOperation;
    6.19      }
    6.20  
    6.21 -    abstract String getExportsObject();
    6.22 +    protected void declaredClass(ClassData classData, String mangledName)
    6.23 +            throws IOException {
    6.24 +    }
    6.25  
    6.26      /** Prints out a debug message. 
    6.27       * 
    6.28 @@ -145,7 +144,7 @@
    6.29                     .append("; };");
    6.30              }
    6.31  
    6.32 -            obfuscationDelegate.exportField(out, "c", "_" + v.getName(), v);
    6.33 +//            obfuscationDelegate.exportField(out, "c", "_" + v.getName(), v);
    6.34          }
    6.35          for (MethodData m : jc.getMethods()) {
    6.36              byte[] onlyArr = m.findAnnotationData(true);
    6.37 @@ -175,7 +174,7 @@
    6.38                      mn = generateInstanceMethod(destObject, m);
    6.39                  }
    6.40              }
    6.41 -            obfuscationDelegate.exportMethod(out, destObject, mn, m);
    6.42 +//            obfuscationDelegate.exportMethod(out, destObject, mn, m);
    6.43              byte[] runAnno = m.findAnnotationData(false);
    6.44              if (runAnno != null) {
    6.45                  out.append("\n    ").append(destObject).append(".").append(mn).append(".anno = {");
    6.46 @@ -188,11 +187,11 @@
    6.47          out.append("\n    c.constructor = CLS;");
    6.48          String instOfName = "$instOf_" + className;
    6.49          out.append("\n    c.").append(instOfName).append(" = true;");
    6.50 -        obfuscationDelegate.exportJSProperty(out, "c", instOfName);
    6.51 +//        obfuscationDelegate.exportJSProperty(out, "c", instOfName);
    6.52          for (String superInterface : jc.getSuperInterfaces()) {
    6.53              instOfName = "$instOf_" + superInterface.replace('/', '_');
    6.54              out.append("\n    c.").append(instOfName).append(" = true;");
    6.55 -            obfuscationDelegate.exportJSProperty(out, "c", instOfName);
    6.56 +//            obfuscationDelegate.exportJSProperty(out, "c", instOfName);
    6.57          }
    6.58          out.append("\n    CLS.$class = 'temp';");
    6.59          out.append("\n    CLS.$class = ");
    6.60 @@ -239,7 +238,7 @@
    6.61          out.append("\n  return arguments[0] ? new CLS() : CLS.prototype;");
    6.62          out.append("\n};");
    6.63  
    6.64 -        obfuscationDelegate.exportClass(out, getExportsObject(), className, jc);
    6.65 +        declaredClass(jc, className);
    6.66  
    6.67  //        StringBuilder sb = new StringBuilder();
    6.68  //        for (String init : toInitilize.toArray()) {
     7.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java	Thu Apr 25 16:17:48 2013 +0200
     7.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java	Fri Apr 26 18:48:34 2013 +0200
     7.3 @@ -104,7 +104,7 @@
     7.4          if (compiledCode == null) {
     7.5              StringBuilder sb = new StringBuilder();
     7.6              try {
     7.7 -                VM.compile(res, sb, classes, obfuscationDelegate);
     7.8 +                VM.compileStandalone(res, sb, classes);
     7.9                  compiledCode = sb.toString();
    7.10              } catch (IOException ex) {
    7.11                  compiledCode = ex.getMessage();
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ExportedSymbols.java	Fri Apr 26 18:48:34 2013 +0200
     8.3 @@ -0,0 +1,148 @@
     8.4 +/**
     8.5 + * Back 2 Browser Bytecode Translator
     8.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     8.7 + *
     8.8 + * This program is free software: you can redistribute it and/or modify
     8.9 + * it under the terms of the GNU General Public License as published by
    8.10 + * the Free Software Foundation, version 2 of the License.
    8.11 + *
    8.12 + * This program is distributed in the hope that it will be useful,
    8.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    8.15 + * GNU General Public License for more details.
    8.16 + *
    8.17 + * You should have received a copy of the GNU General Public License
    8.18 + * along with this program. Look for COPYING file in the top folder.
    8.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    8.20 + */
    8.21 +package org.apidesign.vm4brwsr;
    8.22 +
    8.23 +import java.io.IOException;
    8.24 +import java.io.InputStream;
    8.25 +import java.util.HashMap;
    8.26 +import java.util.Map;
    8.27 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
    8.28 +import org.apidesign.vm4brwsr.ByteCodeParser.AnnotationParser;
    8.29 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
    8.30 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
    8.31 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
    8.32 +
    8.33 +@ExtraJavaScript(processByteCode = false, resource="")
    8.34 +final class ExportedSymbols {
    8.35 +    private final Bck2Brwsr.Resources resources;
    8.36 +    private final Map<Object, Boolean> isMarkedAsExportedCache;
    8.37 +
    8.38 +    ExportedSymbols(final Bck2Brwsr.Resources resources) {
    8.39 +        this.resources = resources;
    8.40 +
    8.41 +        isMarkedAsExportedCache = new HashMap<Object, Boolean>();
    8.42 +    }
    8.43 +
    8.44 +    boolean isExported(ClassData classData) throws IOException {
    8.45 +        return classData.isPublic() && isMarkedAsExportedPackage(
    8.46 +                                           classData.getPkgName())
    8.47 +                   || isMarkedAsExported(classData);
    8.48 +    }
    8.49 +
    8.50 +    boolean isExported(MethodData methodData) throws IOException {
    8.51 +        return isAccessible(methodData.access) && isExported(methodData.cls)
    8.52 +                   || isMarkedAsExported(methodData);
    8.53 +    }
    8.54 +
    8.55 +    boolean isExported(FieldData fieldData) throws IOException {
    8.56 +        return isAccessible(fieldData.access) && isExported(fieldData.cls)
    8.57 +                   || isMarkedAsExported(fieldData);
    8.58 +    }
    8.59 +
    8.60 +    private boolean isMarkedAsExportedPackage(String pkgName) {
    8.61 +        if (pkgName == null) {
    8.62 +            return false;
    8.63 +        }
    8.64 +
    8.65 +        final Boolean cachedValue = isMarkedAsExportedCache.get(pkgName);
    8.66 +        if (cachedValue != null) {
    8.67 +            return cachedValue;
    8.68 +        }
    8.69 +
    8.70 +        final boolean newValue = resolveIsMarkedAsExportedPackage(pkgName);
    8.71 +        isMarkedAsExportedCache.put(pkgName, newValue);
    8.72 +
    8.73 +        return newValue;
    8.74 +    }
    8.75 +
    8.76 +    private boolean isMarkedAsExported(ClassData classData)
    8.77 +            throws IOException {
    8.78 +        final Boolean cachedValue = isMarkedAsExportedCache.get(classData);
    8.79 +        if (cachedValue != null) {
    8.80 +            return cachedValue;
    8.81 +        }
    8.82 +
    8.83 +        final boolean newValue =
    8.84 +                isMarkedAsExported(classData.findAnnotationData(true),
    8.85 +                                   classData);
    8.86 +        isMarkedAsExportedCache.put(classData, newValue);
    8.87 +
    8.88 +        return newValue;
    8.89 +    }
    8.90 +
    8.91 +    private boolean isMarkedAsExported(MethodData methodData)
    8.92 +            throws IOException {
    8.93 +        return isMarkedAsExported(methodData.findAnnotationData(true),
    8.94 +                                  methodData.cls);
    8.95 +    }
    8.96 +
    8.97 +    private boolean isMarkedAsExported(FieldData fieldData)
    8.98 +            throws IOException {
    8.99 +        return isMarkedAsExported(fieldData.findAnnotationData(true),
   8.100 +                                  fieldData.cls);
   8.101 +    }
   8.102 +
   8.103 +    private boolean resolveIsMarkedAsExportedPackage(String pkgName) {
   8.104 +        try {
   8.105 +            final InputStream is =
   8.106 +                    resources.get(pkgName + "/package-info.class");
   8.107 +            if (is == null) {
   8.108 +                return false;
   8.109 +            }
   8.110 +
   8.111 +            try {
   8.112 +                final ClassData pkgInfoClass = new ClassData(is);
   8.113 +                return isMarkedAsExported(
   8.114 +                               pkgInfoClass.findAnnotationData(true),
   8.115 +                               pkgInfoClass);
   8.116 +            } finally {
   8.117 +                is.close();
   8.118 +            }
   8.119 +        } catch (final IOException e) {
   8.120 +            return false;
   8.121 +        }
   8.122 +    }
   8.123 +
   8.124 +    private boolean isMarkedAsExported(byte[] arrData, ClassData cd)
   8.125 +            throws IOException {
   8.126 +        if (arrData == null) {
   8.127 +            return false;
   8.128 +        }
   8.129 +
   8.130 +        final boolean[] found = { false };
   8.131 +        final AnnotationParser annotationParser =
   8.132 +                new AnnotationParser(false, false) {
   8.133 +                    @Override
   8.134 +                    protected void visitAnnotationStart(
   8.135 +                            String type,
   8.136 +                            boolean top) {
   8.137 +                        if (top && type.equals("Lorg/apidesign/bck2brwsr"
   8.138 +                                                   + "/core/Exported;")) {
   8.139 +                            found[0] = true;
   8.140 +                        }
   8.141 +                    }
   8.142 +                };
   8.143 +        annotationParser.parse(arrData, cd);
   8.144 +        return found[0];
   8.145 +    }
   8.146 +
   8.147 +    private static boolean isAccessible(int access) {
   8.148 +        return (access & (ByteCodeParser.ACC_PUBLIC
   8.149 +                              | ByteCodeParser.ACC_PROTECTED)) != 0;
   8.150 +    }
   8.151 +}
     9.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java	Thu Apr 25 16:17:48 2013 +0200
     9.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java	Fri Apr 26 18:48:34 2013 +0200
     9.3 @@ -27,21 +27,44 @@
     9.4   * @author Jaroslav Tulach <jtulach@netbeans.org>
     9.5   */
     9.6  final class LdrRsrcs implements Bck2Brwsr.Resources {
     9.7 +    private final String module;
     9.8      private final ClassLoader loader;
     9.9  
    9.10      LdrRsrcs(ClassLoader loader) {
    9.11 +        this(null, loader);
    9.12 +    }
    9.13 +
    9.14 +    LdrRsrcs(String module, ClassLoader loader) {
    9.15 +        this.module = module;
    9.16          this.loader = loader;
    9.17      }
    9.18  
    9.19      @Override
    9.20      public InputStream get(String name) throws IOException {
    9.21 -        return findSource(name).openStream();
    9.22 +        final URL url = findSource(name);
    9.23 +        if (url == null) {
    9.24 +            return null;
    9.25 +        }
    9.26 +        if (module != null) {
    9.27 +            final String resourceModule = getModule(url);
    9.28 +            if ((resourceModule != null) && !module.equals(resourceModule)) {
    9.29 +                return null;
    9.30 +            }
    9.31 +        }
    9.32 +
    9.33 +        return url.openStream();
    9.34      }
    9.35  
    9.36 -    @Override
    9.37 -    public String getModule(String name) throws IOException {
    9.38 -        final URL url = findSource(name);
    9.39 +    private URL findSource(String name) throws IOException {
    9.40 +        Enumeration<URL> en = loader.getResources(name);
    9.41 +        URL u = null;
    9.42 +        while (en.hasMoreElements()) {
    9.43 +            u = en.nextElement();
    9.44 +        }
    9.45 +        return u;
    9.46 +    }
    9.47  
    9.48 +    private static String getModule(URL url) throws IOException {
    9.49          if (!"jar".equalsIgnoreCase(url.getProtocol())) {
    9.50              return null;
    9.51          }
    9.52 @@ -70,16 +93,4 @@
    9.53  
    9.54          return moduleName;
    9.55      }
    9.56 -
    9.57 -    private URL findSource(String name) throws IOException {
    9.58 -        Enumeration<URL> en = loader.getResources(name);
    9.59 -        URL u = null;
    9.60 -        while (en.hasMoreElements()) {
    9.61 -            u = en.nextElement();
    9.62 -        }
    9.63 -        if (u == null) {
    9.64 -            throw new IOException("Can't find " + name);
    9.65 -        }
    9.66 -        return u;
    9.67 -    }
    9.68  }
    10.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Thu Apr 25 16:17:48 2013 +0200
    10.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Fri Apr 26 18:48:34 2013 +0200
    10.3 @@ -39,10 +39,11 @@
    10.4      
    10.5      public static void main(String... args) throws IOException, URISyntaxException {
    10.6          final String obfuscate = "--obfuscatelevel";
    10.7 -        
    10.8 +        final String extension = "--createextension";
    10.9 +
   10.10          if (args.length < 2) {
   10.11              System.err.println("Bck2Brwsr Translator from Java(tm) to JavaScript, (c) Jaroslav Tulach 2012");
   10.12 -            System.err.println("Usage: java -cp ... -jar ... [");
   10.13 +            System.err.print("Usage: java -cp ... -jar ... [");
   10.14              System.err.print(obfuscate);
   10.15              System.err.print(" [");
   10.16              boolean first = true;
   10.17 @@ -53,7 +54,8 @@
   10.18                  System.err.print(l.name());
   10.19                  first = false;
   10.20              }
   10.21 -                
   10.22 +            System.err.print("]] [");
   10.23 +            System.err.print(extension);
   10.24              System.err.println("] <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
   10.25              System.exit(9);
   10.26          }
   10.27 @@ -61,6 +63,7 @@
   10.28          final ClassLoader mainClassLoader = Main.class.getClassLoader();
   10.29  
   10.30          ObfuscationLevel obfLevel = ObfuscationLevel.NONE;
   10.31 +        boolean createExtension = false;
   10.32          StringArray classes = new StringArray();
   10.33          String generateTo = null;
   10.34          for (int i = 0; i < args.length; i++) {
   10.35 @@ -84,17 +87,30 @@
   10.36                  }
   10.37                  continue;
   10.38              }
   10.39 +            if (extension.equals(args[i])) { // NOI18N
   10.40 +                createExtension = true;
   10.41 +                continue;
   10.42 +            }
   10.43              if (generateTo == null) {
   10.44                  generateTo = args[i];
   10.45              } else {
   10.46                  collectClasses(classes, mainClassLoader, args[i]);
   10.47              }
   10.48          }
   10.49 -        try (Writer w = new BufferedWriter(new FileWriter(generateTo))) {
   10.50 +        final File outputFile = new File(generateTo);
   10.51 +        String moduleName = null;
   10.52 +        if (createExtension) {
   10.53 +            moduleName = outputFile.getName();
   10.54 +            if (moduleName.endsWith(".js")) {
   10.55 +                moduleName = moduleName.substring(0, moduleName.length() - 3);
   10.56 +            }
   10.57 +        }
   10.58 +        try (Writer w = new BufferedWriter(new FileWriter(outputFile))) {
   10.59              Bck2Brwsr.newCompiler().
   10.60 +                extension(createExtension).
   10.61                  obfuscation(obfLevel).
   10.62                  addRootClasses(classes.toArray()).
   10.63 -                resources(mainClassLoader).
   10.64 +                resources(new LdrRsrcs(moduleName, mainClassLoader)).
   10.65                  generate(w);
   10.66          }
   10.67      }
    11.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Thu Apr 25 16:17:48 2013 +0200
    11.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Fri Apr 26 18:48:34 2013 +0200
    11.3 @@ -19,14 +19,20 @@
    11.4  
    11.5  import java.io.IOException;
    11.6  import java.io.InputStream;
    11.7 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
    11.8  
    11.9  /** Generator of JavaScript from bytecode of classes on classpath of the VM.
   11.10   *
   11.11   * @author Jaroslav Tulach <jtulach@netbeans.org>
   11.12   */
   11.13  abstract class VM extends ByteCodeToJavaScript {
   11.14 -    private VM(Appendable out, ObfuscationDelegate obfuscationDelegate) {
   11.15 -        super(out, obfuscationDelegate);
   11.16 +    protected final Bck2Brwsr.Resources resources;
   11.17 +    private final ExportedSymbols exportedSymbols;
   11.18 +
   11.19 +    private VM(Appendable out, Bck2Brwsr.Resources resources) {
   11.20 +        super(out);
   11.21 +        this.resources = resources;
   11.22 +        this.exportedSymbols = new ExportedSymbols(resources);
   11.23      }
   11.24  
   11.25      static {
   11.26 @@ -44,20 +50,19 @@
   11.27          return false;
   11.28      }
   11.29      
   11.30 -    static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException {
   11.31 -        VM vm = new Standalone(out, ObfuscationDelegate.NULL);
   11.32 -        vm.doCompile(l, names);
   11.33 +    static void compileStandalone(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException {
   11.34 +        VM vm = new Standalone(out, l);
   11.35 +        vm.doCompile(names);
   11.36      }
   11.37  
   11.38 -    static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names,
   11.39 -                        ObfuscationDelegate obfuscationDelegate) throws IOException {
   11.40 -        VM vm = new Standalone(out, obfuscationDelegate);
   11.41 -        vm.doCompile(l, names);
   11.42 +    static void compileExtension(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException {
   11.43 +        VM vm = new Extension(out, l);
   11.44 +        vm.doCompile(names);
   11.45      }
   11.46  
   11.47 -    private void doCompile(Bck2Brwsr.Resources l, StringArray names) throws IOException {
   11.48 +    private void doCompile(StringArray names) throws IOException {
   11.49          generatePrologue();
   11.50 -        generateBody(l, names);
   11.51 +        generateBody(names);
   11.52          generateEpilogue();
   11.53      }
   11.54  
   11.55 @@ -65,7 +70,24 @@
   11.56  
   11.57      protected abstract void generateEpilogue() throws IOException;
   11.58  
   11.59 -    protected void generateBody(Bck2Brwsr.Resources l, StringArray names) throws IOException {
   11.60 +    protected abstract String generateClass(String className)
   11.61 +            throws IOException;
   11.62 +
   11.63 +    protected abstract String getExportsObject();
   11.64 +
   11.65 +    @Override
   11.66 +    protected final void declaredClass(ClassData classData, String mangledName)
   11.67 +            throws IOException {
   11.68 +        if (exportedSymbols.isExported(classData)) {
   11.69 +            out.append("\n").append(getExportsObject()).append("['")
   11.70 +                                               .append(mangledName)
   11.71 +                                               .append("'] = ")
   11.72 +                            .append(accessClass(mangledName))
   11.73 +               .append(";\n");
   11.74 +        }
   11.75 +    }
   11.76 +
   11.77 +    private void generateBody(StringArray names) throws IOException {
   11.78          StringArray processed = new StringArray();
   11.79          StringArray initCode = new StringArray();
   11.80          for (String baseClass : names.toArray()) {
   11.81 @@ -81,12 +103,9 @@
   11.82                  if (name == null) {
   11.83                      break;
   11.84                  }
   11.85 -                InputStream is = loadClass(l, name);
   11.86 -                if (is == null) {
   11.87 -                    throw new IOException("Can't find class " + name);
   11.88 -                }
   11.89 +
   11.90                  try {
   11.91 -                    String ic = compile(is);
   11.92 +                    String ic = generateClass(name);
   11.93                      processed.add(name);
   11.94                      initCode.add(ic == null ? "" : ic);
   11.95                  } catch (RuntimeException ex) {
   11.96 @@ -113,7 +132,7 @@
   11.97                  while (resource.startsWith("/")) {
   11.98                      resource = resource.substring(1);
   11.99                  }
  11.100 -                InputStream emul = l.get(resource);
  11.101 +                InputStream emul = resources.get(resource);
  11.102                  if (emul == null) {
  11.103                      throw new IOException("Can't find " + resource);
  11.104                  }
  11.105 @@ -221,9 +240,8 @@
  11.106      }
  11.107  
  11.108      private static final class Standalone extends VM {
  11.109 -        private Standalone(Appendable out,
  11.110 -                           ObfuscationDelegate obfuscationDelegate) {
  11.111 -            super(out, obfuscationDelegate);
  11.112 +        private Standalone(Appendable out, Bck2Brwsr.Resources resources) {
  11.113 +            super(out, resources);
  11.114          }
  11.115  
  11.116          @Override
  11.117 @@ -236,9 +254,13 @@
  11.118              out.append(
  11.119                    "  return vm;\n"
  11.120                  + "  };\n"
  11.121 +                + "  var extensions = [];\n"
  11.122                  + "  global.bck2brwsr = function() {\n"
  11.123                  + "    var args = Array.prototype.slice.apply(arguments);\n"
  11.124                  + "    var vm = fillInVMSkeleton({});\n"
  11.125 +                + "    for (var i = 0; i < extensions.length; ++i) {\n"
  11.126 +                + "      extensions[i](vm);\n"
  11.127 +                + "    }\n"
  11.128                  + "    var loader = {};\n"
  11.129                  + "    loader.vm = vm;\n"
  11.130                  + "    loader.loadClass = function(name) {\n"
  11.131 @@ -261,29 +283,47 @@
  11.132                  + "      loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, null, args);\n"
  11.133                  + "    return loader;\n"
  11.134                  + "  };\n");
  11.135 +            out.append(
  11.136 +                  "  global.bck2brwsr.registerExtension"
  11.137 +                             + " = function(extension) {\n"
  11.138 +                + "    extensions.push(extension);\n"
  11.139 +                + "  };\n");
  11.140              out.append("}(this));");
  11.141          }
  11.142  
  11.143          @Override
  11.144 -        String getExportsObject() {
  11.145 +        protected String generateClass(String className) throws IOException {
  11.146 +            InputStream is = loadClass(resources, className);
  11.147 +            if (is == null) {
  11.148 +                throw new IOException("Can't find class " + className);
  11.149 +            }
  11.150 +            return compile(is);
  11.151 +        }
  11.152 +
  11.153 +        @Override
  11.154 +        protected String getExportsObject() {
  11.155              return "vm";
  11.156          }
  11.157      }
  11.158  
  11.159      private static final class Extension extends VM {
  11.160 -        private final String name;
  11.161 -
  11.162 -        private Extension(String name,
  11.163 -                          Appendable out,
  11.164 -                          ObfuscationDelegate obfuscationDelegate) {
  11.165 -            super(out, obfuscationDelegate);
  11.166 -            this.name = name;
  11.167 +        private Extension(Appendable out, Bck2Brwsr.Resources resources) {
  11.168 +            super(out, resources);
  11.169          }
  11.170  
  11.171          @Override
  11.172          protected void generatePrologue() throws IOException {
  11.173              out.append("bck2brwsr.registerExtension(function(exports) {\n"
  11.174                             + "  var vm = {};\n");
  11.175 +            out.append("  function link(n, inst) {\n"
  11.176 +                           + "    var cls = n.replace__Ljava_lang_String_2CC("
  11.177 +                                                  + "'/', '_').toString();\n"
  11.178 +                           + "    var dot = n.replace__Ljava_lang_String_2CC("
  11.179 +                                                  + "'/', '.').toString();\n"
  11.180 +                           + "    exports.loadClass(dot);\n"
  11.181 +                           + "    vm[cls] = exports[cls];\n"
  11.182 +                           + "    return vm[cls](inst);\n"
  11.183 +                           + "  };\n");
  11.184          }
  11.185  
  11.186          @Override
  11.187 @@ -292,7 +332,24 @@
  11.188          }
  11.189  
  11.190          @Override
  11.191 -        String getExportsObject() {
  11.192 +        protected String generateClass(String className) throws IOException {
  11.193 +            InputStream is = loadClass(resources, className);
  11.194 +            if (is == null) {
  11.195 +                out.append("\n").append(assignClass(
  11.196 +                                            className.replace('/', '_')))
  11.197 +                   .append("function() {\n  return link('")
  11.198 +                   .append(className)
  11.199 +                   .append("', arguments.length == 0 || arguments[0] === true);"
  11.200 +                               + "\n};");
  11.201 +
  11.202 +                return null;
  11.203 +            }
  11.204 +
  11.205 +            return compile(is);
  11.206 +        }
  11.207 +
  11.208 +        @Override
  11.209 +        protected String getExportsObject() {
  11.210              return "exports";
  11.211          }
  11.212      }
    12.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Thu Apr 25 16:17:48 2013 +0200
    12.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Fri Apr 26 18:48:34 2013 +0200
    12.3 @@ -106,7 +106,7 @@
    12.4          private final VMLazy lazy;
    12.5  
    12.6          public Gen(VMLazy vm, Appendable out) {
    12.7 -            super(out, ObfuscationDelegate.NULL);
    12.8 +            super(out);
    12.9              this.lazy = vm;
   12.10          }
   12.11          
   12.12 @@ -151,10 +151,5 @@
   12.13          String accessClass(String classOperation) {
   12.14              return "vm." + classOperation;
   12.15          }
   12.16 -
   12.17 -        @Override
   12.18 -        String getExportsObject() {
   12.19 -            return "vm";
   12.20 -        }
   12.21      }
   12.22  }
    13.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Thu Apr 25 16:17:48 2013 +0200
    13.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Fri Apr 26 18:48:34 2013 +0200
    13.3 @@ -166,10 +166,5 @@
    13.4              }
    13.5              return u.openStream();
    13.6          }
    13.7 -
    13.8 -        @Override
    13.9 -        public String getModule(String resource) throws IOException {
   13.10 -            return null;
   13.11 -        }
   13.12      }
   13.13  }
    14.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java	Thu Apr 25 16:17:48 2013 +0200
    14.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java	Fri Apr 26 18:48:34 2013 +0200
    14.3 @@ -43,9 +43,4 @@
    14.4      @Override
    14.5      protected void requireScript(String resourcePath) {
    14.6      }
    14.7 -
    14.8 -    @Override
    14.9 -    String getExportsObject() {
   14.10 -        return "global";
   14.11 -    }
   14.12  }