Initial structure for extension modules closure
authorLubomir Nerad <lubomir.nerad@oracle.com>
Thu, 25 Apr 2013 16:17:48 +0200
branchclosure
changeset 1020a6bacea2518f
parent 988 c2386b2f53d0
child 1029 b1fe994d4267
Initial structure for 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/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	Mon Apr 15 15:30:53 2013 +0200
     1.2 +++ b/dew/src/main/java/org/apidesign/bck2brwsr/dew/Dew.java	Thu Apr 25 16:17:48 2013 +0200
     1.3 @@ -135,4 +135,9 @@
     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	Mon Apr 15 15:30:53 2013 +0200
     2.2 +++ b/dew/src/main/java/org/apidesign/bck2brwsr/dew/DewLauncher.java	Thu Apr 25 16:17:48 2013 +0200
     2.3 @@ -122,6 +122,11 @@
     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	Mon Apr 15 15:30:53 2013 +0200
     3.2 +++ b/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Thu Apr 25 16:17:48 2013 +0200
     3.3 @@ -460,6 +460,11 @@
     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	Mon Apr 15 15:30:53 2013 +0200
     4.2 +++ b/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java	Thu Apr 25 16:17:48 2013 +0200
     4.3 @@ -128,5 +128,10 @@
     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	Mon Apr 15 15:30:53 2013 +0200
     5.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Thu Apr 25 16:17:48 2013 +0200
     5.3 @@ -193,5 +193,7 @@
     5.4           *   or the file cannot be found
     5.5           */
     5.6          public InputStream get(String resource) throws IOException;
     5.7 +
     5.8 +        public String getModule(String resource) throws IOException;
     5.9      }
    5.10  }
     6.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Mon Apr 15 15:30:53 2013 +0200
     6.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Thu Apr 25 16:17:48 2013 +0200
     6.3 @@ -30,10 +30,6 @@
     6.4      final Appendable out;
     6.5      final ObfuscationDelegate obfuscationDelegate;
     6.6  
     6.7 -    protected ByteCodeToJavaScript(Appendable out) {
     6.8 -        this(out, ObfuscationDelegate.NULL);
     6.9 -    }
    6.10 -
    6.11      protected ByteCodeToJavaScript(
    6.12              Appendable out, ObfuscationDelegate obfuscationDelegate) {
    6.13          this.out = out;
    6.14 @@ -66,7 +62,7 @@
    6.15          return classOperation;
    6.16      }
    6.17  
    6.18 -    abstract String getVMObject();
    6.19 +    abstract String getExportsObject();
    6.20  
    6.21      /** Prints out a debug message. 
    6.22       * 
    6.23 @@ -243,7 +239,7 @@
    6.24          out.append("\n  return arguments[0] ? new CLS() : CLS.prototype;");
    6.25          out.append("\n};");
    6.26  
    6.27 -        obfuscationDelegate.exportClass(out, getVMObject(), className, jc);
    6.28 +        obfuscationDelegate.exportClass(out, getExportsObject(), className, jc);
    6.29  
    6.30  //        StringBuilder sb = new StringBuilder();
    6.31  //        for (String init : toInitilize.toArray()) {
     7.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java	Mon Apr 15 15:30:53 2013 +0200
     7.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java	Thu Apr 25 16:17:48 2013 +0200
     7.3 @@ -35,6 +35,43 @@
     7.4  
     7.5      @Override
     7.6      public InputStream get(String name) throws IOException {
     7.7 +        return findSource(name).openStream();
     7.8 +    }
     7.9 +
    7.10 +    @Override
    7.11 +    public String getModule(String name) throws IOException {
    7.12 +        final URL url = findSource(name);
    7.13 +
    7.14 +        if (!"jar".equalsIgnoreCase(url.getProtocol())) {
    7.15 +            return null;
    7.16 +        }
    7.17 +
    7.18 +        final String fullPathString = url.getPath();
    7.19 +        final int sepIndex = fullPathString.indexOf('!');
    7.20 +        final String jarPathString =
    7.21 +                (sepIndex != -1) ? fullPathString.substring(0, sepIndex)
    7.22 +                                 : fullPathString;
    7.23 +        if (!jarPathString.endsWith(".jar")) {
    7.24 +            return null;
    7.25 +        }
    7.26 +
    7.27 +        String moduleName =
    7.28 +                jarPathString.substring(
    7.29 +                                  jarPathString.lastIndexOf('/') + 1,
    7.30 +                                  jarPathString.length() - 4);
    7.31 +        if (moduleName.endsWith("-SNAPSHOT")) {
    7.32 +            moduleName = moduleName.substring(
    7.33 +                                        0, moduleName.length() - 9);
    7.34 +        }
    7.35 +        final int dashIndex = moduleName.lastIndexOf('-');
    7.36 +        if (dashIndex != -1) {
    7.37 +            moduleName = moduleName.substring(0, dashIndex);
    7.38 +        }
    7.39 +
    7.40 +        return moduleName;
    7.41 +    }
    7.42 +
    7.43 +    private URL findSource(String name) throws IOException {
    7.44          Enumeration<URL> en = loader.getResources(name);
    7.45          URL u = null;
    7.46          while (en.hasMoreElements()) {
    7.47 @@ -43,6 +80,6 @@
    7.48          if (u == null) {
    7.49              throw new IOException("Can't find " + name);
    7.50          }
    7.51 -        return u.openStream();
    7.52 +        return u;
    7.53      }
    7.54  }
     8.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Mon Apr 15 15:30:53 2013 +0200
     8.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Thu Apr 25 16:17:48 2013 +0200
     8.3 @@ -18,9 +18,16 @@
     8.4  package org.apidesign.vm4brwsr;
     8.5  
     8.6  import java.io.BufferedWriter;
     8.7 +import java.io.File;
     8.8  import java.io.FileWriter;
     8.9  import java.io.IOException;
    8.10  import java.io.Writer;
    8.11 +import java.net.URI;
    8.12 +import java.net.URISyntaxException;
    8.13 +import java.net.URL;
    8.14 +import java.util.Enumeration;
    8.15 +import java.util.jar.JarEntry;
    8.16 +import java.util.jar.JarFile;
    8.17  
    8.18  /** Generator of JavaScript from bytecode of classes on classpath of the VM
    8.19   * with a Main method.
    8.20 @@ -30,7 +37,7 @@
    8.21  final class Main {
    8.22      private Main() {}
    8.23      
    8.24 -    public static void main(String... args) throws IOException {
    8.25 +    public static void main(String... args) throws IOException, URISyntaxException {
    8.26          final String obfuscate = "--obfuscatelevel";
    8.27          
    8.28          if (args.length < 2) {
    8.29 @@ -50,7 +57,9 @@
    8.30              System.err.println("] <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
    8.31              System.exit(9);
    8.32          }
    8.33 -        
    8.34 +
    8.35 +        final ClassLoader mainClassLoader = Main.class.getClassLoader();
    8.36 +
    8.37          ObfuscationLevel obfLevel = ObfuscationLevel.NONE;
    8.38          StringArray classes = new StringArray();
    8.39          String generateTo = null;
    8.40 @@ -78,15 +87,114 @@
    8.41              if (generateTo == null) {
    8.42                  generateTo = args[i];
    8.43              } else {
    8.44 -                classes = classes.addAndNew(args[i]);
    8.45 +                collectClasses(classes, mainClassLoader, args[i]);
    8.46              }
    8.47          }
    8.48          try (Writer w = new BufferedWriter(new FileWriter(generateTo))) {
    8.49              Bck2Brwsr.newCompiler().
    8.50                  obfuscation(obfLevel).
    8.51                  addRootClasses(classes.toArray()).
    8.52 -                resources(Main.class.getClassLoader()).
    8.53 +                resources(mainClassLoader).
    8.54                  generate(w);
    8.55          }
    8.56      }
    8.57 +
    8.58 +    private static void collectClasses(
    8.59 +            final StringArray dest,
    8.60 +            final ClassLoader cl, final String relativePath)
    8.61 +                throws IOException, URISyntaxException {
    8.62 +        final Enumeration<URL> urls = cl.getResources(relativePath);
    8.63 +        if (!urls.hasMoreElements()) {
    8.64 +            dest.add(relativePath);
    8.65 +            return;
    8.66 +        }
    8.67 +        do {
    8.68 +            final URL url = urls.nextElement();
    8.69 +            switch (url.getProtocol()) {
    8.70 +                case "file":
    8.71 +                    collectClasses(dest, relativePath,
    8.72 +                                   new File(new URI(url.toString())));
    8.73 +                    continue;
    8.74 +                case "jar":
    8.75 +                    final String fullPath = url.getPath();
    8.76 +                    final int sepIndex = fullPath.indexOf('!');
    8.77 +                    final String jarFilePath =
    8.78 +                            (sepIndex != -1) ? fullPath.substring(0, sepIndex)
    8.79 +                                             : fullPath;
    8.80 +
    8.81 +                    final URI jarUri = new URI(jarFilePath);
    8.82 +                    if (jarUri.getScheme().equals("file")) {
    8.83 +                        try (JarFile jarFile = new JarFile(new File(jarUri))) {
    8.84 +                            collectClasses(dest, relativePath, jarFile);
    8.85 +                            continue;
    8.86 +                        }
    8.87 +                    }
    8.88 +                    break;
    8.89 +            }
    8.90 +
    8.91 +            dest.add(relativePath);
    8.92 +        } while (urls.hasMoreElements());
    8.93 +    }
    8.94 +
    8.95 +    private static void collectClasses(final StringArray dest,
    8.96 +                                       final String relativePath,
    8.97 +                                       final File file) {
    8.98 +        if (file.isDirectory()) {
    8.99 +            final File[] subFiles = file.listFiles();
   8.100 +            for (final File subFile: subFiles) {
   8.101 +                collectClasses(dest,
   8.102 +                               extendPath(relativePath, subFile.getName()),
   8.103 +                               subFile);
   8.104 +            }
   8.105 +
   8.106 +            return;
   8.107 +        }
   8.108 +
   8.109 +        final String filePath = file.getPath();
   8.110 +        if (filePath.endsWith(".class")) {
   8.111 +            validateAndAddClass(dest, relativePath);
   8.112 +        }
   8.113 +    }
   8.114 +
   8.115 +    private static void collectClasses(final StringArray dest,
   8.116 +                                       final String relativePath,
   8.117 +                                       final JarFile jarFile) {
   8.118 +        if (relativePath.endsWith(".class")) {
   8.119 +            if (jarFile.getJarEntry(relativePath) != null) {
   8.120 +                validateAndAddClass(dest, relativePath);
   8.121 +            }
   8.122 +
   8.123 +            return;
   8.124 +        }
   8.125 +
   8.126 +        final String expectedPrefix =
   8.127 +                relativePath.endsWith("/") ? relativePath
   8.128 +                                           : relativePath + '/';
   8.129 +        final Enumeration<JarEntry> entries = jarFile.entries();
   8.130 +        while (entries.hasMoreElements()) {
   8.131 +            final JarEntry entry = entries.nextElement();
   8.132 +            if (!entry.isDirectory()) {
   8.133 +                final String entryName = entry.getName();
   8.134 +                if (entryName.startsWith(expectedPrefix)
   8.135 +                        && entryName.endsWith(".class")) {
   8.136 +                    validateAndAddClass(dest, entryName);
   8.137 +                }
   8.138 +            }
   8.139 +        }
   8.140 +    }
   8.141 +
   8.142 +    private static String extendPath(final String relativePath,
   8.143 +                                     final String fileName) {
   8.144 +        return relativePath.endsWith("/") ? relativePath + fileName
   8.145 +                                          : relativePath + '/' + fileName;
   8.146 +    }
   8.147 +
   8.148 +    private static void validateAndAddClass(final StringArray dest,
   8.149 +                                            final String relativePath) {
   8.150 +        final String className =
   8.151 +                relativePath.substring(0, relativePath.length() - 6);
   8.152 +        if (!className.endsWith("package-info")) {
   8.153 +            dest.add(className);
   8.154 +        }
   8.155 +    }
   8.156  }
     9.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Mon Apr 15 15:30:53 2013 +0200
     9.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Thu Apr 25 16:17:48 2013 +0200
     9.3 @@ -24,11 +24,7 @@
     9.4   *
     9.5   * @author Jaroslav Tulach <jtulach@netbeans.org>
     9.6   */
     9.7 -class VM extends ByteCodeToJavaScript {
     9.8 -    public VM(Appendable out) {
     9.9 -        super(out);
    9.10 -    }
    9.11 -
    9.12 +abstract class VM extends ByteCodeToJavaScript {
    9.13      private VM(Appendable out, ObfuscationDelegate obfuscationDelegate) {
    9.14          super(out, obfuscationDelegate);
    9.15      }
    9.16 @@ -49,16 +45,27 @@
    9.17      }
    9.18      
    9.19      static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException {
    9.20 -        new VM(out).doCompile(l, names);
    9.21 +        VM vm = new Standalone(out, ObfuscationDelegate.NULL);
    9.22 +        vm.doCompile(l, names);
    9.23      }
    9.24  
    9.25      static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names,
    9.26                          ObfuscationDelegate obfuscationDelegate) throws IOException {
    9.27 -        new VM(out, obfuscationDelegate).doCompile(l, names);
    9.28 +        VM vm = new Standalone(out, obfuscationDelegate);
    9.29 +        vm.doCompile(l, names);
    9.30      }
    9.31  
    9.32 -    protected void doCompile(Bck2Brwsr.Resources l, StringArray names) throws IOException {
    9.33 -        out.append("(function VM(global) {var fillInVMSkeleton = function(vm) {");
    9.34 +    private void doCompile(Bck2Brwsr.Resources l, StringArray names) throws IOException {
    9.35 +        generatePrologue();
    9.36 +        generateBody(l, names);
    9.37 +        generateEpilogue();
    9.38 +    }
    9.39 +
    9.40 +    protected abstract void generatePrologue() throws IOException;
    9.41 +
    9.42 +    protected abstract void generateEpilogue() throws IOException;
    9.43 +
    9.44 +    protected void generateBody(Bck2Brwsr.Resources l, StringArray names) throws IOException {
    9.45          StringArray processed = new StringArray();
    9.46          StringArray initCode = new StringArray();
    9.47          for (String baseClass : names.toArray()) {
    9.48 @@ -76,7 +83,7 @@
    9.49                  }
    9.50                  InputStream is = loadClass(l, name);
    9.51                  if (is == null) {
    9.52 -                    throw new IOException("Can't find class " + name); 
    9.53 +                    throw new IOException("Can't find class " + name);
    9.54                  }
    9.55                  try {
    9.56                      String ic = compile(is);
    9.57 @@ -91,11 +98,11 @@
    9.58                                  break;
    9.59                              }
    9.60                          }
    9.61 -                        throw new IOException("Error while compiling " + name + "\n" 
    9.62 +                        throw new IOException("Error while compiling " + name + "\n"
    9.63                              + seq.subSequence(lastBlock + 1, seq.length()), ex
    9.64                          );
    9.65                      } else {
    9.66 -                        throw new IOException("Error while compiling " + name + "\n" 
    9.67 +                        throw new IOException("Error while compiling " + name + "\n"
    9.68                              + out, ex
    9.69                          );
    9.70                      }
    9.71 @@ -113,7 +120,7 @@
    9.72                  readResource(emul, out);
    9.73              }
    9.74              scripts = new StringArray();
    9.75 -            
    9.76 +
    9.77              StringArray toInit = StringArray.asList(references.toArray());
    9.78              toInit.reverse();
    9.79  
    9.80 @@ -128,36 +135,8 @@
    9.81                  }
    9.82              }
    9.83          }
    9.84 -        out.append(
    9.85 -              "  return vm;\n"
    9.86 -            + "  };\n"
    9.87 -            + "  global.bck2brwsr = function() {\n"
    9.88 -            + "    var args = Array.prototype.slice.apply(arguments);\n"
    9.89 -            + "    var vm = fillInVMSkeleton({});\n"
    9.90 -            + "    var loader = {};\n"
    9.91 -            + "    loader.vm = vm;\n"
    9.92 -            + "    loader.loadClass = function(name) {\n"
    9.93 -            + "      var attr = name.replace__Ljava_lang_String_2CC('.','_');\n"
    9.94 -            + "      var fn = vm[attr];\n"
    9.95 -            + "      if (fn) return fn(false);\n"
    9.96 -            + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
    9.97 -            + "        load__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
    9.98 -            + "    }\n"
    9.99 -            + "    if (vm.loadClass) {\n"
   9.100 -            + "      throw 'Cannot initialize the bck2brwsr VM twice!';\n"
   9.101 -            + "    }\n"
   9.102 -            + "    vm.loadClass = loader.loadClass;\n"
   9.103 -            + "    vm.loadBytes = function(name) {\n"
   9.104 -            + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
   9.105 -            + "        loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
   9.106 -            + "    }\n"
   9.107 -            + "    vm.java_lang_reflect_Array(false);\n"
   9.108 -            + "    vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
   9.109 -            + "      loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, null, args);\n"
   9.110 -            + "    return loader;\n"
   9.111 -            + "  };\n");
   9.112 -        out.append("}(this));");
   9.113      }
   9.114 +
   9.115      private static void readResource(InputStream emul, Appendable out) throws IOException {
   9.116          try {
   9.117              int state = 0;
   9.118 @@ -241,8 +220,80 @@
   9.119          return "vm." + className;
   9.120      }
   9.121  
   9.122 -    @Override
   9.123 -    String getVMObject() {
   9.124 -        return "vm";
   9.125 +    private static final class Standalone extends VM {
   9.126 +        private Standalone(Appendable out,
   9.127 +                           ObfuscationDelegate obfuscationDelegate) {
   9.128 +            super(out, obfuscationDelegate);
   9.129 +        }
   9.130 +
   9.131 +        @Override
   9.132 +        protected void generatePrologue() throws IOException {
   9.133 +            out.append("(function VM(global) {var fillInVMSkeleton = function(vm) {");
   9.134 +        }
   9.135 +
   9.136 +        @Override
   9.137 +        protected void generateEpilogue() throws IOException {
   9.138 +            out.append(
   9.139 +                  "  return vm;\n"
   9.140 +                + "  };\n"
   9.141 +                + "  global.bck2brwsr = function() {\n"
   9.142 +                + "    var args = Array.prototype.slice.apply(arguments);\n"
   9.143 +                + "    var vm = fillInVMSkeleton({});\n"
   9.144 +                + "    var loader = {};\n"
   9.145 +                + "    loader.vm = vm;\n"
   9.146 +                + "    loader.loadClass = function(name) {\n"
   9.147 +                + "      var attr = name.replace__Ljava_lang_String_2CC('.','_');\n"
   9.148 +                + "      var fn = vm[attr];\n"
   9.149 +                + "      if (fn) return fn(false);\n"
   9.150 +                + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
   9.151 +                + "        load__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
   9.152 +                + "    }\n"
   9.153 +                + "    if (vm.loadClass) {\n"
   9.154 +                + "      throw 'Cannot initialize the bck2brwsr VM twice!';\n"
   9.155 +                + "    }\n"
   9.156 +                + "    vm.loadClass = loader.loadClass;\n"
   9.157 +                + "    vm.loadBytes = function(name) {\n"
   9.158 +                + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
   9.159 +                + "        loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
   9.160 +                + "    }\n"
   9.161 +                + "    vm.java_lang_reflect_Array(false);\n"
   9.162 +                + "    vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
   9.163 +                + "      loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, null, args);\n"
   9.164 +                + "    return loader;\n"
   9.165 +                + "  };\n");
   9.166 +            out.append("}(this));");
   9.167 +        }
   9.168 +
   9.169 +        @Override
   9.170 +        String getExportsObject() {
   9.171 +            return "vm";
   9.172 +        }
   9.173 +    }
   9.174 +
   9.175 +    private static final class Extension extends VM {
   9.176 +        private final String name;
   9.177 +
   9.178 +        private Extension(String name,
   9.179 +                          Appendable out,
   9.180 +                          ObfuscationDelegate obfuscationDelegate) {
   9.181 +            super(out, obfuscationDelegate);
   9.182 +            this.name = name;
   9.183 +        }
   9.184 +
   9.185 +        @Override
   9.186 +        protected void generatePrologue() throws IOException {
   9.187 +            out.append("bck2brwsr.registerExtension(function(exports) {\n"
   9.188 +                           + "  var vm = {};\n");
   9.189 +        }
   9.190 +
   9.191 +        @Override
   9.192 +        protected void generateEpilogue() throws IOException {
   9.193 +            out.append("});");
   9.194 +        }
   9.195 +
   9.196 +        @Override
   9.197 +        String getExportsObject() {
   9.198 +            return "exports";
   9.199 +        }
   9.200      }
   9.201  }
    10.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Mon Apr 15 15:30:53 2013 +0200
    10.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Thu Apr 25 16:17:48 2013 +0200
    10.3 @@ -106,7 +106,7 @@
    10.4          private final VMLazy lazy;
    10.5  
    10.6          public Gen(VMLazy vm, Appendable out) {
    10.7 -            super(out);
    10.8 +            super(out, ObfuscationDelegate.NULL);
    10.9              this.lazy = vm;
   10.10          }
   10.11          
   10.12 @@ -153,7 +153,7 @@
   10.13          }
   10.14  
   10.15          @Override
   10.16 -        String getVMObject() {
   10.17 +        String getExportsObject() {
   10.18              return "vm";
   10.19          }
   10.20      }
    11.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Mon Apr 15 15:30:53 2013 +0200
    11.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Thu Apr 25 16:17:48 2013 +0200
    11.3 @@ -166,5 +166,10 @@
    11.4              }
    11.5              return u.openStream();
    11.6          }
    11.7 +
    11.8 +        @Override
    11.9 +        public String getModule(String resource) throws IOException {
   11.10 +            return null;
   11.11 +        }
   11.12      }
   11.13  }
    12.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java	Mon Apr 15 15:30:53 2013 +0200
    12.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java	Thu Apr 25 16:17:48 2013 +0200
    12.3 @@ -45,7 +45,7 @@
    12.4      }
    12.5  
    12.6      @Override
    12.7 -    String getVMObject() {
    12.8 +    String getExportsObject() {
    12.9          return "global";
   12.10      }
   12.11  }