Merging the closure branch as it seems to be in a state when it is ready to work and not break anything
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 06 May 2014 17:46:47 +0200
changeset 1539ae8575329e1b
parent 1512 5171ac3b4232
parent 1538 dfddf572c7ec
child 1557 bfda398c3a68
Merging the closure branch as it seems to be in a state when it is ready to work and not break anything
rt/vm/src/main/java/org/apidesign/vm4brwsr/ObfuscationDelegate.java
     1.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java	Wed Apr 30 09:26:28 2014 +0200
     1.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java	Tue May 06 17:46:47 2014 +0200
     1.3 @@ -60,6 +60,7 @@
     1.4  import javax.tools.Diagnostic;
     1.5  import javax.tools.FileObject;
     1.6  import javax.tools.StandardLocation;
     1.7 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
     1.8  import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
     1.9  import org.apidesign.bck2brwsr.htmlpage.api.Model;
    1.10  import org.apidesign.bck2brwsr.htmlpage.api.On;
    1.11 @@ -75,6 +76,7 @@
    1.12   *
    1.13   * @author Jaroslav Tulach <jtulach@netbeans.org>
    1.14   */
    1.15 +@ExtraJavaScript(processByteCode = false, resource = "")
    1.16  @ServiceProvider(service=Processor.class)
    1.17  @SupportedAnnotationTypes({
    1.18      "org.apidesign.bck2brwsr.htmlpage.api.Model",
    1.19 @@ -193,6 +195,7 @@
    1.20                  w.append("package " + pkg + ";\n");
    1.21                  w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
    1.22                  w.append("import org.apidesign.bck2brwsr.htmlpage.KOList;\n");
    1.23 +                w.append("import org.apidesign.bck2brwsr.core.Exported;\n");
    1.24                  w.append("import org.apidesign.bck2brwsr.core.JavaScriptOnly;\n");
    1.25                  w.append("final class ").append(className).append(" implements Cloneable {\n");
    1.26                  w.append("  private boolean locked;\n");
    1.27 @@ -344,6 +347,7 @@
    1.28                  w.append("package " + pkg + ";\n");
    1.29                  w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
    1.30                  w.append("import org.apidesign.bck2brwsr.htmlpage.KOList;\n");
    1.31 +                w.append("import org.apidesign.bck2brwsr.core.Exported;\n");
    1.32                  w.append("final class ").append(className).append(" {\n");
    1.33                  w.append("  private boolean locked;\n");
    1.34                  if (!initializeOnClick(className, (TypeElement) e, w, pp)) {
    1.35 @@ -555,6 +559,7 @@
    1.36                  }
    1.37                  w.write(";\n");
    1.38                  
    1.39 +                w.write("@Exported\n");
    1.40                  w.write("public java.util.List<" + tn + "> " + gs[0] + "() {\n");
    1.41                  w.write("  if (locked) throw new IllegalStateException();\n");
    1.42                  w.write("  prop_" + p.name() + ".assign(ko);\n");
    1.43 @@ -562,10 +567,12 @@
    1.44                  w.write("}\n");
    1.45              } else {
    1.46                  w.write("private " + tn + " prop_" + p.name() + ";\n");
    1.47 +                w.write("@Exported\n");
    1.48                  w.write("public " + tn + " " + gs[0] + "() {\n");
    1.49                  w.write("  if (locked) throw new IllegalStateException();\n");
    1.50                  w.write("  return prop_" + p.name() + ";\n");
    1.51                  w.write("}\n");
    1.52 +                w.write("@Exported\n");
    1.53                  w.write("public void " + gs[1] + "(" + tn + " v) {\n");
    1.54                  w.write("  if (locked) throw new IllegalStateException();\n");
    1.55                  w.write("  prop_" + p.name() + " = v;\n");
    1.56 @@ -621,6 +628,7 @@
    1.57              final String sn = ee.getSimpleName().toString();
    1.58              String[] gs = toGetSet(sn, tn, array);
    1.59              
    1.60 +            w.write("@Exported\n");
    1.61              w.write("public " + tn + " " + gs[0] + "() {\n");
    1.62              w.write("  if (locked) throw new IllegalStateException();\n");
    1.63              int arg = 0;
    1.64 @@ -796,6 +804,7 @@
    1.65                  return false;
    1.66              }
    1.67              String n = e.getSimpleName().toString();
    1.68 +            body.append("@Exported\n");
    1.69              body.append("private void ").append(n).append("(Object data, Object ev) {\n");
    1.70              body.append("  ").append(clazz.getSimpleName()).append(".").append(n).append("(");
    1.71              body.append(wrapParams(e, null, className, "ev", "data"));
     2.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ProcessPage.java	Wed Apr 30 09:26:28 2014 +0200
     2.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ProcessPage.java	Tue May 06 17:46:47 2014 +0200
     2.3 @@ -25,11 +25,13 @@
     2.4  import java.util.TreeMap;
     2.5  import javax.xml.parsers.DocumentBuilder;
     2.6  import javax.xml.parsers.DocumentBuilderFactory;
     2.7 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
     2.8  import org.w3c.dom.Document;
     2.9  import org.w3c.dom.Element;
    2.10  import org.w3c.dom.Node;
    2.11  import org.w3c.dom.NodeList;
    2.12  
    2.13 +@ExtraJavaScript(processByteCode = false, resource = "")
    2.14  class ProcessPage {
    2.15      private final Map<String,String> ids2Elems = new TreeMap<String, String>();
    2.16      
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/package-info.java	Tue May 06 17:46:47 2014 +0200
     3.3 @@ -0,0 +1,21 @@
     3.4 +/**
     3.5 + * Back 2 Browser Bytecode Translator
     3.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     3.7 + *
     3.8 + * This program is free software: you can redistribute it and/or modify
     3.9 + * it under the terms of the GNU General Public License as published by
    3.10 + * the Free Software Foundation, version 2 of the License.
    3.11 + *
    3.12 + * This program is distributed in the hope that it will be useful,
    3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.15 + * GNU General Public License for more details.
    3.16 + *
    3.17 + * You should have received a copy of the GNU General Public License
    3.18 + * along with this program. Look for COPYING file in the top folder.
    3.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    3.20 + */
    3.21 +@Exported
    3.22 +package org.apidesign.bck2brwsr.htmlpage.api;
    3.23 +
    3.24 +import org.apidesign.bck2brwsr.core.Exported;
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/package-info.java	Tue May 06 17:46:47 2014 +0200
     4.3 @@ -0,0 +1,21 @@
     4.4 +/**
     4.5 + * Back 2 Browser Bytecode Translator
     4.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4.7 + *
     4.8 + * This program is free software: you can redistribute it and/or modify
     4.9 + * it under the terms of the GNU General Public License as published by
    4.10 + * the Free Software Foundation, version 2 of the License.
    4.11 + *
    4.12 + * This program is distributed in the hope that it will be useful,
    4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.15 + * GNU General Public License for more details.
    4.16 + *
    4.17 + * You should have received a copy of the GNU General Public License
    4.18 + * along with this program. Look for COPYING file in the top folder.
    4.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    4.20 + */
    4.21 +@Exported
    4.22 +package org.apidesign.bck2brwsr.htmlpage;
    4.23 +
    4.24 +import org.apidesign.bck2brwsr.core.Exported;
     5.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Compile.java	Wed Apr 30 09:26:28 2014 +0200
     5.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Compile.java	Tue May 06 17:46:47 2014 +0200
     5.3 @@ -42,11 +42,13 @@
     5.4  import javax.tools.StandardJavaFileManager;
     5.5  import javax.tools.StandardLocation;
     5.6  import javax.tools.ToolProvider;
     5.7 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
     5.8  
     5.9  /**
    5.10   *
    5.11   * @author Jaroslav Tulach <jtulach@netbeans.org>
    5.12   */
    5.13 +@ExtraJavaScript(processByteCode = false, resource = "")
    5.14  final class Compile implements DiagnosticListener<JavaFileObject> {
    5.15      private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
    5.16      private final Map<String, byte[]> classes;
    5.17 @@ -89,23 +91,8 @@
    5.18  
    5.19          final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
    5.20  
    5.21 -        JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
    5.22 -            @Override
    5.23 -            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
    5.24 -                return code;
    5.25 -            }
    5.26 -        };
    5.27 -        final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
    5.28 -            @Override
    5.29 -            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
    5.30 -                return html;
    5.31 -            }
    5.32 -
    5.33 -            @Override
    5.34 -            public InputStream openInputStream() throws IOException {
    5.35 -                return new ByteArrayInputStream(html.getBytes());
    5.36 -            }
    5.37 -        };
    5.38 +        JavaFileObject file = new Mem(URI.create("mem://mem"), Kind.SOURCE, code);
    5.39 +        final JavaFileObject htmlFile = new Mem2(URI.create("mem://mem2"), Kind.OTHER, html);
    5.40          
    5.41          final URI scratch;
    5.42          try {
    5.43 @@ -114,52 +101,7 @@
    5.44              throw new IOException(ex);
    5.45          }
    5.46          
    5.47 -        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
    5.48 -            @Override
    5.49 -            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
    5.50 -                if (kind  == Kind.CLASS) {
    5.51 -                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    5.52 -
    5.53 -                    class2BAOS.put(className.replace('.', '/') + ".class", buffer);
    5.54 -                    return new SimpleJavaFileObject(sibling.toUri(), kind) {
    5.55 -                        @Override
    5.56 -                        public OutputStream openOutputStream() throws IOException {
    5.57 -                            return buffer;
    5.58 -                        }
    5.59 -                    };
    5.60 -                }
    5.61 -                
    5.62 -                if (kind == Kind.SOURCE) {
    5.63 -                    return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) {
    5.64 -                        private final ByteArrayOutputStream data = new ByteArrayOutputStream();
    5.65 -                        @Override
    5.66 -                        public OutputStream openOutputStream() throws IOException {
    5.67 -                            return data;
    5.68 -                        }
    5.69 -
    5.70 -                        @Override
    5.71 -                        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
    5.72 -                            data.close();
    5.73 -                            return new String(data.toByteArray());
    5.74 -                        }
    5.75 -                    };
    5.76 -                }
    5.77 -                
    5.78 -                throw new IllegalStateException();
    5.79 -            }
    5.80 -
    5.81 -            @Override
    5.82 -            public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
    5.83 -                if (location == StandardLocation.SOURCE_PATH) {
    5.84 -                    if (packageName.equals(pkg)) {
    5.85 -                        return htmlFile;
    5.86 -                    }
    5.87 -                }
    5.88 -                
    5.89 -                return null;
    5.90 -            }
    5.91 -            
    5.92 -        };
    5.93 +        JavaFileManager jfm = new ForwardingJavaFileManagerImpl(sjfm, class2BAOS, scratch, htmlFile);
    5.94  
    5.95          ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
    5.96  
    5.97 @@ -200,4 +142,117 @@
    5.98          String fqn = "'" + pkg + '.' + cls + "'";
    5.99          return html.replace("'${fqn}'", fqn);
   5.100      }
   5.101 +
   5.102 +    @ExtraJavaScript(processByteCode = false, resource = "")
   5.103 +    private class ForwardingJavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {
   5.104 +
   5.105 +        private final Map<String, ByteArrayOutputStream> class2BAOS;
   5.106 +        private final URI scratch;
   5.107 +        private final JavaFileObject htmlFile;
   5.108 +
   5.109 +        public ForwardingJavaFileManagerImpl(JavaFileManager fileManager, Map<String, ByteArrayOutputStream> class2BAOS, URI scratch, JavaFileObject htmlFile) {
   5.110 +            super(fileManager);
   5.111 +            this.class2BAOS = class2BAOS;
   5.112 +            this.scratch = scratch;
   5.113 +            this.htmlFile = htmlFile;
   5.114 +        }
   5.115 +
   5.116 +        @Override
   5.117 +        public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
   5.118 +            if (kind  == Kind.CLASS) {
   5.119 +                final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
   5.120 +                
   5.121 +                class2BAOS.put(className.replace('.', '/') + ".class", buffer);
   5.122 +                return new Sibling(sibling.toUri(), kind, buffer);
   5.123 +            }
   5.124 +            
   5.125 +            if (kind == Kind.SOURCE) {
   5.126 +                return new Source(scratch/*sibling.toUri()*/, kind);
   5.127 +            }
   5.128 +            
   5.129 +            throw new IllegalStateException();
   5.130 +        }
   5.131 +
   5.132 +            @Override
   5.133 +            public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
   5.134 +                if (location == StandardLocation.SOURCE_PATH) {
   5.135 +                    if (packageName.equals(pkg)) {
   5.136 +                        return htmlFile;
   5.137 +                    }
   5.138 +                }
   5.139 +                
   5.140 +                return null;
   5.141 +            }
   5.142 +
   5.143 +      @ExtraJavaScript(processByteCode = false, resource = "")
   5.144 +      private class Sibling extends SimpleJavaFileObject {
   5.145 +            private final ByteArrayOutputStream buffer;
   5.146 +
   5.147 +            public Sibling(URI uri, Kind kind, ByteArrayOutputStream buffer) {
   5.148 +                super(uri, kind);
   5.149 +                this.buffer = buffer;
   5.150 +            }
   5.151 +
   5.152 +            @Override
   5.153 +            public OutputStream openOutputStream() throws IOException {
   5.154 +                return buffer;
   5.155 +            }
   5.156 +        }
   5.157 +
   5.158 +      @ExtraJavaScript(processByteCode = false, resource = "")
   5.159 +      private class Source extends SimpleJavaFileObject {
   5.160 +            public Source(URI uri, Kind kind) {
   5.161 +                super(uri, kind);
   5.162 +            }
   5.163 +            private final ByteArrayOutputStream data = new ByteArrayOutputStream();
   5.164 +
   5.165 +            @Override
   5.166 +            public OutputStream openOutputStream() throws IOException {
   5.167 +                return data;
   5.168 +            }
   5.169 +
   5.170 +            @Override
   5.171 +            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   5.172 +                data.close();
   5.173 +                return new String(data.toByteArray());
   5.174 +            }
   5.175 +        }
   5.176 +    }
   5.177 +
   5.178 +    @ExtraJavaScript(processByteCode = false, resource = "")
   5.179 +    private static class Mem extends SimpleJavaFileObject {
   5.180 +
   5.181 +        private final String code;
   5.182 +
   5.183 +        public Mem(URI uri, Kind kind, String code) {
   5.184 +            super(uri, kind);
   5.185 +            this.code = code;
   5.186 +        }
   5.187 +
   5.188 +        @Override
   5.189 +        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   5.190 +            return code;
   5.191 +        }
   5.192 +    }
   5.193 +
   5.194 +    @ExtraJavaScript(processByteCode = false, resource = "")
   5.195 +    private static class Mem2 extends SimpleJavaFileObject {
   5.196 +
   5.197 +        private final String html;
   5.198 +
   5.199 +        public Mem2(URI uri, Kind kind, String html) {
   5.200 +            super(uri, kind);
   5.201 +            this.html = html;
   5.202 +        }
   5.203 +
   5.204 +        @Override
   5.205 +        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   5.206 +            return html;
   5.207 +        }
   5.208 +
   5.209 +        @Override
   5.210 +        public InputStream openInputStream() throws IOException {
   5.211 +            return new ByteArrayInputStream(html.getBytes());
   5.212 +        }
   5.213 +    }
   5.214  }
     6.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageTest.java	Wed Apr 30 09:26:28 2014 +0200
     6.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageTest.java	Tue May 06 17:46:47 2014 +0200
     6.3 @@ -21,6 +21,7 @@
     6.4  import java.util.Locale;
     6.5  import javax.tools.Diagnostic;
     6.6  import javax.tools.JavaFileObject;
     6.7 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
     6.8  import static org.testng.Assert.*;
     6.9  import org.testng.annotations.Test;
    6.10  
    6.11 @@ -28,6 +29,7 @@
    6.12   *
    6.13   * @author Jaroslav Tulach <jtulach@netbeans.org>
    6.14   */
    6.15 +@ExtraJavaScript(processByteCode = false, resource = "")
    6.16  public class PageTest {
    6.17      @Test public void verifyWrongType() throws IOException {
    6.18          String html = "<html><body>"
     7.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java	Wed Apr 30 09:26:28 2014 +0200
     7.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java	Tue May 06 17:46:47 2014 +0200
     7.3 @@ -24,10 +24,12 @@
     7.4  import javax.script.ScriptEngine;
     7.5  import javax.script.ScriptEngineManager;
     7.6  import javax.script.ScriptException;
     7.7 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
     7.8  import org.apidesign.vm4brwsr.Bck2Brwsr;
     7.9  import org.testng.annotations.Test;
    7.10  import static org.testng.Assert.*;
    7.11  
    7.12 +@ExtraJavaScript(processByteCode = false, resource = "")
    7.13  public class ProcessPageTest {
    7.14      
    7.15      
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/package-info.java	Tue May 06 17:46:47 2014 +0200
     8.3 @@ -0,0 +1,21 @@
     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 +@Exported
    8.22 +package org.apidesign.bck2brwsr.demo.calc.staticcompilation;
    8.23 +
    8.24 +import org.apidesign.bck2brwsr.core.Exported;
     9.1 --- a/launcher/fx/pom.xml	Wed Apr 30 09:26:28 2014 +0200
     9.2 +++ b/launcher/fx/pom.xml	Tue May 06 17:46:47 2014 +0200
     9.3 @@ -58,11 +58,13 @@
     9.4        <artifactId>testng</artifactId>
     9.5        <scope>test</scope>
     9.6      </dependency>
     9.7 +    <!--
     9.8      <dependency>
     9.9        <groupId>org.netbeans.modules</groupId>
    9.10        <artifactId>org-netbeans-bootstrap</artifactId>
    9.11        <version>RELEASE73</version>
    9.12      </dependency>
    9.13 +    -->
    9.14      <dependency>
    9.15        <groupId>${project.groupId}</groupId>
    9.16        <artifactId>core</artifactId>
    10.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java	Wed Apr 30 09:26:28 2014 +0200
    10.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java	Tue May 06 17:46:47 2014 +0200
    10.3 @@ -28,12 +28,14 @@
    10.4  import java.io.Reader;
    10.5  import java.io.UnsupportedEncodingException;
    10.6  import java.io.Writer;
    10.7 +import java.net.JarURLConnection;
    10.8  import java.net.URI;
    10.9  import java.net.URISyntaxException;
   10.10  import java.net.URL;
   10.11  import java.util.ArrayList;
   10.12  import java.util.Arrays;
   10.13  import java.util.Enumeration;
   10.14 +import java.util.HashSet;
   10.15  import java.util.LinkedHashSet;
   10.16  import java.util.List;
   10.17  import java.util.Set;
   10.18 @@ -42,6 +44,7 @@
   10.19  import java.util.concurrent.CountDownLatch;
   10.20  import java.util.concurrent.LinkedBlockingQueue;
   10.21  import java.util.concurrent.TimeUnit;
   10.22 +import java.util.jar.JarFile;
   10.23  import java.util.logging.Level;
   10.24  import java.util.logging.Logger;
   10.25  import org.apidesign.bck2brwsr.launcher.InvocationContext.Resource;
   10.26 @@ -59,7 +62,6 @@
   10.27  import org.glassfish.grizzly.websockets.WebSocketAddOn;
   10.28  import org.glassfish.grizzly.websockets.WebSocketApplication;
   10.29  import org.glassfish.grizzly.websockets.WebSocketEngine;
   10.30 -import org.openide.util.Exceptions;
   10.31  
   10.32  /**
   10.33   * Lightweight server to launch Bck2Brwsr applications and tests.
   10.34 @@ -176,7 +178,7 @@
   10.35              nl.getTransport().setWorkerThreadPoolConfig(fewThreads);
   10.36              nl.getTransport().setKernelThreadPoolConfig(oneKernel);
   10.37          }
   10.38 -        */
   10.39 +*/        
   10.40          final ServerConfiguration conf = s.getServerConfiguration();
   10.41          VMAndPages vm = new VMAndPages();
   10.42          conf.addHttpHandler(vm, "/");
   10.43 @@ -560,6 +562,12 @@
   10.44  
   10.45      abstract void generateBck2BrwsrJS(StringBuilder sb, Res loader) throws IOException;
   10.46      abstract String harnessResource();
   10.47 +    String compileJar(JarFile jar) throws IOException {
   10.48 +        return null;
   10.49 +    }
   10.50 +    String compileFromClassPath(URL f, Res loader) throws IOException {
   10.51 +        return null;
   10.52 +    }
   10.53  
   10.54      private static URI pageURL(String protocol, HttpServer server, final String page) {
   10.55          NetworkListener listener = server.getListeners().iterator().next();
   10.56 @@ -571,8 +579,18 @@
   10.57          }
   10.58      }
   10.59  
   10.60 -    class Res {
   10.61 -        public InputStream get(String resource, int skip) throws IOException {
   10.62 +    final class Res {
   10.63 +        private final Set<URL> ignore = new HashSet<URL>();
   10.64 +        
   10.65 +        String compileJar(JarFile jar, URL jarURL) throws IOException {
   10.66 +            String ret = BaseHTTPLauncher.this.compileJar(jar);
   10.67 +            ignore.add(jarURL);
   10.68 +            return ret;
   10.69 +        }
   10.70 +        String compileFromClassPath(URL f) throws IOException {
   10.71 +            return BaseHTTPLauncher.this.compileFromClassPath(f, this);
   10.72 +        }
   10.73 +        public URL get(String resource, int skip) throws IOException {
   10.74              if (!resource.endsWith(".class")) {
   10.75                  return getResource(resource, skip);
   10.76              }
   10.77 @@ -582,7 +600,7 @@
   10.78                  while (en.hasMoreElements()) {
   10.79                      u = en.nextElement();
   10.80                      if (u.toExternalForm().matches("^.*emul.*rt\\.jar.*$")) {
   10.81 -                        return u.openStream();
   10.82 +                        return u;
   10.83                      }
   10.84                  }
   10.85              }
   10.86 @@ -591,11 +609,11 @@
   10.87                      LOG.log(Level.WARNING, "No fallback to bootclasspath for {0}", u);
   10.88                      return null;
   10.89                  }
   10.90 -                return u.openStream();
   10.91 +                return u;
   10.92              }
   10.93              throw new IOException("Can't find " + resource);
   10.94          }
   10.95 -        private InputStream getResource(String resource, int skip) throws IOException {
   10.96 +        private URL getResource(String resource, int skip) throws IOException {
   10.97              for (ClassLoader l : loaders) {
   10.98                  Enumeration<URL> en = l.getResources(resource);
   10.99                  while (en.hasMoreElements()) {
  10.100 @@ -605,8 +623,14 @@
  10.101                          // module is not compiled with target 1.6, currently
  10.102                          continue;
  10.103                      }
  10.104 +                    if (now.getProtocol().equals("jar")) {
  10.105 +                        JarURLConnection juc = (JarURLConnection) now.openConnection();
  10.106 +                        if (ignore.contains(juc.getJarFileURL())) {
  10.107 +                            continue;
  10.108 +                        }
  10.109 +                    }
  10.110                      if (--skip < 0) {
  10.111 -                        return now.openStream();
  10.112 +                        return now;
  10.113                      }
  10.114                  }
  10.115              }
  10.116 @@ -644,7 +668,7 @@
  10.117              }
  10.118              OutputStream os = response.getOutputStream();
  10.119              try { 
  10.120 -                InputStream is = res.get(r, 0);
  10.121 +                InputStream is = res.get(r, 0).openStream();
  10.122                  copyStream(is, os, request.getRequestURL().toString(), replace);
  10.123              } catch (IOException ex) {
  10.124                  response.setDetailMessage(ex.getLocalizedMessage());
  10.125 @@ -714,14 +738,42 @@
  10.126              if (res.startsWith("/")) {
  10.127                  res = res.substring(1);
  10.128              }
  10.129 +            String skip = request.getParameter("skip");
  10.130 +            int skipCnt = skip == null ? 0 : Integer.parseInt(skip);
  10.131 +            URL url = loader.get(res, skipCnt);
  10.132 +            if (url != null && !res.equals("META-INF/MANIFEST.MF")) try {
  10.133 +                response.setCharacterEncoding("UTF-8");
  10.134 +                if (url.getProtocol().equals("jar")) {
  10.135 +                    JarURLConnection juc = (JarURLConnection) url.openConnection();
  10.136 +                    String s = loader.compileJar(juc.getJarFile(), juc.getJarFileURL());
  10.137 +                    if (s != null) {
  10.138 +                        Writer w = response.getWriter();
  10.139 +                        w.append(s);
  10.140 +                        w.close();
  10.141 +                        return;
  10.142 +                    }
  10.143 +                }
  10.144 +                if (url.getProtocol().equals("file")) {
  10.145 +                    String s = loader.compileFromClassPath(url);
  10.146 +                    if (s != null) {
  10.147 +                        Writer w = response.getWriter();
  10.148 +                        w.append(s);
  10.149 +                        w.close();
  10.150 +                        return;
  10.151 +                    }
  10.152 +                }
  10.153 +            } catch (IOException ex) {
  10.154 +                LOG.log(Level.SEVERE, "Cannot handle " + res, ex);
  10.155 +            }
  10.156              InputStream is = null;
  10.157              try {
  10.158 -                String skip = request.getParameter("skip");
  10.159 -                int skipCnt = skip == null ? 0 : Integer.parseInt(skip);
  10.160 -                is = loader.get(res, skipCnt);
  10.161 +                if (url == null) {
  10.162 +                    throw new IOException("Resource not found");
  10.163 +                }
  10.164 +                is = url.openStream();
  10.165                  response.setContentType("text/javascript");
  10.166                  Writer w = response.getWriter();
  10.167 -                w.append("[");
  10.168 +                w.append("([");
  10.169                  for (int i = 0;; i++) {
  10.170                      int b = is.read();
  10.171                      if (b == -1) {
  10.172 @@ -738,7 +790,7 @@
  10.173                      }
  10.174                      w.append(Integer.toString(b));
  10.175                  }
  10.176 -                w.append("\n]");
  10.177 +                w.append("\n])");
  10.178              } catch (IOException ex) {
  10.179                  response.setStatus(HttpStatus.NOT_FOUND_404);
  10.180                  response.setError();
  10.181 @@ -749,6 +801,7 @@
  10.182                  }
  10.183              }
  10.184          }
  10.185 +
  10.186      }
  10.187      private static class WS extends WebSocketApplication {
  10.188  
  10.189 @@ -767,7 +820,7 @@
  10.190                  String s = new String(out.toByteArray(), "UTF-8");
  10.191                  socket.send(s);
  10.192              } catch (IOException ex) {
  10.193 -                Exceptions.printStackTrace(ex);
  10.194 +                LOG.log(Level.WARNING, null, ex);
  10.195              }
  10.196          }
  10.197  
    11.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/FXBrwsrLauncher.java	Wed Apr 30 09:26:28 2014 +0200
    11.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/FXBrwsrLauncher.java	Tue May 06 17:46:47 2014 +0200
    11.3 @@ -37,7 +37,6 @@
    11.4  import java.util.logging.Logger;
    11.5  import javafx.application.Platform;
    11.6  import org.apidesign.bck2brwsr.launcher.fximpl.JVMBridge;
    11.7 -import org.openide.util.Exceptions;
    11.8  
    11.9  /**
   11.10   *
    12.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXInspect.java	Wed Apr 30 09:26:28 2014 +0200
    12.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXInspect.java	Tue May 06 17:46:47 2014 +0200
    12.3 @@ -29,7 +29,6 @@
    12.4  import javafx.application.Platform;
    12.5  import javafx.scene.web.WebEngine;
    12.6  import javafx.util.Callback;
    12.7 -import org.openide.util.Exceptions;
    12.8  
    12.9  /**
   12.10   *
    13.1 --- a/launcher/http/pom.xml	Wed Apr 30 09:26:28 2014 +0200
    13.2 +++ b/launcher/http/pom.xml	Tue May 06 17:46:47 2014 +0200
    13.3 @@ -56,5 +56,16 @@
    13.4        <artifactId>vm4brwsr</artifactId>
    13.5        <version>${project.version}</version>
    13.6      </dependency>
    13.7 +    <dependency>
    13.8 +      <groupId>org.testng</groupId>
    13.9 +      <artifactId>testng</artifactId>
   13.10 +      <scope>test</scope>
   13.11 +    </dependency>
   13.12 +    <dependency>
   13.13 +      <groupId>${project.groupId}</groupId>
   13.14 +      <artifactId>emul.mini</artifactId>
   13.15 +      <version>${project.version}</version>
   13.16 +      <scope>test</scope>
   13.17 +    </dependency>
   13.18    </dependencies>
   13.19  </project>
    14.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Wed Apr 30 09:26:28 2014 +0200
    14.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Tue May 06 17:46:47 2014 +0200
    14.3 @@ -25,8 +25,10 @@
    14.4  import java.io.Reader;
    14.5  import java.net.MalformedURLException;
    14.6  import java.net.URL;
    14.7 +import java.util.HashSet;
    14.8 +import java.util.Set;
    14.9 +import java.util.jar.JarFile;
   14.10  import java.util.logging.Level;
   14.11 -import org.apidesign.vm4brwsr.Bck2Brwsr;
   14.12  
   14.13  /**
   14.14   * Lightweight server to launch Bck2Brwsr applications and tests.
   14.15 @@ -34,6 +36,7 @@
   14.16   * execution engine.
   14.17   */
   14.18  final class Bck2BrwsrLauncher extends BaseHTTPLauncher {
   14.19 +    private Set<String> testClasses = new HashSet<String>();
   14.20      
   14.21      public Bck2BrwsrLauncher(String cmd) {
   14.22          super(cmd);
   14.23 @@ -43,15 +46,24 @@
   14.24      String harnessResource() {
   14.25          return "org/apidesign/bck2brwsr/launcher/harness.xhtml";
   14.26      }
   14.27 +
   14.28 +    @Override
   14.29 +    String compileJar(JarFile jar) throws IOException {
   14.30 +        return CompileCP.compileJAR(jar, testClasses);
   14.31 +    }
   14.32 +
   14.33 +    @Override
   14.34 +    public InvocationContext createInvocation(Class<?> clazz, String method) {
   14.35 +        testClasses.add(clazz.getName().replace('.', '/'));
   14.36 +        return super.createInvocation(clazz, method);
   14.37 +    }
   14.38 +
   14.39 +    @Override String compileFromClassPath(URL f, Res loader) throws IOException {
   14.40 +        return CompileCP.compileFromClassPath(f, loader);
   14.41 +    }
   14.42      
   14.43      @Override
   14.44      void generateBck2BrwsrJS(StringBuilder sb, final Res loader) throws IOException {
   14.45 -        class R implements Bck2Brwsr.Resources {
   14.46 -            @Override
   14.47 -            public InputStream get(String resource) throws IOException {
   14.48 -                return loader.get(resource, 0);
   14.49 -            }
   14.50 -        }
   14.51          String b2b = System.getProperty("bck2brwsr.js");
   14.52          if (b2b != null) {
   14.53              LOG.log(Level.INFO, "Serving bck2brwsr.js from {0}", b2b);
   14.54 @@ -78,16 +90,17 @@
   14.55              }
   14.56          } else {
   14.57              LOG.log(Level.INFO, "Generating bck2brwsr.js from scratch", b2b);
   14.58 -            Bck2Brwsr.generate(sb, new R());
   14.59 +            CompileCP.compileVM(sb, loader);
   14.60          }
   14.61          sb.append(
   14.62                "(function WrapperVM(global) {\n"
   14.63              + "  var cache = {};\n"
   14.64 +            + "  var empty = {};\n"
   14.65              + "  function ldCls(res, skip) {\n"
   14.66              + "    var c = cache[res];\n"
   14.67              + "    if (c) {\n"
   14.68 +            + "      if (c[skip] === empty) return null;\n"
   14.69              + "      if (c[skip]) return c[skip];\n"
   14.70 -            + "      if (c[skip] === null) return null;\n"
   14.71              + "    } else {\n"
   14.72              + "      cache[res] = c = new Array();\n"
   14.73              + "    }\n"
   14.74 @@ -98,8 +111,9 @@
   14.75              + "      c[skip] = null;\n"
   14.76              + "      return null;\n"
   14.77              + "    }\n"
   14.78 -            + "    var arr = eval('(' + request.responseText + ')');\n"
   14.79 -            + "    c[skip] = arr;\n"
   14.80 +            + "    var arr = eval(request.responseText);\n"
   14.81 +            + "    if (arr === null) c[skip] = empty;\n"
   14.82 +            + "    else c[skip] = arr;\n"
   14.83              + "    return arr;\n"
   14.84              + "  }\n"
   14.85              + "  var prevvm = global.bck2brwsr;\n"
   14.86 @@ -108,6 +122,7 @@
   14.87              + "    args.unshift(ldCls);\n"
   14.88              + "    return prevvm.apply(null, args);\n"
   14.89              + "  };\n"
   14.90 +            + "  global.bck2brwsr.registerExtension = prevvm.registerExtension;\n"
   14.91              + "})(this);\n"
   14.92          );
   14.93          LOG.log(Level.INFO, "Serving bck2brwsr.js", b2b);
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java	Tue May 06 17:46:47 2014 +0200
    15.3 @@ -0,0 +1,249 @@
    15.4 +/**
    15.5 + * Back 2 Browser Bytecode Translator
    15.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    15.7 + *
    15.8 + * This program is free software: you can redistribute it and/or modify
    15.9 + * it under the terms of the GNU General Public License as published by
   15.10 + * the Free Software Foundation, version 2 of the License.
   15.11 + *
   15.12 + * This program is distributed in the hope that it will be useful,
   15.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15.15 + * GNU General Public License for more details.
   15.16 + *
   15.17 + * You should have received a copy of the GNU General Public License
   15.18 + * along with this program. Look for COPYING file in the top folder.
   15.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   15.20 + */
   15.21 +package org.apidesign.bck2brwsr.launcher;
   15.22 +
   15.23 +import java.io.BufferedReader;
   15.24 +import java.io.File;
   15.25 +import java.io.IOException;
   15.26 +import java.io.InputStream;
   15.27 +import java.io.InputStreamReader;
   15.28 +import java.io.StringWriter;
   15.29 +import java.net.JarURLConnection;
   15.30 +import java.net.URISyntaxException;
   15.31 +import java.net.URL;
   15.32 +import java.util.ArrayList;
   15.33 +import java.util.Enumeration;
   15.34 +import java.util.HashSet;
   15.35 +import java.util.List;
   15.36 +import java.util.Set;
   15.37 +import java.util.jar.JarEntry;
   15.38 +import java.util.jar.JarFile;
   15.39 +import java.util.logging.Level;
   15.40 +import java.util.logging.Logger;
   15.41 +import java.util.zip.ZipEntry;
   15.42 +import org.apidesign.bck2brwsr.launcher.BaseHTTPLauncher.Res;
   15.43 +import org.apidesign.vm4brwsr.Bck2Brwsr;
   15.44 +
   15.45 +/**
   15.46 + *
   15.47 + * @author Jaroslav Tulach
   15.48 + */
   15.49 +class CompileCP {
   15.50 +    private static final Logger LOG = Logger.getLogger(CompileCP.class.getName());
   15.51 +    static String compileJAR(final JarFile jar, Set<String> testClasses) 
   15.52 +    throws IOException {
   15.53 +        List<String> arr = new ArrayList<>();
   15.54 +        List<String> classes = new ArrayList<>();
   15.55 +        Set<String> exported = new HashSet<String>();
   15.56 +        Set<String> keep = new HashSet<String>(testClasses);
   15.57 +        listJAR(jar, classes, arr, exported, keep);
   15.58 +        List<String> root = new ArrayList<>();
   15.59 +        for (String c : classes) {
   15.60 +            if (keep.contains(c)) {
   15.61 +                root.add(c);
   15.62 +                continue;
   15.63 +            }
   15.64 +            int slash = c.lastIndexOf('/');
   15.65 +            String pkg = c.substring(0, slash + 1);
   15.66 +            if (exported.contains(pkg)) {
   15.67 +                root.add(c);
   15.68 +            }
   15.69 +        }
   15.70 +        
   15.71 +        StringWriter w = new StringWriter();
   15.72 +        try {
   15.73 +            class JarRes extends EmulationResources implements Bck2Brwsr.Resources {
   15.74 +                @Override
   15.75 +                public InputStream get(String resource) throws IOException {
   15.76 +                    InputStream is = jar.getInputStream(new ZipEntry(resource));
   15.77 +                    return is == null ? super.get(resource) : is;
   15.78 +                }
   15.79 +            }
   15.80 +            
   15.81 +            Bck2Brwsr.newCompiler()
   15.82 +                .addClasses(classes.toArray(new String[0]))
   15.83 +                .addRootClasses(root.toArray(new String[0]))
   15.84 +                .addResources(arr.toArray(new String[0]))
   15.85 +                .library(true)
   15.86 +                .resources(new JarRes())
   15.87 +                .generate(w);
   15.88 +            w.flush();
   15.89 +            return w.toString();
   15.90 +        } catch (IOException ex) {
   15.91 +            throw ex;
   15.92 +        } catch (Throwable ex) {
   15.93 +            throw new IOException("Cannot compile: ", ex);
   15.94 +        } finally {
   15.95 +            w.close();
   15.96 +        }
   15.97 +    }
   15.98 +    
   15.99 +    static String compileFromClassPath(URL u, final Res r) throws IOException {
  15.100 +        File f;
  15.101 +        try {
  15.102 +            f = new File(u.toURI());
  15.103 +        } catch (URISyntaxException ex) {
  15.104 +            throw new IOException(ex);
  15.105 +        }
  15.106 +        for (String s : System.getProperty("java.class.path").split(File.pathSeparator)) {
  15.107 +            if (!f.getPath().startsWith(s)) {
  15.108 +                continue;
  15.109 +            }
  15.110 +            File root = new File(s);
  15.111 +            List<String> arr = new ArrayList<>();
  15.112 +            List<String> classes = new ArrayList<>();
  15.113 +            listDir(root, null, classes, arr);
  15.114 +            StringWriter w = new StringWriter();
  15.115 +            try {
  15.116 +                Bck2Brwsr.newCompiler()
  15.117 +                    .addRootClasses(classes.toArray(new String[0]))
  15.118 +                    .addResources(arr.toArray(new String[0]))
  15.119 +                    .library(true)
  15.120 +                    .resources(new EmulationResources() {
  15.121 +                        @Override
  15.122 +                        public InputStream get(String resource) throws IOException {
  15.123 +                            if (r != null) {
  15.124 +                                final URL url = r.get(resource, 0);
  15.125 +                                return url == null ? null : url.openStream();
  15.126 +                            }
  15.127 +                            return super.get(resource);
  15.128 +                        }
  15.129 +                    })
  15.130 +                    .generate(w);
  15.131 +                w.flush();
  15.132 +                return w.toString();
  15.133 +            } catch (ClassFormatError ex) {
  15.134 +                throw new IOException(ex);
  15.135 +            } finally {
  15.136 +                w.close();
  15.137 +            }
  15.138 +        }
  15.139 +        return null;
  15.140 +    }
  15.141 +    
  15.142 +    private static void listJAR(
  15.143 +        JarFile j, List<String> classes,
  15.144 +        List<String> resources, Set<String> exported, Set<String> keep
  15.145 +    ) throws IOException {
  15.146 +        Enumeration<JarEntry> en = j.entries();
  15.147 +        while (en.hasMoreElements()) {
  15.148 +            JarEntry e = en.nextElement();
  15.149 +            final String n = e.getName();
  15.150 +            if (n.contains("package-info")) {
  15.151 +                continue;
  15.152 +            }
  15.153 +            if (n.endsWith("/")) {
  15.154 +                continue;
  15.155 +            }
  15.156 +            int last = n.lastIndexOf('/');
  15.157 +            String pkg = n.substring(0, last + 1);
  15.158 +            if (skipPkg(pkg)) {
  15.159 +                continue;
  15.160 +            }
  15.161 +            if (n.endsWith(".class")) {
  15.162 +                classes.add(n.substring(0, n.length() - 6));
  15.163 +            } else {
  15.164 +                resources.add(n);
  15.165 +                if (n.startsWith("META-INF/services/") && keep != null) {
  15.166 +                    BufferedReader r = new BufferedReader(new InputStreamReader(j.getInputStream(e)));
  15.167 +                    for (;;) {
  15.168 +                        String l = r.readLine();
  15.169 +                        if (l == null) {
  15.170 +                            break;
  15.171 +                        }
  15.172 +                        if (l.startsWith("#")) {
  15.173 +                            continue;
  15.174 +                        }
  15.175 +                        keep.add(l.replace('.', '/'));
  15.176 +                    }
  15.177 +                }
  15.178 +            }
  15.179 +        }
  15.180 +        String exp = j.getManifest().getMainAttributes().getValue("Export-Package");
  15.181 +        if (exp != null && exported != null) {
  15.182 +            for (String def : exp.split(",")) {
  15.183 +                for (String sep : def.split(";")) {
  15.184 +                    exported.add(sep.replace('.', '/') + "/");
  15.185 +                    break;
  15.186 +                }
  15.187 +            }
  15.188 +        }
  15.189 +    }
  15.190 +
  15.191 +    private static boolean skipPkg(String pkg) {
  15.192 +        return pkg.equals("org/apidesign/bck2brwsr/launcher/");
  15.193 +    }
  15.194 +    
  15.195 +    private static void listDir(File f, String pref, List<String> classes, List<String> resources) throws IOException {
  15.196 +        File[] arr = f.listFiles();
  15.197 +        if (arr == null) {
  15.198 +            if (f.getName().equals("package-info.class")) {
  15.199 +                return;
  15.200 +            }
  15.201 +            if (f.getName().endsWith(".class")) {
  15.202 +                classes.add(pref + f.getName().substring(0, f.getName().length() - 6));
  15.203 +            } else {
  15.204 +                resources.add(pref + f.getName());
  15.205 +            }
  15.206 +        } else {
  15.207 +            for (File ch : arr) {
  15.208 +                
  15.209 +                listDir(ch, pref == null ? "" : pref + f.getName() + "/", classes, resources);
  15.210 +            }
  15.211 +        }
  15.212 +    }
  15.213 +
  15.214 +    static void compileVM(StringBuilder sb, final Res r) throws IOException {
  15.215 +        URL u = r.get(InterruptedException.class.getName().replace('.', '/') + ".class", 0);
  15.216 +        JarURLConnection juc = (JarURLConnection)u.openConnection();
  15.217 +        
  15.218 +        List<String> arr = new ArrayList<>();
  15.219 +        List<String> classes = new ArrayList<>();
  15.220 +        listJAR(juc.getJarFile(), classes, arr, null, null);
  15.221 +
  15.222 +        Bck2Brwsr.newCompiler().addRootClasses(classes.toArray(new String[0]))
  15.223 +            .resources(new Bck2Brwsr.Resources() {
  15.224 +                @Override
  15.225 +                public InputStream get(String resource) throws IOException {
  15.226 +                    final URL url = r.get(resource, 0);
  15.227 +                    return url == null ? null : url.openStream();
  15.228 +                }
  15.229 +            }).generate(sb);
  15.230 +    }
  15.231 +
  15.232 +    static class EmulationResources implements Bck2Brwsr.Resources {
  15.233 +
  15.234 +        @Override
  15.235 +        public InputStream get(String name) throws IOException {
  15.236 +            Enumeration<URL> en = CompileCP.class.getClassLoader().getResources(name);
  15.237 +            URL u = null;
  15.238 +            while (en.hasMoreElements()) {
  15.239 +                u = en.nextElement();
  15.240 +            }
  15.241 +            if (u == null) {
  15.242 +                LOG.log(Level.WARNING, "Cannot find {0}", name);
  15.243 +                return null;
  15.244 +            }
  15.245 +            if (u.toExternalForm().contains("/rt.jar!")) {
  15.246 +                LOG.warning(name + "No bootdelegation for ");
  15.247 +                return null;
  15.248 +            }
  15.249 +            return u.openStream();
  15.250 +        }
  15.251 +    }
  15.252 +}
    16.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java	Wed Apr 30 09:26:28 2014 +0200
    16.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java	Tue May 06 17:46:47 2014 +0200
    16.3 @@ -31,6 +31,7 @@
    16.4   *
    16.5   * @author Jaroslav Tulach <jtulach@netbeans.org>
    16.6   */
    16.7 +@org.apidesign.bck2brwsr.core.Exported 
    16.8  public class Console {
    16.9      private Console() {
   16.10      }
   16.11 @@ -265,7 +266,7 @@
   16.12          return u;
   16.13      }
   16.14      
   16.15 -    @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
   16.16 +    @JavaScriptBody(args = {}, body = "vm.java_lang_Class(false).desiredAssertionStatus = true;")
   16.17      private static void turnAssetionStatusOn() {
   16.18      }
   16.19  
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/launcher/http/src/test/java/org/apidesign/bck2brwsr/launcher/CompileCPTest.java	Tue May 06 17:46:47 2014 +0200
    17.3 @@ -0,0 +1,41 @@
    17.4 +/**
    17.5 + * Back 2 Browser Bytecode Translator
    17.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    17.7 + *
    17.8 + * This program is free software: you can redistribute it and/or modify
    17.9 + * it under the terms of the GNU General Public License as published by
   17.10 + * the Free Software Foundation, version 2 of the License.
   17.11 + *
   17.12 + * This program is distributed in the hope that it will be useful,
   17.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   17.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17.15 + * GNU General Public License for more details.
   17.16 + *
   17.17 + * You should have received a copy of the GNU General Public License
   17.18 + * along with this program. Look for COPYING file in the top folder.
   17.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   17.20 + */
   17.21 +package org.apidesign.bck2brwsr.launcher;
   17.22 +
   17.23 +import java.io.File;
   17.24 +import java.net.URL;
   17.25 +import static org.testng.Assert.*;
   17.26 +import org.testng.annotations.Test;
   17.27 +
   17.28 +/**
   17.29 + *
   17.30 + * @author Jaroslav Tulach
   17.31 + */
   17.32 +public class CompileCPTest {
   17.33 +    public CompileCPTest() {
   17.34 +    }
   17.35 +
   17.36 +    @Test public void compileClassPath() throws Exception {
   17.37 +        URL u = CompileCPTest.class.getResource("/" + CompileCPTest.class.getName().replace('.', '/') + ".class");
   17.38 +        assertNotNull(u, "URL found");
   17.39 +        assertEquals(u.getProtocol(), "file", "It comes from a disk");
   17.40 +        
   17.41 +        String resources = CompileCP.compileFromClassPath(u, null);
   17.42 +        assertNotNull(resources, "something compiled");
   17.43 +    }
   17.44 +}
    18.1 --- a/pom.xml	Wed Apr 30 09:26:28 2014 +0200
    18.2 +++ b/pom.xml	Tue May 06 17:46:47 2014 +0200
    18.3 @@ -13,7 +13,7 @@
    18.4    </parent>  
    18.5    <properties>
    18.6        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    18.7 -      <netbeans.version>RELEASE74</netbeans.version>
    18.8 +      <netbeans.version>RELEASE80</netbeans.version>
    18.9        <license>COPYING</license>
   18.10        <net.java.html.version>0.7.6</net.java.html.version>
   18.11        <netbeans.compile.on.save>none</netbeans.compile.on.save>
   18.12 @@ -89,7 +89,7 @@
   18.13                         <exclude>rt/emul/compact/src/main/**</exclude>
   18.14                         <exclude>rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java</exclude>
   18.15                         <exclude>rt/archetype/src/main/resources/archetype-resources/**</exclude>
   18.16 -                       <exclude>rt/emul/compact/src/test/resources/**</exclude>
   18.17 +                       <exclude>rt/emul/*/src/test/resources/**</exclude>
   18.18                         <exclude>javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout*.js</exclude>
   18.19                         <exclude>ko/archetype/src/main/resources/archetype-resources/**</exclude>
   18.20                    </excludes>
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/rt/core/src/main/java/org/apidesign/bck2brwsr/core/Exported.java	Tue May 06 17:46:47 2014 +0200
    19.3 @@ -0,0 +1,38 @@
    19.4 +/**
    19.5 + * Back 2 Browser Bytecode Translator
    19.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    19.7 + *
    19.8 + * This program is free software: you can redistribute it and/or modify
    19.9 + * it under the terms of the GNU General Public License as published by
   19.10 + * the Free Software Foundation, version 2 of the License.
   19.11 + *
   19.12 + * This program is distributed in the hope that it will be useful,
   19.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   19.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19.15 + * GNU General Public License for more details.
   19.16 + *
   19.17 + * You should have received a copy of the GNU General Public License
   19.18 + * along with this program. Look for COPYING file in the top folder.
   19.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   19.20 + */
   19.21 +package org.apidesign.bck2brwsr.core;
   19.22 +
   19.23 +import java.lang.annotation.ElementType;
   19.24 +import java.lang.annotation.Retention;
   19.25 +import java.lang.annotation.RetentionPolicy;
   19.26 +import java.lang.annotation.Target;
   19.27 +
   19.28 +/**
   19.29 + * Marks the corresponding program element as exported. Exported elements are
   19.30 + * visible from other modules. Can be used on packages, classes, methods,
   19.31 + * constructors and fields.
   19.32 + *
   19.33 + * @since 0.6
   19.34 + */
   19.35 +@Retention(RetentionPolicy.CLASS)
   19.36 +@Target({ ElementType.PACKAGE, ElementType.TYPE,
   19.37 +          ElementType.METHOD, ElementType.CONSTRUCTOR,
   19.38 +          ElementType.FIELD })
   19.39 +public @interface Exported {
   19.40 +
   19.41 +}
    20.1 --- a/rt/core/src/main/java/org/apidesign/bck2brwsr/core/impl/JavaScriptProcesor.java	Wed Apr 30 09:26:28 2014 +0200
    20.2 +++ b/rt/core/src/main/java/org/apidesign/bck2brwsr/core/impl/JavaScriptProcesor.java	Tue May 06 17:46:47 2014 +0200
    20.3 @@ -35,6 +35,7 @@
    20.4  import javax.lang.model.element.VariableElement;
    20.5  import javax.lang.model.type.TypeKind;
    20.6  import javax.tools.Diagnostic;
    20.7 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
    20.8  import org.apidesign.bck2brwsr.core.JavaScriptBody;
    20.9  import org.openide.util.lookup.ServiceProvider;
   20.10  
   20.11 @@ -42,6 +43,7 @@
   20.12   *
   20.13   * @author Jaroslav Tulach <jtulach@netbeans.org>
   20.14   */
   20.15 +@ExtraJavaScript(processByteCode = false, resource="")
   20.16  @ServiceProvider(service = Processor.class)
   20.17  public final class JavaScriptProcesor extends AbstractProcessor {
   20.18      @Override
    21.1 --- a/rt/emul/brwsrtest/pom.xml	Wed Apr 30 09:26:28 2014 +0200
    21.2 +++ b/rt/emul/brwsrtest/pom.xml	Tue May 06 17:46:47 2014 +0200
    21.3 @@ -48,5 +48,11 @@
    21.4        <version>${project.version}</version>
    21.5        <scope>provided</scope>
    21.6      </dependency>
    21.7 +    <dependency>
    21.8 +      <groupId>${project.groupId}</groupId>
    21.9 +      <artifactId>emul</artifactId>
   21.10 +      <version>${project.version}</version>
   21.11 +      <scope>test</scope>
   21.12 +    </dependency>
   21.13    </dependencies>
   21.14  </project>
    22.1 --- a/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/BooleanTest.java	Wed Apr 30 09:26:28 2014 +0200
    22.2 +++ b/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/BooleanTest.java	Tue May 06 17:46:47 2014 +0200
    22.3 @@ -19,7 +19,6 @@
    22.4  
    22.5  import org.apidesign.bck2brwsr.core.JavaScriptBody;
    22.6  import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
    22.7 -import org.apidesign.bck2brwsr.vmtest.Compare;
    22.8  import org.apidesign.bck2brwsr.vmtest.VMTest;
    22.9  import org.testng.annotations.Factory;
   22.10  
   22.11 @@ -28,6 +27,8 @@
   22.12   * @author Jaroslav Tulach <jtulach@netbeans.org>
   22.13   */
   22.14  public class BooleanTest {
   22.15 +    private static Boolean TRUE = Boolean.TRUE;
   22.16 +    
   22.17      @JavaScriptBody(args = { "tr" }, body = "return tr ? true : false;")
   22.18      private static native Object trueFalse(boolean tr);
   22.19      
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/ResourcesInBrwsrTest.java	Tue May 06 17:46:47 2014 +0200
    23.3 @@ -0,0 +1,71 @@
    23.4 +/**
    23.5 + * Back 2 Browser Bytecode Translator
    23.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    23.7 + *
    23.8 + * This program is free software: you can redistribute it and/or modify
    23.9 + * it under the terms of the GNU General Public License as published by
   23.10 + * the Free Software Foundation, version 2 of the License.
   23.11 + *
   23.12 + * This program is distributed in the hope that it will be useful,
   23.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   23.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   23.15 + * GNU General Public License for more details.
   23.16 + *
   23.17 + * You should have received a copy of the GNU General Public License
   23.18 + * along with this program. Look for COPYING file in the top folder.
   23.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   23.20 + */
   23.21 +package org.apidesign.bck2brwsr.brwsrtest;
   23.22 +
   23.23 +import java.io.IOException;
   23.24 +import java.io.InputStream;
   23.25 +import java.net.URL;
   23.26 +import java.util.Enumeration;
   23.27 +import org.apidesign.bck2brwsr.vmtest.Compare;
   23.28 +import org.apidesign.bck2brwsr.vmtest.VMTest;
   23.29 +import org.testng.annotations.Factory;
   23.30 +
   23.31 +/**
   23.32 + *
   23.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   23.34 + */
   23.35 +public class ResourcesInBrwsrTest {
   23.36 +    
   23.37 +    @Compare public String readResourceAsStream() throws Exception {
   23.38 +        InputStream is = getClass().getResourceAsStream("Resources.txt");
   23.39 +        return readString(is);
   23.40 +    }
   23.41 +    
   23.42 +    @Compare public String readResourceViaConnection() throws Exception {
   23.43 +        InputStream is = getClass().getResource("Resources.txt").openConnection().getInputStream();
   23.44 +        return readString(is);
   23.45 +    }
   23.46 +
   23.47 +    private String readString(InputStream is) throws IOException {
   23.48 +        StringBuilder sb = new StringBuilder();
   23.49 +        byte[] b = new byte[512];
   23.50 +        for (;;) { 
   23.51 +            int len = is.read(b);
   23.52 +            if (len == -1) {
   23.53 +                return sb.toString();
   23.54 +            }
   23.55 +            for (int i = 0; i < len; i++) {
   23.56 +                sb.append((char)b[i]);
   23.57 +            }
   23.58 +        }
   23.59 +    }
   23.60 +
   23.61 +    @Compare public String readResourceAsStreamFromClassLoader() throws Exception {
   23.62 +        InputStream is = getClass().getClassLoader().getResourceAsStream("org/apidesign/bck2brwsr/brwsrtest/Resources.txt");
   23.63 +        return readString(is);
   23.64 +    }
   23.65 +    
   23.66 +    @Compare public String toURIFromURL() throws Exception {
   23.67 +        URL u = new URL("http://apidesign.org");
   23.68 +        return u.toURI().toString();
   23.69 +    }
   23.70 +    
   23.71 +    @Factory public static Object[] create() {
   23.72 +        return VMTest.create(ResourcesInBrwsrTest.class);
   23.73 +    }
   23.74 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/rt/emul/brwsrtest/src/test/resources/org/apidesign/bck2brwsr/brwsrtest/Resources.txt	Tue May 06 17:46:47 2014 +0200
    24.3 @@ -0,0 +1,1 @@
    24.4 +Ahoj
    25.1 --- a/rt/emul/compact/pom.xml	Wed Apr 30 09:26:28 2014 +0200
    25.2 +++ b/rt/emul/compact/pom.xml	Tue May 06 17:46:47 2014 +0200
    25.3 @@ -86,7 +86,25 @@
    25.4                          </configuration>
    25.5                      </execution>
    25.6                  </executions>                
    25.7 -            </plugin>      
    25.8 +            </plugin> 
    25.9 +            <plugin>
   25.10 +                <groupId>org.apache.maven.plugins</groupId>
   25.11 +                <artifactId>maven-surefire-plugin</artifactId>
   25.12 +                <executions>
   25.13 +                    <execution>
   25.14 +                        <id>brwsr</id>
   25.15 +                        <goals>
   25.16 +                            <goal>test</goal>
   25.17 +                        </goals>
   25.18 +                        <phase>verify</phase>
   25.19 +                        <configuration>
   25.20 +                            <systemProperties>
   25.21 +                                <vmtest.js>brwsr</vmtest.js>
   25.22 +                            </systemProperties>
   25.23 +                        </configuration>
   25.24 +                    </execution>
   25.25 +                </executions>
   25.26 +            </plugin>     
   25.27        </plugins>
   25.28    </build>
   25.29  </project>
    26.1 --- a/rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java	Wed Apr 30 09:26:28 2014 +0200
    26.2 +++ b/rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java	Tue May 06 17:46:47 2014 +0200
    26.3 @@ -50,6 +50,7 @@
    26.4  import java.util.WeakHashMap;
    26.5  import org.apidesign.bck2brwsr.core.JavaScriptBody;
    26.6  import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
    26.7 +import org.apidesign.vm4brwsr.api.VM;
    26.8  
    26.9  /**
   26.10   * {@code Proxy} provides static methods for creating dynamic proxy
   26.11 @@ -677,7 +678,10 @@
   26.12      }
   26.13  
   26.14      @JavaScriptBody(args = { "ignore", "name", "byteCode" }, 
   26.15 -        body = "return vm._reload(name, byteCode).constructor.$class;"
   26.16 +        body = 
   26.17 +            "var r = vm._reload;"
   26.18 +          + "if (!r) r = exports._reload;"
   26.19 +          + "return r(name, byteCode).constructor.$class;"
   26.20      )
   26.21      private static native Class defineClass0(
   26.22          ClassLoader loader, String name, byte[] b
    27.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/NotifyWaitTest.java	Wed Apr 30 09:26:28 2014 +0200
    27.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/NotifyWaitTest.java	Tue May 06 17:46:47 2014 +0200
    27.3 @@ -28,6 +28,7 @@
    27.4   */
    27.5  public class NotifyWaitTest {
    27.6      
    27.7 +
    27.8      @Compare public synchronized String canCallNotify() throws Exception {
    27.9          notify();
   27.10          return "OK";
    28.1 --- a/rt/emul/fake/src/main/java/java/io/PrintWriter.java	Wed Apr 30 09:26:28 2014 +0200
    28.2 +++ b/rt/emul/fake/src/main/java/java/io/PrintWriter.java	Tue May 06 17:46:47 2014 +0200
    28.3 @@ -21,6 +21,6 @@
    28.4   * @author Jaroslav Tulach
    28.5   */
    28.6  public abstract class PrintWriter {
    28.7 -    public abstract PrintWriter append(String s);
    28.8 +    public abstract PrintWriter append(CharSequence s);
    28.9      public abstract void println(String s);
   28.10  }
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/rt/emul/mini/src/main/java/java/io/package-info.java	Tue May 06 17:46:47 2014 +0200
    29.3 @@ -0,0 +1,21 @@
    29.4 +/**
    29.5 + * Back 2 Browser Bytecode Translator
    29.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    29.7 + *
    29.8 + * This program is free software: you can redistribute it and/or modify
    29.9 + * it under the terms of the GNU General Public License as published by
   29.10 + * the Free Software Foundation, version 2 of the License.
   29.11 + *
   29.12 + * This program is distributed in the hope that it will be useful,
   29.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   29.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   29.15 + * GNU General Public License for more details.
   29.16 + *
   29.17 + * You should have received a copy of the GNU General Public License
   29.18 + * along with this program. Look for COPYING file in the top folder.
   29.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   29.20 + */
   29.21 +@Exported
   29.22 +package java.io;
   29.23 +
   29.24 +import org.apidesign.bck2brwsr.core.Exported;
    30.1 --- a/rt/emul/mini/src/main/java/java/lang/Class.java	Wed Apr 30 09:26:28 2014 +0200
    30.2 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java	Tue May 06 17:46:47 2014 +0200
    30.3 @@ -35,6 +35,7 @@
    30.4  import java.lang.reflect.TypeVariable;
    30.5  import java.net.URL;
    30.6  import org.apidesign.bck2brwsr.core.JavaScriptBody;
    30.7 +import org.apidesign.bck2brwsr.core.JavaScriptOnly;
    30.8  import org.apidesign.bck2brwsr.emul.reflect.AnnotationImpl;
    30.9  import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
   30.10  
   30.11 @@ -150,7 +151,7 @@
   30.12      public static Class<?> forName(String className)
   30.13      throws ClassNotFoundException {
   30.14          if (className.startsWith("[")) {
   30.15 -            Class<?> arrType = defineArray(className);
   30.16 +            Class<?> arrType = defineArray(className, null);
   30.17              Class<?> c = arrType;
   30.18              while (c != null && c.isArray()) {
   30.19                  c = c.getComponentType0(); // verify component type is sane
   30.20 @@ -1543,13 +1544,24 @@
   30.21      public Class<?> getComponentType() {
   30.22          if (isArray()) {
   30.23              try {
   30.24 -                return getComponentType0();
   30.25 +                Class<?> c = getComponentTypeByFnc();
   30.26 +                return c != null ? c : getComponentType0();
   30.27              } catch (ClassNotFoundException cnfe) {
   30.28                  throw new IllegalStateException(cnfe);
   30.29              }
   30.30          }
   30.31          return null;
   30.32      }
   30.33 +    
   30.34 +    @JavaScriptBody(args = {  }, body = 
   30.35 +        "if (this.fnc) {\n"
   30.36 +      + "  var c = this.fnc(false).constructor.$class;\n"
   30.37 +//      + "  java.lang.System.out.println('will call: ' + (!!this.fnc) + ' res: ' + c.jvmName);\n"
   30.38 +      + "  if (c) return c;\n"
   30.39 +      + "}\n"
   30.40 +      + "return null;"
   30.41 +    )
   30.42 +    private native Class<?> getComponentTypeByFnc();
   30.43  
   30.44      private Class<?> getComponentType0() throws ClassNotFoundException {
   30.45          String n = getName().substring(1);
   30.46 @@ -1576,24 +1588,26 @@
   30.47              case 'C':
   30.48                  return Character.TYPE;
   30.49              case '[':
   30.50 -                return defineArray(n);
   30.51 +                return defineArray(n, null);
   30.52              default:
   30.53                  throw new ClassNotFoundException("Unknown component type of " + getName());
   30.54          }
   30.55      }
   30.56      
   30.57 -    @JavaScriptBody(args = { "sig" }, body = 
   30.58 +    @JavaScriptBody(args = { "sig", "fnc" }, body = 
   30.59          "if (!sig) sig = '[Ljava/lang/Object;';\n" +
   30.60          "var c = Array[sig];\n" +
   30.61 -        "if (c) return c;\n" +
   30.62 -        "c = vm.java_lang_Class(true);\n" +
   30.63 -        "c.jvmName = sig;\n" +
   30.64 -        "c.superclass = vm.java_lang_Object(false).$class;\n" +
   30.65 -        "c.array = true;\n" +
   30.66 -        "Array[sig] = c;\n" +
   30.67 +        "if (!c) {\n" +
   30.68 +        "  c = vm.java_lang_Class(true);\n" +
   30.69 +        "  c.jvmName = sig;\n" +
   30.70 +        "  c.superclass = vm.java_lang_Object(false).$class;\n" +
   30.71 +        "  c.array = true;\n" +
   30.72 +        "  Array[sig] = c;\n" +
   30.73 +        "}\n" +
   30.74 +        "if (!c.fnc) c.fnc = fnc;\n" +
   30.75          "return c;"
   30.76      )
   30.77 -    private static native Class<?> defineArray(String sig);
   30.78 +    private static native Class<?> defineArray(String sig, Object fnc);
   30.79      
   30.80      /**
   30.81       * Returns true if and only if this class was declared as an enum in the
   30.82 @@ -1725,7 +1739,7 @@
   30.83      native static Class getPrimitiveClass(String type);
   30.84  
   30.85      @JavaScriptBody(args = {}, body = 
   30.86 -        "return vm.desiredAssertionStatus ? vm.desiredAssertionStatus : false;"
   30.87 +        "return this.desiredAssertionStatus ? this.desiredAssertionStatus : false;"
   30.88      )
   30.89      public native boolean desiredAssertionStatus();
   30.90      
   30.91 @@ -1760,7 +1774,7 @@
   30.92      static native int defaultHashCode(Object self);
   30.93  
   30.94      @JavaScriptBody(args = "self", body
   30.95 -            = "\nif (!self.$instOf_java_lang_Cloneable) {"
   30.96 +            = "\nif (!self['$instOf_java_lang_Cloneable']) {"
   30.97              + "\n  return null;"
   30.98              + "\n} else {"
   30.99              + "\n  var clone = self.constructor(true);"
  30.100 @@ -1773,5 +1787,39 @@
  30.101              + "\n}"
  30.102      )
  30.103      static native Object clone(Object self) throws CloneNotSupportedException;
  30.104 +
  30.105 +    @JavaScriptOnly(name = "toJS", value = "function(v) {\n"
  30.106 +        + "  if (v === null) return null;\n"
  30.107 +        + "  if (Object.prototype.toString.call(v) === '[object Array]') {\n"
  30.108 +        + "    return vm.org_apidesign_bck2brwsr_emul_lang_System(false).convArray__Ljava_lang_Object_2Ljava_lang_Object_2(v);\n"
  30.109 +        + "  }\n"
  30.110 +        + "  return v.valueOf();\n"
  30.111 +        + "}\n"
  30.112 +    )
  30.113 +    static native int toJS();
  30.114 +
  30.115 +    @JavaScriptOnly(name = "activate__Ljava_io_Closeable_2Lorg_apidesign_html_boot_spi_Fn$Presenter_2", value = "function() {\n"
  30.116 +        + "  return vm.org_apidesign_bck2brwsr_emul_lang_System(false).activate__Ljava_io_Closeable_2();"
  30.117 +        + "}\n"
  30.118 +    )
  30.119 +    static native int activate();
  30.120 +    
  30.121 +    private static Object bck2BrwsrCnvrt(Object o) {
  30.122 +        if (o instanceof Throwable) {
  30.123 +            return o;
  30.124 +        }
  30.125 +        final String msg = msg(o);
  30.126 +        if (msg == null || msg.startsWith("TypeError")) {
  30.127 +            return new NullPointerException(msg);
  30.128 +        }
  30.129 +        return new Throwable(msg);
  30.130 +    }
  30.131 +
  30.132 +    @JavaScriptBody(args = {"o"}, body = "return o ? o.toString() : null;")
  30.133 +    private static native String msg(Object o);
  30.134 +
  30.135 +    @JavaScriptOnly(name = "bck2BrwsrThrwrbl", value = "c.bck2BrwsrCnvrt__Ljava_lang_Object_2Ljava_lang_Object_2")
  30.136 +    private static void bck2BrwsrCnvrtVM() {
  30.137 +    }
  30.138      
  30.139  }
    31.1 --- a/rt/emul/mini/src/main/java/java/lang/ClassLoader.java	Wed Apr 30 09:26:28 2014 +0200
    31.2 +++ b/rt/emul/mini/src/main/java/java/lang/ClassLoader.java	Tue May 06 17:46:47 2014 +0200
    31.3 @@ -588,6 +588,9 @@
    31.4       * @since  1.2
    31.5       */
    31.6      public Enumeration<URL> getResources(String name) throws IOException {
    31.7 +        if (this == SYSTEM) {
    31.8 +            return findResources(name);
    31.9 +        }
   31.10          Enumeration[] tmp = new Enumeration[2];
   31.11          if (parent != null) {
   31.12              tmp[0] = parent.getResources(name);
    32.1 --- a/rt/emul/mini/src/main/java/java/lang/String.java	Wed Apr 30 09:26:28 2014 +0200
    32.2 +++ b/rt/emul/mini/src/main/java/java/lang/String.java	Tue May 06 17:46:47 2014 +0200
    32.3 @@ -1016,7 +1016,7 @@
    32.4       * @see  #equalsIgnoreCase(String)
    32.5       */
    32.6      @JavaScriptBody(args = { "obj" }, body = 
    32.7 -        "return obj != null && obj.$instOf_java_lang_String && "
    32.8 +        "return obj != null && obj['$instOf_java_lang_String'] && "
    32.9          + "this.toString() === obj.toString();"
   32.10      )
   32.11      public boolean equals(Object anObject) {
    33.1 --- a/rt/emul/mini/src/main/java/java/lang/Throwable.java	Wed Apr 30 09:26:28 2014 +0200
    33.2 +++ b/rt/emul/mini/src/main/java/java/lang/Throwable.java	Tue May 06 17:46:47 2014 +0200
    33.3 @@ -1025,22 +1025,4 @@
    33.4  //        else
    33.5  //            return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
    33.6      }
    33.7 -    
    33.8 -    private static Object bck2BrwsrCnvrt(Object o) {
    33.9 -        if (o instanceof Throwable) {
   33.10 -            return o;
   33.11 -        }
   33.12 -        final String msg = msg(o);
   33.13 -        if (msg == null || msg.startsWith("TypeError")) {
   33.14 -            return new NullPointerException(msg);
   33.15 -        }
   33.16 -        return new Throwable(msg);
   33.17 -    }
   33.18 -    
   33.19 -    @JavaScriptBody(args = { "o" }, body = "return o ? o.toString() : null;")
   33.20 -    private static native String msg(Object o);
   33.21 -
   33.22 -    @JavaScriptOnly(name = "bck2BrwsrCnvrt", value = "c.bck2BrwsrCnvrt__Ljava_lang_Object_2Ljava_lang_Object_2")
   33.23 -    private static void bck2BrwsrCnvrtVM() {
   33.24 -    }
   33.25  }
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/rt/emul/mini/src/main/java/java/lang/annotation/package-info.java	Tue May 06 17:46:47 2014 +0200
    34.3 @@ -0,0 +1,21 @@
    34.4 +/**
    34.5 + * Back 2 Browser Bytecode Translator
    34.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    34.7 + *
    34.8 + * This program is free software: you can redistribute it and/or modify
    34.9 + * it under the terms of the GNU General Public License as published by
   34.10 + * the Free Software Foundation, version 2 of the License.
   34.11 + *
   34.12 + * This program is distributed in the hope that it will be useful,
   34.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   34.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   34.15 + * GNU General Public License for more details.
   34.16 + *
   34.17 + * You should have received a copy of the GNU General Public License
   34.18 + * along with this program. Look for COPYING file in the top folder.
   34.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   34.20 + */
   34.21 +@Exported
   34.22 +package java.lang.annotation;
   34.23 +
   34.24 +import org.apidesign.bck2brwsr.core.Exported;
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/rt/emul/mini/src/main/java/java/lang/package-info.java	Tue May 06 17:46:47 2014 +0200
    35.3 @@ -0,0 +1,21 @@
    35.4 +/**
    35.5 + * Back 2 Browser Bytecode Translator
    35.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    35.7 + *
    35.8 + * This program is free software: you can redistribute it and/or modify
    35.9 + * it under the terms of the GNU General Public License as published by
   35.10 + * the Free Software Foundation, version 2 of the License.
   35.11 + *
   35.12 + * This program is distributed in the hope that it will be useful,
   35.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   35.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   35.15 + * GNU General Public License for more details.
   35.16 + *
   35.17 + * You should have received a copy of the GNU General Public License
   35.18 + * along with this program. Look for COPYING file in the top folder.
   35.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   35.20 + */
   35.21 +@Exported
   35.22 +package java.lang;
   35.23 +
   35.24 +import org.apidesign.bck2brwsr.core.Exported;
    36.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Array.java	Wed Apr 30 09:26:28 2014 +0200
    36.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Array.java	Tue May 06 17:46:47 2014 +0200
    36.3 @@ -25,6 +25,7 @@
    36.4  
    36.5  package java.lang.reflect;
    36.6  
    36.7 +import org.apidesign.bck2brwsr.core.Exported;
    36.8  import org.apidesign.bck2brwsr.core.JavaScriptBody;
    36.9  import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
   36.10  
   36.11 @@ -75,7 +76,7 @@
   36.12              throw new NegativeArraySizeException();
   36.13          }
   36.14          String sig = findSignature(componentType);
   36.15 -        return newArray(componentType.isPrimitive(), sig, length);
   36.16 +        return newArray(componentType.isPrimitive(), sig, null, length);
   36.17      }
   36.18      
   36.19      private static String findSignature(Class<?> type) {
   36.20 @@ -629,25 +630,67 @@
   36.21       * Private
   36.22       */
   36.23  
   36.24 -    @JavaScriptBody(args = { "primitive", "sig", "length" }, body =
   36.25 +    @JavaScriptBody(args = { "primitive", "sig", "fn", "length" }, body =
   36.26            "var arr = new Array(length);\n"
   36.27          + "var value = primitive ? 0 : null;\n"
   36.28          + "for(var i = 0; i < length; i++) arr[i] = value;\n"
   36.29          + "arr.jvmName = sig;\n"
   36.30 +        + "arr.fnc = fn;\n"
   36.31 +//        + "java.lang.System.out.println('Assigned ' + arr.jvmName + ' fn: ' + (!!arr.fnc));\n"
   36.32          + "return arr;"
   36.33      )
   36.34 -    static native Object newArray(boolean primitive, String sig, int length);
   36.35 +    @Exported
   36.36 +    private static native Object newArray(boolean primitive, String sig, Object fn, int length);
   36.37  
   36.38 -    static Object multiNewArray(String sig, int[] dims, int index)
   36.39 +    @Exported
   36.40 +    private static boolean isInstance(Object arr, String sig)  {
   36.41 +        if (arr == null) {
   36.42 +            return false;
   36.43 +        }
   36.44 +        return sig.equals(arr.getClass().getName());
   36.45 +    }
   36.46 +    
   36.47 +    @Exported
   36.48 +    private static boolean isInstance(Object arr, int dimensions, Object fn) throws ClassNotFoundException {
   36.49 +        if (arr == null) {
   36.50 +            return false;
   36.51 +        }
   36.52 +//        log("isInstance for " + arr + " and " + dimensions);
   36.53 +        Class<?> c = arr.getClass();
   36.54 +        while (dimensions-- > 0) {
   36.55 +//            log(" class: " + c);
   36.56 +            c = c.getComponentType();
   36.57 +//            log(" next class: " + c);
   36.58 +            if (c == null) {
   36.59 +                return false;
   36.60 +            }
   36.61 +        }
   36.62 +        Class<?> t = classFromFn(fn);
   36.63 +//        log(" to check: " + t);
   36.64 +        return t.isAssignableFrom(c);
   36.65 +    }
   36.66 +    
   36.67 +    @JavaScriptBody(args = { "cntstr" }, body = "return cntstr(false).constructor.$class;")
   36.68 +    private static native Class<?> classFromFn(Object cntstr);
   36.69 +
   36.70 +//    @JavaScriptBody(args = { "m" }, body = "java.lang.System.out.println(m.toString().toString());")
   36.71 +//    private static native void log(Object m);
   36.72 +    
   36.73 +    @Exported
   36.74 +    private static Object multiNewArray(String sig, int[] dims, Object fn)
   36.75 +    throws IllegalArgumentException, NegativeArraySizeException {
   36.76 +        return multiNewArray(sig, dims, 0, fn);
   36.77 +    }
   36.78 +    private static Object multiNewArray(String sig, int[] dims, int index, Object fn)
   36.79      throws IllegalArgumentException, NegativeArraySizeException {
   36.80          if (dims.length == index + 1) {
   36.81 -            return newArray(sig.length() == 2, sig, dims[index]);
   36.82 +            return newArray(sig.length() == 2, sig, fn, dims[index]);
   36.83          }
   36.84 -        Object arr = newArray(false, sig, dims[index]);
   36.85 +        Object arr = newArray(false, sig, null, dims[index]);
   36.86          String compsig = sig.substring(1);
   36.87          int len = getLength(arr);
   36.88          for (int i = 0; i < len; i++) {
   36.89 -            setArray(arr, i, multiNewArray(compsig, dims, index + 1));
   36.90 +            setArray(arr, i, multiNewArray(compsig, dims, index + 1, fn));
   36.91          }
   36.92          return arr;
   36.93      }
    37.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/package-info.java	Wed Apr 30 09:26:28 2014 +0200
    37.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/package-info.java	Tue May 06 17:46:47 2014 +0200
    37.3 @@ -46,4 +46,7 @@
    37.4   *
    37.5   * @since JDK1.1
    37.6   */
    37.7 +@Exported
    37.8  package java.lang.reflect;
    37.9 +
   37.10 +import org.apidesign.bck2brwsr.core.Exported;
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/rt/emul/mini/src/main/java/java/net/package-info.java	Tue May 06 17:46:47 2014 +0200
    38.3 @@ -0,0 +1,21 @@
    38.4 +/**
    38.5 + * Back 2 Browser Bytecode Translator
    38.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    38.7 + *
    38.8 + * This program is free software: you can redistribute it and/or modify
    38.9 + * it under the terms of the GNU General Public License as published by
   38.10 + * the Free Software Foundation, version 2 of the License.
   38.11 + *
   38.12 + * This program is distributed in the hope that it will be useful,
   38.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   38.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   38.15 + * GNU General Public License for more details.
   38.16 + *
   38.17 + * You should have received a copy of the GNU General Public License
   38.18 + * along with this program. Look for COPYING file in the top folder.
   38.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   38.20 + */
   38.21 +@Exported
   38.22 +package java.net;
   38.23 +
   38.24 +import org.apidesign.bck2brwsr.core.Exported;
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/rt/emul/mini/src/main/java/java/util/package-info.java	Tue May 06 17:46:47 2014 +0200
    39.3 @@ -0,0 +1,21 @@
    39.4 +/**
    39.5 + * Back 2 Browser Bytecode Translator
    39.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    39.7 + *
    39.8 + * This program is free software: you can redistribute it and/or modify
    39.9 + * it under the terms of the GNU General Public License as published by
   39.10 + * the Free Software Foundation, version 2 of the License.
   39.11 + *
   39.12 + * This program is distributed in the hope that it will be useful,
   39.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   39.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   39.15 + * GNU General Public License for more details.
   39.16 + *
   39.17 + * You should have received a copy of the GNU General Public License
   39.18 + * along with this program. Look for COPYING file in the top folder.
   39.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   39.20 + */
   39.21 +@Exported
   39.22 +package java.util;
   39.23 +
   39.24 +import org.apidesign.bck2brwsr.core.Exported;
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/rt/emul/mini/src/main/java/java/util/zip/package-info.java	Tue May 06 17:46:47 2014 +0200
    40.3 @@ -0,0 +1,21 @@
    40.4 +/**
    40.5 + * Back 2 Browser Bytecode Translator
    40.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    40.7 + *
    40.8 + * This program is free software: you can redistribute it and/or modify
    40.9 + * it under the terms of the GNU General Public License as published by
   40.10 + * the Free Software Foundation, version 2 of the License.
   40.11 + *
   40.12 + * This program is distributed in the hope that it will be useful,
   40.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   40.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   40.15 + * GNU General Public License for more details.
   40.16 + *
   40.17 + * You should have received a copy of the GNU General Public License
   40.18 + * along with this program. Look for COPYING file in the top folder.
   40.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   40.20 + */
   40.21 +@Exported
   40.22 +package java.util.zip;
   40.23 +
   40.24 +import org.apidesign.bck2brwsr.core.Exported;
    41.1 --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java	Wed Apr 30 09:26:28 2014 +0200
    41.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java	Tue May 06 17:46:47 2014 +0200
    41.3 @@ -17,9 +17,10 @@
    41.4   */
    41.5  package org.apidesign.bck2brwsr.emul.lang;
    41.6  
    41.7 +import java.io.Closeable;
    41.8 +import java.io.IOException;
    41.9  import java.lang.reflect.Method;
   41.10  import org.apidesign.bck2brwsr.core.JavaScriptBody;
   41.11 -import org.apidesign.bck2brwsr.core.JavaScriptOnly;
   41.12  
   41.13  /**
   41.14   *
   41.15 @@ -73,15 +74,15 @@
   41.16      @JavaScriptBody(args = { "obj" }, body="return vm.java_lang_Object(false).hashCode__I.call(obj);")
   41.17      public static native int identityHashCode(Object obj);
   41.18      
   41.19 -    @JavaScriptOnly(name = "toJS", value = "function(v) {\n" + 
   41.20 -        "  if (v === null) return null;\n" +
   41.21 -        "  if (Object.prototype.toString.call(v) === '[object Array]') {\n" +
   41.22 -        "    return vm.org_apidesign_bck2brwsr_emul_lang_System(false).convArray__Ljava_lang_Object_2Ljava_lang_Object_2(v);\n" +
   41.23 -        "  }\n" +
   41.24 -        "  return v.valueOf();\n" +
   41.25 -        "}\n"
   41.26 -    )
   41.27 -    public static native int toJS();
   41.28 +    public static Closeable activate() {
   41.29 +        return DUMMY;
   41.30 +    }
   41.31 +    private static final Closeable DUMMY = new Closeable() {
   41.32 +        @Override
   41.33 +        public void close() throws IOException {
   41.34 +        }
   41.35 +    };
   41.36 +    
   41.37      
   41.38      private static Object convArray(Object o) {
   41.39          if (o instanceof Object[]) {
    42.1 --- a/rt/emul/mini/src/main/java/org/apidesign/vm4brwsr/api/VM.java	Wed Apr 30 09:26:28 2014 +0200
    42.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/vm4brwsr/api/VM.java	Tue May 06 17:46:47 2014 +0200
    42.3 @@ -40,7 +40,11 @@
    42.4          reloadImpl(clazz.getName(), byteCode);
    42.5      }
    42.6      
    42.7 -    @JavaScriptBody(args = { "name", "byteCode" }, body = "vm._reload(name, byteCode);")
    42.8 +    @JavaScriptBody(args = { "name", "byteCode" }, body = 
    42.9 +        "var r = vm._reload;"
   42.10 +      + "if (!r) r = exports._reload;"
   42.11 +      + "r(name, byteCode);"
   42.12 +    )
   42.13      private static void reloadImpl(String name, byte[] byteCode) throws IOException {
   42.14          throw new IOException();
   42.15      }
    43.1 --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_String.js	Wed Apr 30 09:26:28 2014 +0200
    43.2 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_String.js	Tue May 06 17:46:47 2014 +0200
    43.3 @@ -14,7 +14,7 @@
    43.4    return arr[indx];
    43.5  };
    43.6  Array.prototype.getClass__Ljava_lang_Class_2 = function() {
    43.7 -  return vm.java_lang_Class(false).defineArray__Ljava_lang_Class_2Ljava_lang_String_2(this.jvmName);
    43.8 +  return vm.java_lang_Class(false).defineArray__Ljava_lang_Class_2Ljava_lang_String_2Ljava_lang_Object_2(this.jvmName, this.fnc);
    43.9  };
   43.10  Array.prototype.clone__Ljava_lang_Object_2 = function() {
   43.11    var s = this.length;
   43.12 @@ -23,5 +23,6 @@
   43.13        ret[i] = this[i];
   43.14    }
   43.15    ret.jvmName = this.jvmName;
   43.16 +  ret.fnc = this.fnc;
   43.17    return ret;
   43.18  };
    44.1 --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java	Wed Apr 30 09:26:28 2014 +0200
    44.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java	Tue May 06 17:46:47 2014 +0200
    44.3 @@ -75,6 +75,15 @@
    44.4      @Parameter(defaultValue = "false")
    44.5      private boolean ignoreBootClassPath;
    44.6  
    44.7 +    /**
    44.8 +     * Indicates whether to create an extension library 
    44.9 +     * module instead of a standalone JavaScript VM.
   44.10 +     *
   44.11 +     * @since 0.9
   44.12 +     */
   44.13 +    @Parameter(defaultValue="false")
   44.14 +    private boolean library;
   44.15 +
   44.16      @Override
   44.17      public void execute() throws MojoExecutionException {
   44.18          if (!classes.isDirectory()) {
   44.19 @@ -101,6 +110,7 @@
   44.20              FileWriter w = new FileWriter(javascript);
   44.21              Bck2Brwsr.newCompiler().
   44.22                  obfuscation(obfuscation).
   44.23 +                library(library).
   44.24                  resources(url, ignoreBootClassPath).
   44.25                  addRootClasses(arr.toArray(new String[0])).
   44.26                  generate(w);
   44.27 @@ -123,7 +133,9 @@
   44.28              return newest;
   44.29          } else if (toCheck.getName().endsWith(".class")) {
   44.30              final String cls = prefix.substring(0, prefix.length() - 7);
   44.31 -            arr.add(cls);
   44.32 +            if (!cls.endsWith("package-info")) {
   44.33 +                arr.add(cls);
   44.34 +            }
   44.35              return toCheck.lastModified();
   44.36          } else {
   44.37              return 0L;
    45.1 --- a/rt/vm/pom.xml	Wed Apr 30 09:26:28 2014 +0200
    45.2 +++ b/rt/vm/pom.xml	Tue May 06 17:46:47 2014 +0200
    45.3 @@ -159,5 +159,11 @@
    45.4        <scope>test</scope>
    45.5        <version>${net.java.html.version}</version>
    45.6      </dependency>
    45.7 +    <dependency>
    45.8 +      <groupId>${project.groupId}</groupId>
    45.9 +      <artifactId>fake</artifactId>
   45.10 +      <version>${project.version}</version>
   45.11 +      <scope>test</scope>
   45.12 +    </dependency>
   45.13    </dependencies>
   45.14  </project>
    46.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Wed Apr 30 09:26:28 2014 +0200
    46.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Tue May 06 17:46:47 2014 +0200
    46.3 @@ -19,6 +19,7 @@
    46.4  
    46.5  import java.io.IOException;
    46.6  import java.io.InputStream;
    46.7 +import org.apidesign.bck2brwsr.core.Exported;
    46.8  
    46.9  /** Build your own virtual machine! Use methods in this class to generate
   46.10   * a skeleton JVM in JavaScript that contains pre-compiled classes of your
   46.11 @@ -53,13 +54,19 @@
   46.12   */
   46.13  public final class Bck2Brwsr {
   46.14      private final ObfuscationLevel level;
   46.15 +    private final StringArray rootcls;
   46.16      private final StringArray classes;
   46.17 +    private final StringArray resources;
   46.18      private final Resources res;
   46.19 +    private final boolean extension;
   46.20  
   46.21 -    private Bck2Brwsr(ObfuscationLevel level, StringArray classes, Resources resources) {
   46.22 +    private Bck2Brwsr(ObfuscationLevel level, StringArray rootcls, StringArray classes, StringArray resources, Resources res, boolean extension) {
   46.23          this.level = level;
   46.24 +        this.rootcls = rootcls;
   46.25          this.classes = classes;
   46.26 -        this.res = resources;
   46.27 +        this.resources = resources;
   46.28 +        this.res = res;
   46.29 +        this.extension = extension;
   46.30      }
   46.31      
   46.32      /** Helper method to generate virtual machine from bytes served by a <code>resources</code>
   46.33 @@ -96,23 +103,69 @@
   46.34       * @since 0.5
   46.35       */
   46.36      public static Bck2Brwsr newCompiler() {
   46.37 -        StringArray arr = StringArray.asList(VM.class.getName().replace('.', '/'));
   46.38 -        return new Bck2Brwsr(ObfuscationLevel.NONE, arr, null);
   46.39 +        return new Bck2Brwsr(ObfuscationLevel.NONE, new StringArray(), new StringArray(), new StringArray(), null, false);
   46.40      }
   46.41  
   46.42 -    /** Creates new instance of the Bck2Brwsr compiler which inherits
   46.43 -     * all values from <code>this</code> instance and adds additional classes 
   46.44 -     * to the list of those that should be compiled by the {@link #generate(java.lang.Appendable)} 
   46.45 -     * method.
   46.46 +    /** Adds additional classes 
   46.47 +     * to the list of those that should be included in the generated
   46.48 +     * JavaScript file.
   46.49 +     * These classes are guaranteed to be available in the
   46.50 +     * generated virtual machine code accessible using their fully 
   46.51 +     * qualified name. This brings the same behavior as if the
   46.52 +     * classes were added by {@link #addClasses(java.lang.String...) } and
   46.53 +     * were annotated with {@link Exported} annotation.
   46.54       * 
   46.55       * @param classes the classes to add to the compilation
   46.56 -     * @return new instance of the compiler
   46.57 +     * @return new instance of the Bck2Brwsr compiler which inherits
   46.58 +     * all values from <code>this</code>
   46.59       */
   46.60      public Bck2Brwsr addRootClasses(String... classes) {
   46.61          if (classes.length == 0) {
   46.62              return this;
   46.63          } else {
   46.64 -            return new Bck2Brwsr(level, this.classes.addAndNew(classes), res);
   46.65 +            return new Bck2Brwsr(level, rootcls.addAndNew(classes), this.classes, resources, res,
   46.66 +                                 extension);
   46.67 +        }
   46.68 +    }
   46.69 +    
   46.70 +    /** Adds additional classes 
   46.71 +     * to the list of those that should be included in the generated
   46.72 +     * JavaScript file. These classes are guaranteed to be present,
   46.73 +     * but they may not be accessible through their fully qualified
   46.74 +     * name.
   46.75 +     * 
   46.76 +     * @param classes the classes to add to the compilation
   46.77 +     * @return new instance of the Bck2Brwsr compiler which inherits
   46.78 +     * all values from <code>this</code>
   46.79 +     * @since 0.9
   46.80 +     */
   46.81 +    public Bck2Brwsr addClasses(String... classes) {
   46.82 +        if (classes.length == 0) {
   46.83 +            return this;
   46.84 +        } else {
   46.85 +            return new Bck2Brwsr(level, rootcls, this.classes.addAndNew(classes), resources, res,
   46.86 +                extension);
   46.87 +        }
   46.88 +    }
   46.89 +    
   46.90 +    /** These resources should be made available in the compiled file in
   46.91 +     * binary form. These resources can then be loaded
   46.92 +     * by {@link ClassLoader#getResource(java.lang.String)} and similar 
   46.93 +     * methods.
   46.94 +     * 
   46.95 +     * @param resources names of the resources to be loaded by {@link Resources#get(java.lang.String)}
   46.96 +     * @return new instance of the Bck2Brwsr compiler which inherits
   46.97 +     *   all values from <code>this</code> just adds few more resource names
   46.98 +     *   for processing
   46.99 +     * @since 0.9
  46.100 +     */
  46.101 +    public Bck2Brwsr addResources(String... resources) {
  46.102 +        if (resources.length == 0) {
  46.103 +            return this;
  46.104 +        } else {
  46.105 +            return new Bck2Brwsr(level, rootcls, this.classes, 
  46.106 +                this.resources.addAndNew(resources), res, extension
  46.107 +            );
  46.108          }
  46.109      }
  46.110      
  46.111 @@ -125,7 +178,7 @@
  46.112       * @since 0.5
  46.113       */
  46.114      public Bck2Brwsr obfuscation(ObfuscationLevel level) {
  46.115 -        return new Bck2Brwsr(level, classes, res);
  46.116 +        return new Bck2Brwsr(level, rootcls, classes, resources, res, extension);
  46.117      }
  46.118      
  46.119      /** A way to change the provider of additional resources (classes) for the 
  46.120 @@ -137,7 +190,22 @@
  46.121       * @since 0.5
  46.122       */
  46.123      public Bck2Brwsr resources(Resources res) {
  46.124 -        return new Bck2Brwsr(level, classes, res);
  46.125 +        return new Bck2Brwsr(level, rootcls, classes, resources, res, extension);
  46.126 +    }
  46.127 +
  46.128 +    /** Should one generate a library? By default the system generates
  46.129 +     * all transitive classes needed by the the transitive closure of
  46.130 +     * {@link #addRootClasses(java.lang.String...)} and {@link #addClasses(java.lang.String...)}.
  46.131 +     * By turning on the library mode, only classes explicitly listed
  46.132 +     * will be included in the archive. The others will be referenced
  46.133 +     * as external ones.
  46.134 +     * 
  46.135 +     * @param library turn on the library mode?
  46.136 +     * @return new instance of the compiler with library flag changed
  46.137 +     * @since 0.9
  46.138 +     */
  46.139 +    public Bck2Brwsr library(boolean library) {
  46.140 +        return new Bck2Brwsr(level, rootcls, classes, resources, res, library);
  46.141      }
  46.142  
  46.143      /** A way to change the provider of additional resources (classes) for the 
  46.144 @@ -173,10 +241,9 @@
  46.145       * @since 0.5
  46.146       */
  46.147      public void generate(Appendable out) throws IOException {
  46.148 -        Resources r = res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader(), false);
  46.149          if (level != ObfuscationLevel.NONE) {
  46.150              try {
  46.151 -                ClosureWrapper.produceTo(out, level, r, classes);
  46.152 +                ClosureWrapper.produceTo(out, level, this);
  46.153                  return;
  46.154              } catch (IOException ex) {
  46.155                  throw ex;
  46.156 @@ -186,9 +253,33 @@
  46.157              }
  46.158          }
  46.159  
  46.160 -        VM.compile(r, out, classes);
  46.161 +        VM.compile(out, this);
  46.162      }
  46.163      
  46.164 +    //
  46.165 +    // Internal getters
  46.166 +    // 
  46.167 +    
  46.168 +    Resources getResources() {
  46.169 +        return res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader(), false);
  46.170 +    }
  46.171 +    
  46.172 +    String[] allClasses() {
  46.173 +        return classes.addAndNew(rootcls.toArray()).toArray();
  46.174 +    }
  46.175 +    StringArray allResources() {
  46.176 +        return resources;
  46.177 +    }
  46.178 +
  46.179 +    
  46.180 +    StringArray rootClasses() {
  46.181 +        return rootcls;
  46.182 +    }
  46.183 +    
  46.184 +    boolean isExtension() {
  46.185 +        return extension;
  46.186 +    }
  46.187 +
  46.188      /** Provider of resources (classes and other files). The 
  46.189       * {@link #generate(java.lang.Appendable, org.apidesign.vm4brwsr.Bck2Brwsr.Resources, java.lang.String[]) 
  46.190       * generator method} will call back here for all classes needed during
    47.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java	Wed Apr 30 09:26:28 2014 +0200
    47.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java	Tue May 06 17:46:47 2014 +0200
    47.3 @@ -1186,7 +1186,7 @@
    47.4              pkgPrefixLen = classname.lastIndexOf("/") + 1;
    47.5              if (pkgPrefixLen != 0) {
    47.6                  pkgPrefix = classname.substring(0, pkgPrefixLen);
    47.7 -                return ("package  " + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";\n");
    47.8 +                return /* ("package  " + */ pkgPrefix.substring(0, pkgPrefixLen - 1) /* + ";\n") */;
    47.9              } else {
   47.10                  return null;
   47.11              }
   47.12 @@ -1239,6 +1239,30 @@
   47.13              return getNameAndType(c2.cpx2, 1, arr);
   47.14          }
   47.15  
   47.16 +        public MethodData findMethod(String name, String signature) {
   47.17 +            for (MethodData md: methods) {
   47.18 +                if (md.getName().equals(name)
   47.19 +                        && md.getInternalSig().equals(signature)) {
   47.20 +                    return md;
   47.21 +                }
   47.22 +            }
   47.23 +
   47.24 +            // not found
   47.25 +            return null;
   47.26 +        }
   47.27 +
   47.28 +        public FieldData findField(String name, String signature) {
   47.29 +            for (FieldData fd: fields) {
   47.30 +                if (fd.getName().equals(name)
   47.31 +                        && fd.getInternalSig().equals(signature)) {
   47.32 +                    return fd;
   47.33 +                }
   47.34 +            }
   47.35 +
   47.36 +            // not found
   47.37 +            return null;
   47.38 +        }
   47.39 +
   47.40          static byte[] findAttr(String n, AttrData[] attrs) {
   47.41              for (AttrData ad : attrs) {
   47.42                  if (n.equals(ad.getAttrName())) {
    48.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Wed Apr 30 09:26:28 2014 +0200
    48.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Tue May 06 17:46:47 2014 +0200
    48.3 @@ -29,16 +29,10 @@
    48.4      private ClassData jc;
    48.5      private final Appendable out;
    48.6      private boolean outChanged;
    48.7 -    final ObfuscationDelegate obfuscationDelegate;
    48.8 +    private boolean callbacks;
    48.9  
   48.10      protected ByteCodeToJavaScript(Appendable out) {
   48.11 -        this(out, ObfuscationDelegate.NULL);
   48.12 -    }
   48.13 -
   48.14 -    protected ByteCodeToJavaScript(
   48.15 -            Appendable out, ObfuscationDelegate obfuscationDelegate) {
   48.16          this.out = out;
   48.17 -        this.obfuscationDelegate = obfuscationDelegate;
   48.18      }
   48.19      
   48.20      @Override
   48.21 @@ -88,7 +82,38 @@
   48.22          return classOperation;
   48.23      }
   48.24  
   48.25 -    abstract String getVMObject();
   48.26 +    protected String accessField(String object, String mangledName,
   48.27 +                                 String[] fieldInfoName) throws IOException {
   48.28 +        return object + "." + mangledName;
   48.29 +    }
   48.30 +
   48.31 +    protected String accessStaticMethod(
   48.32 +                             String object,
   48.33 +                             String mangledName,
   48.34 +                             String[] fieldInfoName) throws IOException {
   48.35 +        return object + "." + mangledName;
   48.36 +    }
   48.37 +
   48.38 +    protected String accessVirtualMethod(
   48.39 +                             String object,
   48.40 +                             String mangledName,
   48.41 +                             String[] fieldInfoName) throws IOException {
   48.42 +        return object + "." + mangledName;
   48.43 +    }
   48.44 +
   48.45 +    protected void declaredClass(ClassData classData, String mangledName)
   48.46 +            throws IOException {
   48.47 +    }
   48.48 +
   48.49 +    protected void declaredField(FieldData fieldData,
   48.50 +                                 String destObject,
   48.51 +                                 String mangledName) throws IOException {
   48.52 +    }
   48.53 +
   48.54 +    protected void declaredMethod(MethodData methodData,
   48.55 +                                  String destObject,
   48.56 +                                  String mangledName) throws IOException {
   48.57 +    }
   48.58  
   48.59      /** Prints out a debug message. 
   48.60       * 
   48.61 @@ -111,7 +136,12 @@
   48.62       */
   48.63      
   48.64      public String compile(InputStream classFile) throws IOException {
   48.65 -        this.jc = new ClassData(classFile);
   48.66 +        return compile(new ClassData(classFile));
   48.67 +    }
   48.68 +
   48.69 +    protected String compile(ClassData classData) throws IOException {
   48.70 +        this.jc = classData;
   48.71 +        this.callbacks = this.jc.getClassName().endsWith("/$JsCallbacks$");
   48.72          if (jc.getMajor_version() < 50) {
   48.73              throw new IOException("Can't compile " + jc.getClassName() + ". Class file version " + jc.getMajor_version() + "."
   48.74                  + jc.getMinor_version() + " - recompile with -target 1.6 (at least)."
   48.75 @@ -194,7 +224,7 @@
   48.76                     .append("; };");
   48.77              }
   48.78  
   48.79 -            obfuscationDelegate.exportField(this, "c", "_" + v.getName(), v);
   48.80 +            declaredField(v, "c", "_" + v.getName());
   48.81          }
   48.82          for (MethodData m : jc.getMethods()) {
   48.83              byte[] onlyArr = m.findAnnotationData(true);
   48.84 @@ -224,7 +254,7 @@
   48.85                      mn = generateInstanceMethod(destObject, m);
   48.86                  }
   48.87              }
   48.88 -            obfuscationDelegate.exportMethod(this, destObject, mn, m);
   48.89 +            declaredMethod(m, destObject, mn);
   48.90              byte[] runAnno = m.findAnnotationData(false);
   48.91              if (runAnno != null) {
   48.92                  append("\n    ").append(destObject).append(".").append(mn).append(".anno = {");
   48.93 @@ -237,16 +267,16 @@
   48.94          append("\n    c.constructor = CLS;");
   48.95          append("\n    function fillInstOf(x) {");
   48.96          String instOfName = "$instOf_" + className;
   48.97 -        append("\n        x.").append(instOfName).append(" = true;");
   48.98 +        append("\n        x['").append(instOfName).append("'] = true;");
   48.99          for (String superInterface : jc.getSuperInterfaces()) {
  48.100              String intrfc = superInterface.replace('/', '_');
  48.101 -            append("\n      vm.").append(intrfc).append("(false).fillInstOf(x);");
  48.102 +            append("\n      vm.").append(intrfc).append("(false)['fillInstOf'](x);");
  48.103              requireReference(superInterface);
  48.104          }
  48.105          append("\n    }");
  48.106 -        append("\n    c.fillInstOf = fillInstOf;");
  48.107 +        append("\n    c['fillInstOf'] = fillInstOf;");
  48.108          append("\n    fillInstOf(c);");
  48.109 -        obfuscationDelegate.exportJSProperty(this, "c", instOfName);
  48.110 +//        obfuscationDelegate.exportJSProperty(this, "c", instOfName);
  48.111          append("\n    CLS.$class = 'temp';");
  48.112          append("\n    CLS.$class = ");
  48.113          append(accessClass("java_lang_Class(true);"));
  48.114 @@ -292,7 +322,7 @@
  48.115          append("\n  return arguments[0] ? new CLS() : CLS.prototype;");
  48.116          append("\n};");
  48.117  
  48.118 -        obfuscationDelegate.exportClass(this, getVMObject(), className, jc);
  48.119 +        declaredClass(jc, className);
  48.120  
  48.121  //        StringBuilder sb = new StringBuilder();
  48.122  //        for (String init : toInitilize.toArray()) {
  48.123 @@ -1251,9 +1281,10 @@
  48.124                      final int type = VarType.fromFieldType(fi[2].charAt(0));
  48.125                      final String mangleClass = mangleClassName(fi[0]);
  48.126                      final String mangleClassAccess = accessClass(mangleClass);
  48.127 -                    smapper.replace(this, type, "@3(false)._@2.call(@1)",
  48.128 +                    smapper.replace(this, type, "@2.call(@1)",
  48.129                           smapper.getA(0),
  48.130 -                         fi[1], mangleClassAccess
  48.131 +                         accessField(mangleClassAccess + "(false)",
  48.132 +                                     "_" + fi[1], fi)
  48.133                      );
  48.134                      i += 2;
  48.135                      break;
  48.136 @@ -1264,11 +1295,11 @@
  48.137                      final int type = VarType.fromFieldType(fi[2].charAt(0));
  48.138                      final String mangleClass = mangleClassName(fi[0]);
  48.139                      final String mangleClassAccess = accessClass(mangleClass);
  48.140 -                    emit(smapper, this, "@4(false)._@3.call(@2, @1);",
  48.141 +                    emit(smapper, this, "@3.call(@2, @1);",
  48.142                           smapper.popT(type),
  48.143 -                         smapper.popA(), fi[1], 
  48.144 -                         mangleClassAccess
  48.145 -                    );
  48.146 +                         smapper.popA(),
  48.147 +                         accessField(mangleClassAccess + "(false)",
  48.148 +                                     "_" + fi[1], fi));
  48.149                      i += 2;
  48.150                      break;
  48.151                  }
  48.152 @@ -1557,12 +1588,17 @@
  48.153          }
  48.154  
  48.155          final String in = mi[0];
  48.156 -        append(accessClass(mangleClassName(in)));
  48.157 -        append("(false).");
  48.158 +        String mcn;
  48.159 +        if (callbacks && in.equals("org/apidesign/html/boot/spi/Fn")) {
  48.160 +            mcn = "java_lang_Class";
  48.161 +        } else {
  48.162 +            mcn = mangleClassName(in);
  48.163 +        }
  48.164 +        String object = accessClass(mcn) + "(false)";
  48.165          if (mn.startsWith("cons_")) {
  48.166 -            append("constructor.");
  48.167 +            object += ".constructor";
  48.168          }
  48.169 -        append(mn);
  48.170 +        append(accessStaticMethod(object, mn, mi));
  48.171          if (isStatic) {
  48.172              append('(');
  48.173          } else {
  48.174 @@ -1601,8 +1637,7 @@
  48.175                 .append(" = ");
  48.176          }
  48.177  
  48.178 -        append(vars[0]).append('.');
  48.179 -        append(mn);
  48.180 +        append(accessVirtualMethod(vars[0].toString(), mn, mi));
  48.181          append('(');
  48.182          String sep = "";
  48.183          for (int j = 1; j < numArguments; ++j) {
  48.184 @@ -1640,7 +1675,7 @@
  48.185          String s = jc.stringValue(entryIndex, classRef);
  48.186          if (classRef[0] != null) {
  48.187              if (classRef[0].startsWith("[")) {
  48.188 -                s = accessClass("java_lang_Class") + "(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('" + classRef[0] + "')";
  48.189 +                s = accessClass("java_lang_Class") + "(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('" + classRef[0] + "')";
  48.190              } else {
  48.191                  addReference(classRef[0]);
  48.192                  s = accessClass(mangleClassName(s)) + "(false).constructor.$class";
  48.193 @@ -1708,7 +1743,8 @@
  48.194              append(space);
  48.195              space = outputArg(this, p.args, index);
  48.196              if (p.html4j && space.length() > 0) {
  48.197 -                toValue.append("\n  ").append(p.args[index]).append(" = vm.org_apidesign_bck2brwsr_emul_lang_System(false).toJS(").
  48.198 +                toValue.append("\n  ").append(p.args[index]).append(" = ")
  48.199 +                    .append(accessClass("java_lang_Class")).append("(false).toJS(").
  48.200                      append(p.args[index]).append(");");
  48.201              }
  48.202              index++;
  48.203 @@ -2026,8 +2062,8 @@
  48.204              if (e.catch_cpx != 0) { //not finally
  48.205                  final String classInternalName = jc.getClassName(e.catch_cpx);
  48.206                  addReference(classInternalName);
  48.207 -                append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);");
  48.208 -                append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
  48.209 +                append("e = vm.java_lang_Class(false).bck2BrwsrThrwrbl(e);");
  48.210 +                append("if (e['$instOf_" + classInternalName.replace('/', '_') + "']) {");
  48.211                  append("var stA0 = e;");
  48.212                  goTo(this, current, e.handler_pc, topMostLabel);
  48.213                  append("}\n");
  48.214 @@ -2080,19 +2116,23 @@
  48.215              case 11: jvmType = "[J"; break;
  48.216              default: throw new IllegalStateException("Array type: " + atype);
  48.217          }
  48.218 -        emit(smapper, this, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
  48.219 +        emit(smapper, this, 
  48.220 +            "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2Ljava_lang_Object_2I'](true, '@3', null, @1);",
  48.221               smapper.popI(), smapper.pushA(), jvmType);
  48.222      }
  48.223  
  48.224      private void generateANewArray(int type, final StackMapper smapper) throws IOException {
  48.225          String typeName = jc.getClassName(type);
  48.226 +        String ref = "null";
  48.227          if (typeName.startsWith("[")) {
  48.228 -            typeName = "[" + typeName;
  48.229 +            typeName = "'[" + typeName + "'";
  48.230          } else {
  48.231 -            typeName = "[L" + typeName + ";";
  48.232 +            ref = "vm." + mangleClassName(typeName);
  48.233 +            typeName = "'[L" + typeName + ";'";
  48.234          }
  48.235 -        emit(smapper, this, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
  48.236 -             smapper.popI(), smapper.pushA(), typeName);
  48.237 +        emit(smapper, this,
  48.238 +            "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2Ljava_lang_Object_2I'](false, @3, @4, @1);",
  48.239 +             smapper.popI(), smapper.pushA(), typeName, ref);
  48.240      }
  48.241  
  48.242      private int generateMultiANewArray(int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException {
  48.243 @@ -2107,8 +2147,14 @@
  48.244              dims.insert(1, smapper.popI());
  48.245          }
  48.246          dims.append(']');
  48.247 -        emit(smapper, this, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
  48.248 -             dims.toString(), smapper.pushA(), typeName);
  48.249 +        String fn = "null";
  48.250 +        if (typeName.charAt(dim) == 'L') {
  48.251 +            fn = "vm." + mangleClassName(typeName.substring(dim + 1, typeName.length() - 1));
  48.252 +        }
  48.253 +        emit(smapper, this, 
  48.254 +            "var @2 = Array.prototype['multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3ILjava_lang_Object_2']('@3', @1, @4);",
  48.255 +             dims.toString(), smapper.pushA(), typeName, fn
  48.256 +        );
  48.257          return i;
  48.258      }
  48.259  
  48.260 @@ -2160,29 +2206,56 @@
  48.261      }
  48.262  
  48.263      private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException {
  48.264 -        final String type = jc.getClassName(indx);
  48.265 +        String type = jc.getClassName(indx);
  48.266          if (!type.startsWith("[")) {
  48.267 -            emit(smapper, this, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;",
  48.268 +            emit(smapper, this, 
  48.269 +                    "var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;",
  48.270                   smapper.popA(), smapper.pushI(),
  48.271                   type.replace('/', '_'));
  48.272          } else {
  48.273 -            emit(smapper, this, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);",
  48.274 -                smapper.popA(), smapper.pushI(),
  48.275 -                type
  48.276 -            );
  48.277 +            int cnt = 0;
  48.278 +            while (type.charAt(cnt) == '[') {
  48.279 +                cnt++;
  48.280 +            }
  48.281 +            if (type.charAt(cnt) == 'L') {
  48.282 +                type = "vm." + mangleClassName(type.substring(cnt + 1, type.length() - 1));
  48.283 +                emit(smapper, this, 
  48.284 +                    "var @2 = Array.prototype['isInstance__ZLjava_lang_Object_2ILjava_lang_Object_2'](@1, @4, @3);",
  48.285 +                    smapper.popA(), smapper.pushI(),
  48.286 +                    type, "" + cnt
  48.287 +                );
  48.288 +            } else {
  48.289 +                emit(smapper, this, 
  48.290 +                    "var @2 = Array.prototype['isInstance__ZLjava_lang_Object_2Ljava_lang_String_2'](@1, '@3');",
  48.291 +                    smapper.popA(), smapper.pushI(), type
  48.292 +                );
  48.293 +            }
  48.294          }
  48.295      }
  48.296  
  48.297      private void generateCheckcast(int indx, final StackMapper smapper) throws IOException {
  48.298 -        final String type = jc.getClassName(indx);
  48.299 +        String type = jc.getClassName(indx);
  48.300          if (!type.startsWith("[")) {
  48.301              emitNoFlush(smapper, 
  48.302 -                 "if (@1 !== null && !@1.$instOf_@2) throw vm.java_lang_ClassCastException(true);",
  48.303 +                 "if (@1 !== null && !@1['$instOf_@2']) throw vm.java_lang_ClassCastException(true);",
  48.304                   smapper.getT(0, VarType.REFERENCE, false), type.replace('/', '_'));
  48.305          } else {
  48.306 -            emitNoFlush(smapper, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);",
  48.307 -                 smapper.getT(0, VarType.REFERENCE, false), type
  48.308 -            );
  48.309 +            int cnt = 0;
  48.310 +            while (type.charAt(cnt) == '[') {
  48.311 +                cnt++;
  48.312 +            }
  48.313 +            if (type.charAt(cnt) == 'L') {
  48.314 +                type = "vm." + mangleClassName(type.substring(cnt + 1, type.length() - 1));
  48.315 +                emitNoFlush(smapper, 
  48.316 +                    "if (@1 !== null && !Array.prototype['isInstance__ZLjava_lang_Object_2ILjava_lang_Object_2'](@1, @3, @2)) throw vm.java_lang_ClassCastException(true);",
  48.317 +                     smapper.getT(0, VarType.REFERENCE, false), type, "" + cnt
  48.318 +                );
  48.319 +            } else {
  48.320 +                emitNoFlush(smapper, 
  48.321 +                    "if (@1 !== null && !Array.prototype['isInstance__ZLjava_lang_Object_2Ljava_lang_String_2'](@1, '@2')) throw vm.java_lang_ClassCastException(true);",
  48.322 +                     smapper.getT(0, VarType.REFERENCE, false), type
  48.323 +                );
  48.324 +            }
  48.325          }
  48.326      }
  48.327  
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java	Tue May 06 17:46:47 2014 +0200
    49.3 @@ -0,0 +1,213 @@
    49.4 +/**
    49.5 + * Back 2 Browser Bytecode Translator
    49.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    49.7 + *
    49.8 + * This program is free software: you can redistribute it and/or modify
    49.9 + * it under the terms of the GNU General Public License as published by
   49.10 + * the Free Software Foundation, version 2 of the License.
   49.11 + *
   49.12 + * This program is distributed in the hope that it will be useful,
   49.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   49.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   49.15 + * GNU General Public License for more details.
   49.16 + *
   49.17 + * You should have received a copy of the GNU General Public License
   49.18 + * along with this program. Look for COPYING file in the top folder.
   49.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   49.20 + */
   49.21 +package org.apidesign.vm4brwsr;
   49.22 +
   49.23 +import java.io.IOException;
   49.24 +import java.io.InputStream;
   49.25 +import java.util.HashMap;
   49.26 +import java.util.Map;
   49.27 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
   49.28 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
   49.29 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
   49.30 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
   49.31 +
   49.32 +@ExtraJavaScript(processByteCode = false, resource="")
   49.33 +final class ClassDataCache {
   49.34 +    private static final Object MISSING_CLASS = new Object();
   49.35 +
   49.36 +    private final Bck2Brwsr.Resources resources;
   49.37 +    private final Map<String, Object> classDataMap;
   49.38 +
   49.39 +    ClassDataCache(final Bck2Brwsr.Resources resources) {
   49.40 +        this.resources = resources;
   49.41 +
   49.42 +        classDataMap = new HashMap<String, Object>();
   49.43 +    }
   49.44 +
   49.45 +    ClassData getClassData(String className) throws IOException {
   49.46 +        if (className.startsWith("[")) {
   49.47 +            // required for accessVirtualMethod, shouldn't be problematic for
   49.48 +            // calls from other sources
   49.49 +            className = "java/lang/Object";
   49.50 +        }
   49.51 +        Object cacheEntry = classDataMap.get(className);
   49.52 +        if (cacheEntry == null) {
   49.53 +            final InputStream is = loadClass(resources, className);
   49.54 +            cacheEntry = (is != null) ? new ClassData(is) : MISSING_CLASS;
   49.55 +            classDataMap.put(className, cacheEntry);
   49.56 +        }
   49.57 +
   49.58 +        return (cacheEntry != MISSING_CLASS) ? (ClassData) cacheEntry : null;
   49.59 +    }
   49.60 +
   49.61 +    MethodData findMethod(final String startingClass,
   49.62 +                          final String name,
   49.63 +                          final String signature) throws IOException {
   49.64 +        return findMethod(getClassData(startingClass), name, signature);
   49.65 +    }
   49.66 +
   49.67 +    FieldData findField(final String startingClass,
   49.68 +                        final String name,
   49.69 +                        final String signature) throws IOException {
   49.70 +        return findField(getClassData(startingClass), name, signature);
   49.71 +    }
   49.72 +
   49.73 +    MethodData findMethod(final ClassData startingClass,
   49.74 +                          final String name,
   49.75 +                          final String signature) throws IOException {
   49.76 +        final FindFirstTraversalCallback<MethodData> ffTraversalCallback =
   49.77 +                new FindFirstTraversalCallback<MethodData>();
   49.78 +
   49.79 +        findMethods(startingClass, name, signature, ffTraversalCallback);
   49.80 +        return ffTraversalCallback.getFirst();
   49.81 +    }
   49.82 +
   49.83 +    FieldData findField(final ClassData startingClass,
   49.84 +                        final String name,
   49.85 +                        final String signature) throws IOException {
   49.86 +        final FindFirstTraversalCallback<FieldData> ffTraversalCallback =
   49.87 +                new FindFirstTraversalCallback<FieldData>();
   49.88 +
   49.89 +        findFields(startingClass, name, signature, ffTraversalCallback);
   49.90 +        return ffTraversalCallback.getFirst();
   49.91 +    }
   49.92 +
   49.93 +    void findMethods(final ClassData startingClass,
   49.94 +                     final String methodName,
   49.95 +                     final String methodSignature,
   49.96 +                     final TraversalCallback<MethodData> mdTraversalCallback)
   49.97 +                             throws IOException {
   49.98 +        traverseHierarchy(
   49.99 +                startingClass,
  49.100 +                new FindMethodsTraversalCallback(methodName, methodSignature,
  49.101 +                                                 mdTraversalCallback));
  49.102 +    }
  49.103 +
  49.104 +    void findFields(final ClassData startingClass,
  49.105 +                    final String fieldName,
  49.106 +                    final String fieldSignature,
  49.107 +                    final TraversalCallback<FieldData> fdTraversalCallback)
  49.108 +                            throws IOException {
  49.109 +        traverseHierarchy(
  49.110 +                startingClass,
  49.111 +                new FindFieldsTraversalCallback(fieldName, fieldSignature,
  49.112 +                                                fdTraversalCallback));
  49.113 +    }
  49.114 +
  49.115 +    private boolean traverseHierarchy(
  49.116 +            ClassData currentClass,
  49.117 +            final TraversalCallback<ClassData> cdTraversalCallback)
  49.118 +                throws IOException {
  49.119 +        while (currentClass != null) {
  49.120 +            if (!cdTraversalCallback.traverse(currentClass)) {
  49.121 +                return false;
  49.122 +            }
  49.123 +
  49.124 +            for (final String superIfaceName:
  49.125 +                    currentClass.getSuperInterfaces()) {
  49.126 +                if (!traverseHierarchy(getClassData(superIfaceName),
  49.127 +                                       cdTraversalCallback)) {
  49.128 +                    return false;
  49.129 +                }
  49.130 +            }
  49.131 +
  49.132 +            final String superClassName = currentClass.getSuperClassName();
  49.133 +            if (superClassName == null) {
  49.134 +                break;
  49.135 +            }
  49.136 +
  49.137 +            currentClass = getClassData(superClassName);
  49.138 +        }
  49.139 +
  49.140 +        return true;
  49.141 +    }
  49.142 +
  49.143 +    interface TraversalCallback<T> {
  49.144 +        boolean traverse(T object);
  49.145 +    }
  49.146 +
  49.147 +    private final class FindFirstTraversalCallback<T>
  49.148 +            implements TraversalCallback<T> {
  49.149 +        private T firstObject;
  49.150 +
  49.151 +        @Override
  49.152 +        public boolean traverse(final T object) {
  49.153 +            firstObject = object;
  49.154 +            return false;
  49.155 +        }
  49.156 +
  49.157 +        public T getFirst() {
  49.158 +            return firstObject;
  49.159 +        }
  49.160 +    }
  49.161 +
  49.162 +    private final class FindMethodsTraversalCallback
  49.163 +            implements TraversalCallback<ClassData> {
  49.164 +        private final String methodName;
  49.165 +        private final String methodSignature;
  49.166 +        private final TraversalCallback<MethodData> mdTraversalCallback;
  49.167 +
  49.168 +        public FindMethodsTraversalCallback(
  49.169 +                final String methodName,
  49.170 +                final String methodSignature,
  49.171 +                final TraversalCallback<MethodData> mdTraversalCallback) {
  49.172 +            this.methodName = methodName;
  49.173 +            this.methodSignature = methodSignature;
  49.174 +            this.mdTraversalCallback = mdTraversalCallback;
  49.175 +        }
  49.176 +
  49.177 +        @Override
  49.178 +        public boolean traverse(final ClassData classData) {
  49.179 +            final MethodData methodData =
  49.180 +                    classData.findMethod(methodName, methodSignature);
  49.181 +            return (methodData != null)
  49.182 +                       ? mdTraversalCallback.traverse(methodData)
  49.183 +                       : true;
  49.184 +        }
  49.185 +    }
  49.186 +
  49.187 +    private final class FindFieldsTraversalCallback
  49.188 +            implements TraversalCallback<ClassData> {
  49.189 +        private final String fieldName;
  49.190 +        private final String fieldSignature;
  49.191 +        private final TraversalCallback<FieldData> fdTraversalCallback;
  49.192 +
  49.193 +        public FindFieldsTraversalCallback(
  49.194 +                final String fieldName,
  49.195 +                final String fieldSignature,
  49.196 +                final TraversalCallback<FieldData> fdTraversalCallback) {
  49.197 +            this.fieldName = fieldName;
  49.198 +            this.fieldSignature = fieldSignature;
  49.199 +            this.fdTraversalCallback = fdTraversalCallback;
  49.200 +        }
  49.201 +
  49.202 +        @Override
  49.203 +        public boolean traverse(final ClassData classData) {
  49.204 +            final FieldData fieldData =
  49.205 +                    classData.findField(fieldName, fieldSignature);
  49.206 +            return (fieldData != null)
  49.207 +                       ? fdTraversalCallback.traverse(fieldData)
  49.208 +                       : true;
  49.209 +        }
  49.210 +    }
  49.211 +
  49.212 +    private static InputStream loadClass(Bck2Brwsr.Resources l, String name)
  49.213 +            throws IOException {
  49.214 +        return l.get(name + ".class"); // NOI18N
  49.215 +    }
  49.216 +}
    50.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java	Wed Apr 30 09:26:28 2014 +0200
    50.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java	Tue May 06 17:46:47 2014 +0200
    50.3 @@ -23,14 +23,9 @@
    50.4  import java.io.OutputStream;
    50.5  import java.io.PrintStream;
    50.6  import java.util.ArrayList;
    50.7 -import java.util.Arrays;
    50.8 -import java.util.Collection;
    50.9  import java.util.Collections;
   50.10  import java.util.List;
   50.11  import org.apidesign.bck2brwsr.core.ExtraJavaScript;
   50.12 -import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
   50.13 -import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
   50.14 -import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
   50.15  
   50.16  /**
   50.17   *
   50.18 @@ -40,24 +35,18 @@
   50.19  final class ClosureWrapper extends CommandLineRunner {
   50.20      private static final String[] ARGS = { "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--js", "bck2brwsr-raw.js" /*, "--debug", "--formatting", "PRETTY_PRINT" */ };
   50.21  
   50.22 -    private final ClosuresObfuscationDelegate obfuscationDelegate;
   50.23 -    private final Bck2Brwsr.Resources res;
   50.24 -    private final StringArray classes;
   50.25 +    private final Bck2Brwsr config;
   50.26  
   50.27      private String compiledCode;
   50.28      private String externsCode;
   50.29  
   50.30 -    private ClosureWrapper(Appendable out, 
   50.31 -                           String compilationLevel,
   50.32 -                           ClosuresObfuscationDelegate obfuscationDelegate,
   50.33 -                           Bck2Brwsr.Resources res, StringArray classes) {
   50.34 +    private ClosureWrapper(Appendable out,
   50.35 +                           String compilationLevel, Bck2Brwsr config) {
   50.36          super(
   50.37              generateArguments(compilationLevel),
   50.38              new PrintStream(new APS(out)), System.err
   50.39          );
   50.40 -        this.obfuscationDelegate = obfuscationDelegate;
   50.41 -        this.res = res;
   50.42 -        this.classes = classes;
   50.43 +        this.config = config;
   50.44      }
   50.45  
   50.46      @Override
   50.47 @@ -100,7 +89,7 @@
   50.48          if (compiledCode == null) {
   50.49              StringBuilder sb = new StringBuilder();
   50.50              try {
   50.51 -                VM.compile(res, sb, classes, obfuscationDelegate);
   50.52 +                VM.compile(sb, config);
   50.53                  compiledCode = sb.toString();
   50.54              } catch (IOException ex) {
   50.55                  compiledCode = ex.getMessage();
   50.56 @@ -115,7 +104,7 @@
   50.57              getCompiledCode();
   50.58  
   50.59              final StringBuilder sb = new StringBuilder("function RAW() {};\n");
   50.60 -            for (final String extern: obfuscationDelegate.getExterns()) {
   50.61 +            for (final String extern: FIXED_EXTERNS) {
   50.62                  sb.append("RAW.prototype.").append(extern).append(";\n");
   50.63              }
   50.64              externsCode = sb.toString();
   50.65 @@ -142,8 +131,16 @@
   50.66          return finalArgs;
   50.67      }
   50.68  
   50.69 -    static int produceTo(Appendable w, ObfuscationLevel obfuscationLevel, Bck2Brwsr.Resources resources, StringArray arr) throws IOException {
   50.70 -        ClosureWrapper cw = create(w, obfuscationLevel, resources, arr);
   50.71 +    static int produceTo(Appendable output,
   50.72 +        ObfuscationLevel obfuscationLevel,
   50.73 +        Bck2Brwsr config
   50.74 +    ) throws IOException {
   50.75 +        final ClosureWrapper cw =
   50.76 +                new ClosureWrapper(output,
   50.77 +                                   (obfuscationLevel == ObfuscationLevel.FULL)
   50.78 +                                           ? "ADVANCED_OPTIMIZATIONS"
   50.79 +                                           : "SIMPLE_OPTIMIZATIONS",
   50.80 +                                   config);
   50.81          try {
   50.82              return cw.doRun();
   50.83          } catch (FlagUsageException ex) {
   50.84 @@ -151,185 +148,51 @@
   50.85          }
   50.86      }
   50.87  
   50.88 -    private static ClosureWrapper create(Appendable w,
   50.89 -                                         ObfuscationLevel obfuscationLevel,
   50.90 -                                         Bck2Brwsr.Resources resources,
   50.91 -                                         StringArray arr) {
   50.92 -        switch (obfuscationLevel) {
   50.93 -            case MINIMAL:
   50.94 -                return new ClosureWrapper(w, "SIMPLE_OPTIMIZATIONS",
   50.95 -                                          new SimpleObfuscationDelegate(),
   50.96 -                                          resources, arr);
   50.97 -/*                
   50.98 -            case MEDIUM:
   50.99 -                return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
  50.100 -                                          new MediumObfuscationDelegate(),
  50.101 -                                          resources, arr);
  50.102 -*/
  50.103 -            case FULL:
  50.104 -                return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
  50.105 -                                          new FullObfuscationDelegate(),
  50.106 -                                          resources, arr);
  50.107 -            default:
  50.108 -                throw new IllegalArgumentException(
  50.109 -                        "Unsupported level: " + obfuscationLevel);
  50.110 -        }
  50.111 -    }
  50.112 -
  50.113 -    private static abstract class ClosuresObfuscationDelegate
  50.114 -            extends ObfuscationDelegate {
  50.115 -        public abstract Collection<String> getExterns();
  50.116 -    }
  50.117 -
  50.118 -    private static final class SimpleObfuscationDelegate
  50.119 -            extends ClosuresObfuscationDelegate {
  50.120 -        @Override
  50.121 -        public void exportJSProperty(Appendable out,
  50.122 -                                     String destObject,
  50.123 -                                     String propertyName) throws IOException {
  50.124 -        }
  50.125 -
  50.126 -        @Override
  50.127 -        public void exportClass(Appendable out,
  50.128 -                                String destObject,
  50.129 -                                String mangledName,
  50.130 -                                ClassData classData) throws IOException {
  50.131 -        }
  50.132 -
  50.133 -        @Override
  50.134 -        public void exportMethod(Appendable out,
  50.135 -                                 String destObject,
  50.136 -                                 String mangledName,
  50.137 -                                 MethodData methodData) throws IOException {
  50.138 -        }
  50.139 -
  50.140 -        @Override
  50.141 -        public void exportField(Appendable out,
  50.142 -                                String destObject,
  50.143 -                                String mangledName,
  50.144 -                                FieldData fieldData) throws IOException {
  50.145 -        }
  50.146 -
  50.147 -        @Override
  50.148 -        public Collection<String> getExterns() {
  50.149 -            return Collections.EMPTY_LIST;
  50.150 -        }
  50.151 -    }
  50.152 -
  50.153 -    private static abstract class AdvancedObfuscationDelegate
  50.154 -            extends ClosuresObfuscationDelegate {
  50.155 -        private static final String[] INITIAL_EXTERNS = {
  50.156 -            "bck2brwsr",
  50.157 -            "$class",
  50.158 -            "anno",
  50.159 -            "array",
  50.160 -            "access",
  50.161 -            "cls",
  50.162 -            "vm",
  50.163 -            "loadClass",
  50.164 -            "loadBytes",
  50.165 -            "jvmName",
  50.166 -            "primitive",
  50.167 -            "superclass",
  50.168 -            "cnstr",
  50.169 -            "add32",
  50.170 -            "sub32",
  50.171 -            "mul32",
  50.172 -            "neg32",
  50.173 -            "toInt8",
  50.174 -            "toInt16",
  50.175 -            "next32",
  50.176 -            "high32",
  50.177 -            "toInt32",
  50.178 -            "toFP",
  50.179 -            "toLong",
  50.180 -            "toExactString",
  50.181 -            "add64",
  50.182 -            "sub64",
  50.183 -            "mul64",
  50.184 -            "and64",
  50.185 -            "or64",
  50.186 -            "xor64",
  50.187 -            "shl64",
  50.188 -            "shr64",
  50.189 -            "ushr64",
  50.190 -            "compare64",
  50.191 -            "compare",
  50.192 -            "neg64",
  50.193 -            "div32",
  50.194 -            "mod32",
  50.195 -            "div64",
  50.196 -            "mod64",
  50.197 -            "at",
  50.198 -            "getClass__Ljava_lang_Class_2",
  50.199 -            "clone__Ljava_lang_Object_2"
  50.200 -        };
  50.201 -
  50.202 -        private final Collection<String> externs;
  50.203 -
  50.204 -        protected AdvancedObfuscationDelegate() {
  50.205 -            externs = new ArrayList<String>(Arrays.asList(INITIAL_EXTERNS));
  50.206 -        }
  50.207 -
  50.208 -        @Override
  50.209 -        public void exportClass(Appendable out,
  50.210 -                                String destObject,
  50.211 -                                String mangledName,
  50.212 -                                ClassData classData) throws IOException {
  50.213 -            exportJSProperty(out, destObject, mangledName);
  50.214 -        }
  50.215 -
  50.216 -        @Override
  50.217 -        public void exportMethod(Appendable out,
  50.218 -                                 String destObject,
  50.219 -                                 String mangledName,
  50.220 -                                 MethodData methodData) throws IOException {
  50.221 -            if ((methodData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
  50.222 -                exportJSProperty(out, destObject, mangledName);
  50.223 -            }
  50.224 -        }
  50.225 -
  50.226 -        @Override
  50.227 -        public void exportField(Appendable out,
  50.228 -                                String destObject,
  50.229 -                                String mangledName,
  50.230 -                                FieldData fieldData) throws IOException {
  50.231 -            if ((fieldData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
  50.232 -                exportJSProperty(out, destObject, mangledName);
  50.233 -            }
  50.234 -        }
  50.235 -
  50.236 -        @Override
  50.237 -        public Collection<String> getExterns() {
  50.238 -            return externs;
  50.239 -        }
  50.240 -
  50.241 -        protected void addExtern(String extern) {
  50.242 -            externs.add(extern);
  50.243 -        }
  50.244 -    }
  50.245 -
  50.246 -    private static final class MediumObfuscationDelegate
  50.247 -            extends AdvancedObfuscationDelegate {
  50.248 -        @Override
  50.249 -        public void exportJSProperty(Appendable out,
  50.250 -                                     String destObject,
  50.251 -                                     String propertyName) {
  50.252 -            addExtern(propertyName);
  50.253 -        }
  50.254 -    }
  50.255 -
  50.256 -    private static final class FullObfuscationDelegate
  50.257 -            extends AdvancedObfuscationDelegate {
  50.258 -        @Override
  50.259 -        public void exportJSProperty(Appendable out,
  50.260 -                                     String destObject,
  50.261 -                                     String propertyName) throws IOException {
  50.262 -            out.append("\n").append(destObject).append("['")
  50.263 -                                               .append(propertyName)
  50.264 -                                               .append("'] = ")
  50.265 -                            .append(destObject).append(".").append(propertyName)
  50.266 -               .append(";\n");
  50.267 -        }
  50.268 -    }
  50.269 +    private static final String[] FIXED_EXTERNS = {
  50.270 +        "bck2brwsr",
  50.271 +        "bck2BrwsrThrwrbl",
  50.272 +        "registerExtension",
  50.273 +        "$class",
  50.274 +        "anno",
  50.275 +        "array",
  50.276 +        "access",
  50.277 +        "cls",
  50.278 +        "vm",
  50.279 +        "loadClass",
  50.280 +        "loadBytes",
  50.281 +        "jvmName",
  50.282 +        "primitive",
  50.283 +        "superclass",
  50.284 +        "cnstr",
  50.285 +        "add32",
  50.286 +        "sub32",
  50.287 +        "mul32",
  50.288 +        "neg32",
  50.289 +        "toInt8",
  50.290 +        "toInt16",
  50.291 +        "next32",
  50.292 +        "high32",
  50.293 +        "toInt32",
  50.294 +        "toFP",
  50.295 +        "toLong",
  50.296 +        "toExactString",
  50.297 +        "add64",
  50.298 +        "sub64",
  50.299 +        "mul64",
  50.300 +        "and64",
  50.301 +        "or64",
  50.302 +        "xor64",
  50.303 +        "shl64",
  50.304 +        "shr64",
  50.305 +        "ushr64",
  50.306 +        "compare64",
  50.307 +        "neg64",
  50.308 +        "div32",
  50.309 +        "mod32",
  50.310 +        "div64",
  50.311 +        "mod64",
  50.312 +        "at",
  50.313 +        "getClass__Ljava_lang_Class_2",
  50.314 +        "clone__Ljava_lang_Object_2"
  50.315 +    };
  50.316  }
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ExportedSymbols.java	Tue May 06 17:46:47 2014 +0200
    51.3 @@ -0,0 +1,153 @@
    51.4 +/**
    51.5 + * Back 2 Browser Bytecode Translator
    51.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    51.7 + *
    51.8 + * This program is free software: you can redistribute it and/or modify
    51.9 + * it under the terms of the GNU General Public License as published by
   51.10 + * the Free Software Foundation, version 2 of the License.
   51.11 + *
   51.12 + * This program is distributed in the hope that it will be useful,
   51.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   51.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   51.15 + * GNU General Public License for more details.
   51.16 + *
   51.17 + * You should have received a copy of the GNU General Public License
   51.18 + * along with this program. Look for COPYING file in the top folder.
   51.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   51.20 + */
   51.21 +package org.apidesign.vm4brwsr;
   51.22 +
   51.23 +import java.io.IOException;
   51.24 +import java.io.InputStream;
   51.25 +import java.util.HashMap;
   51.26 +import java.util.Map;
   51.27 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
   51.28 +import org.apidesign.vm4brwsr.ByteCodeParser.AnnotationParser;
   51.29 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
   51.30 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
   51.31 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
   51.32 +
   51.33 +@ExtraJavaScript(processByteCode = false, resource="")
   51.34 +final class ExportedSymbols {
   51.35 +    private final Bck2Brwsr.Resources resources;
   51.36 +    private final StringArray exported;
   51.37 +    private final Map<Object, Boolean> isMarkedAsExportedCache;
   51.38 +
   51.39 +    ExportedSymbols(final Bck2Brwsr.Resources resources, StringArray explicitlyExported) {
   51.40 +        this.resources = resources;
   51.41 +        this.exported = explicitlyExported;
   51.42 +
   51.43 +        isMarkedAsExportedCache = new HashMap<Object, Boolean>();
   51.44 +    }
   51.45 +
   51.46 +    boolean isExported(ClassData classData) throws IOException {
   51.47 +        if (exported.contains(classData.getClassName())) {
   51.48 +            return true;
   51.49 +        }
   51.50 +        return classData.isPublic() && isMarkedAsExportedPackage(
   51.51 +                                           classData.getPkgName())
   51.52 +                   || isMarkedAsExported(classData);
   51.53 +    }
   51.54 +
   51.55 +    boolean isExported(MethodData methodData) throws IOException {
   51.56 +        return isAccessible(methodData.access) && isExported(methodData.cls)
   51.57 +                   || isMarkedAsExported(methodData);
   51.58 +    }
   51.59 +
   51.60 +    boolean isExported(FieldData fieldData) throws IOException {
   51.61 +        return isAccessible(fieldData.access) && isExported(fieldData.cls)
   51.62 +                   || isMarkedAsExported(fieldData);
   51.63 +    }
   51.64 +
   51.65 +    private boolean isMarkedAsExportedPackage(String pkgName) {
   51.66 +        if (pkgName == null) {
   51.67 +            return false;
   51.68 +        }
   51.69 +
   51.70 +        final Boolean cachedValue = isMarkedAsExportedCache.get(pkgName);
   51.71 +        if (cachedValue != null) {
   51.72 +            return cachedValue;
   51.73 +        }
   51.74 +
   51.75 +        final boolean newValue = resolveIsMarkedAsExportedPackage(pkgName);
   51.76 +        isMarkedAsExportedCache.put(pkgName, newValue);
   51.77 +
   51.78 +        return newValue;
   51.79 +    }
   51.80 +
   51.81 +    private boolean isMarkedAsExported(ClassData classData)
   51.82 +            throws IOException {
   51.83 +        final Boolean cachedValue = isMarkedAsExportedCache.get(classData);
   51.84 +        if (cachedValue != null) {
   51.85 +            return cachedValue;
   51.86 +        }
   51.87 +
   51.88 +        final boolean newValue =
   51.89 +                isMarkedAsExported(classData.findAnnotationData(true),
   51.90 +                                   classData);
   51.91 +        isMarkedAsExportedCache.put(classData, newValue);
   51.92 +
   51.93 +        return newValue;
   51.94 +    }
   51.95 +
   51.96 +    private boolean isMarkedAsExported(MethodData methodData)
   51.97 +            throws IOException {
   51.98 +        return isMarkedAsExported(methodData.findAnnotationData(true),
   51.99 +                                  methodData.cls);
  51.100 +    }
  51.101 +
  51.102 +    private boolean isMarkedAsExported(FieldData fieldData)
  51.103 +            throws IOException {
  51.104 +        return isMarkedAsExported(fieldData.findAnnotationData(true),
  51.105 +                                  fieldData.cls);
  51.106 +    }
  51.107 +
  51.108 +    private boolean resolveIsMarkedAsExportedPackage(String pkgName) {
  51.109 +        try {
  51.110 +            final InputStream is =
  51.111 +                    resources.get(pkgName + "/package-info.class");
  51.112 +            if (is == null) {
  51.113 +                return false;
  51.114 +            }
  51.115 +
  51.116 +            try {
  51.117 +                final ClassData pkgInfoClass = new ClassData(is);
  51.118 +                return isMarkedAsExported(
  51.119 +                               pkgInfoClass.findAnnotationData(true),
  51.120 +                               pkgInfoClass);
  51.121 +            } finally {
  51.122 +                is.close();
  51.123 +            }
  51.124 +        } catch (final IOException e) {
  51.125 +            return false;
  51.126 +        }
  51.127 +    }
  51.128 +
  51.129 +    private boolean isMarkedAsExported(byte[] arrData, ClassData cd)
  51.130 +            throws IOException {
  51.131 +        if (arrData == null) {
  51.132 +            return false;
  51.133 +        }
  51.134 +
  51.135 +        final boolean[] found = { false };
  51.136 +        final AnnotationParser annotationParser =
  51.137 +                new AnnotationParser(false, false) {
  51.138 +                    @Override
  51.139 +                    protected void visitAnnotationStart(
  51.140 +                            String type,
  51.141 +                            boolean top) {
  51.142 +                        if (top && type.equals("Lorg/apidesign/bck2brwsr"
  51.143 +                                                   + "/core/Exported;")) {
  51.144 +                            found[0] = true;
  51.145 +                        }
  51.146 +                    }
  51.147 +                };
  51.148 +        annotationParser.parse(arrData, cd);
  51.149 +        return found[0];
  51.150 +    }
  51.151 +
  51.152 +    private static boolean isAccessible(int access) {
  51.153 +        return (access & (ByteCodeParser.ACC_PUBLIC
  51.154 +                              | ByteCodeParser.ACC_PROTECTED)) != 0;
  51.155 +    }
  51.156 +}
    52.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Wed Apr 30 09:26:28 2014 +0200
    52.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Tue May 06 17:46:47 2014 +0200
    52.3 @@ -22,6 +22,12 @@
    52.4  import java.io.FileWriter;
    52.5  import java.io.IOException;
    52.6  import java.io.Writer;
    52.7 +import java.net.URI;
    52.8 +import java.net.URISyntaxException;
    52.9 +import java.net.URL;
   52.10 +import java.util.Enumeration;
   52.11 +import java.util.jar.JarEntry;
   52.12 +import java.util.jar.JarFile;
   52.13  
   52.14  /** Generator of JavaScript from bytecode of classes on classpath of the VM
   52.15   * with a Main method.
   52.16 @@ -31,12 +37,13 @@
   52.17  final class Main {
   52.18      private Main() {}
   52.19      
   52.20 -    public static void main(String... args) throws IOException {
   52.21 +    public static void main(String... args) throws IOException, URISyntaxException {
   52.22          final String obfuscate = "--obfuscatelevel";
   52.23 -        
   52.24 +        final String extension = "--createextension";
   52.25 +
   52.26          if (args.length < 2) {
   52.27              System.err.println("Bck2Brwsr Translator from Java(tm) to JavaScript, (c) Jaroslav Tulach 2012");
   52.28 -            System.err.println("Usage: java -cp ... -jar ... [");
   52.29 +            System.err.print("Usage: java -cp ... -jar ... [");
   52.30              System.err.print(obfuscate);
   52.31              System.err.print(" [");
   52.32              boolean first = true;
   52.33 @@ -47,12 +54,16 @@
   52.34                  System.err.print(l.name());
   52.35                  first = false;
   52.36              }
   52.37 -                
   52.38 +            System.err.print("]] [");
   52.39 +            System.err.print(extension);
   52.40              System.err.println("] <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
   52.41              System.exit(9);
   52.42          }
   52.43 -        
   52.44 +
   52.45 +        final ClassLoader mainClassLoader = Main.class.getClassLoader();
   52.46 +
   52.47          ObfuscationLevel obfLevel = ObfuscationLevel.NONE;
   52.48 +        boolean createExtension = false;
   52.49          StringArray classes = new StringArray();
   52.50          String generateTo = null;
   52.51          for (int i = 0; i < args.length; i++) {
   52.52 @@ -76,10 +87,14 @@
   52.53                  }
   52.54                  continue;
   52.55              }
   52.56 +            if (extension.equals(args[i])) { // NOI18N
   52.57 +                createExtension = true;
   52.58 +                continue;
   52.59 +            }
   52.60              if (generateTo == null) {
   52.61                  generateTo = args[i];
   52.62              } else {
   52.63 -                classes = classes.addAndNew(args[i]);
   52.64 +                collectClasses(classes, mainClassLoader, args[i]);
   52.65              }
   52.66          }
   52.67          
   52.68 @@ -90,11 +105,110 @@
   52.69          }
   52.70          
   52.71          try (Writer w = new BufferedWriter(new FileWriter(gt))) {
   52.72 -            Bck2Brwsr.newCompiler().
   52.73 +            Bck2Brwsr.newCompiler().library(createExtension).
   52.74                  obfuscation(obfLevel).
   52.75                  addRootClasses(classes.toArray()).
   52.76                  resources(new LdrRsrcs(Main.class.getClassLoader(), true)).
   52.77                  generate(w);
   52.78          }
   52.79      }
   52.80 +
   52.81 +    private static void collectClasses(
   52.82 +            final StringArray dest,
   52.83 +            final ClassLoader cl, final String relativePath)
   52.84 +                throws IOException, URISyntaxException {
   52.85 +        final Enumeration<URL> urls = cl.getResources(relativePath);
   52.86 +        if (!urls.hasMoreElements()) {
   52.87 +            dest.add(relativePath);
   52.88 +            return;
   52.89 +        }
   52.90 +        do {
   52.91 +            final URL url = urls.nextElement();
   52.92 +            switch (url.getProtocol()) {
   52.93 +                case "file":
   52.94 +                    collectClasses(dest, relativePath,
   52.95 +                                   new File(new URI(url.toString())));
   52.96 +                    continue;
   52.97 +                case "jar":
   52.98 +                    final String fullPath = url.getPath();
   52.99 +                    final int sepIndex = fullPath.indexOf('!');
  52.100 +                    final String jarFilePath =
  52.101 +                            (sepIndex != -1) ? fullPath.substring(0, sepIndex)
  52.102 +                                             : fullPath;
  52.103 +
  52.104 +                    final URI jarUri = new URI(jarFilePath);
  52.105 +                    if (jarUri.getScheme().equals("file")) {
  52.106 +                        try (JarFile jarFile = new JarFile(new File(jarUri))) {
  52.107 +                            collectClasses(dest, relativePath, jarFile);
  52.108 +                            continue;
  52.109 +                        }
  52.110 +                    }
  52.111 +                    break;
  52.112 +            }
  52.113 +
  52.114 +            dest.add(relativePath);
  52.115 +        } while (urls.hasMoreElements());
  52.116 +    }
  52.117 +
  52.118 +    private static void collectClasses(final StringArray dest,
  52.119 +                                       final String relativePath,
  52.120 +                                       final File file) {
  52.121 +        if (file.isDirectory()) {
  52.122 +            final File[] subFiles = file.listFiles();
  52.123 +            for (final File subFile: subFiles) {
  52.124 +                collectClasses(dest,
  52.125 +                               extendPath(relativePath, subFile.getName()),
  52.126 +                               subFile);
  52.127 +            }
  52.128 +
  52.129 +            return;
  52.130 +        }
  52.131 +
  52.132 +        final String filePath = file.getPath();
  52.133 +        if (filePath.endsWith(".class")) {
  52.134 +            validateAndAddClass(dest, relativePath);
  52.135 +        }
  52.136 +    }
  52.137 +
  52.138 +    private static void collectClasses(final StringArray dest,
  52.139 +                                       final String relativePath,
  52.140 +                                       final JarFile jarFile) {
  52.141 +        if (relativePath.endsWith(".class")) {
  52.142 +            if (jarFile.getJarEntry(relativePath) != null) {
  52.143 +                validateAndAddClass(dest, relativePath);
  52.144 +            }
  52.145 +
  52.146 +            return;
  52.147 +        }
  52.148 +
  52.149 +        final String expectedPrefix =
  52.150 +                relativePath.endsWith("/") ? relativePath
  52.151 +                                           : relativePath + '/';
  52.152 +        final Enumeration<JarEntry> entries = jarFile.entries();
  52.153 +        while (entries.hasMoreElements()) {
  52.154 +            final JarEntry entry = entries.nextElement();
  52.155 +            if (!entry.isDirectory()) {
  52.156 +                final String entryName = entry.getName();
  52.157 +                if (entryName.startsWith(expectedPrefix)
  52.158 +                        && entryName.endsWith(".class")) {
  52.159 +                    validateAndAddClass(dest, entryName);
  52.160 +                }
  52.161 +            }
  52.162 +        }
  52.163 +    }
  52.164 +
  52.165 +    private static String extendPath(final String relativePath,
  52.166 +                                     final String fileName) {
  52.167 +        return relativePath.endsWith("/") ? relativePath + fileName
  52.168 +                                          : relativePath + '/' + fileName;
  52.169 +    }
  52.170 +
  52.171 +    private static void validateAndAddClass(final StringArray dest,
  52.172 +                                            final String relativePath) {
  52.173 +        final String className =
  52.174 +                relativePath.substring(0, relativePath.length() - 6);
  52.175 +        if (!className.endsWith("package-info")) {
  52.176 +            dest.add(className);
  52.177 +        }
  52.178 +    }
  52.179  }
    53.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ObfuscationDelegate.java	Wed Apr 30 09:26:28 2014 +0200
    53.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.3 @@ -1,75 +0,0 @@
    53.4 -/**
    53.5 - * Back 2 Browser Bytecode Translator
    53.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    53.7 - *
    53.8 - * This program is free software: you can redistribute it and/or modify
    53.9 - * it under the terms of the GNU General Public License as published by
   53.10 - * the Free Software Foundation, version 2 of the License.
   53.11 - *
   53.12 - * This program is distributed in the hope that it will be useful,
   53.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   53.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   53.15 - * GNU General Public License for more details.
   53.16 - *
   53.17 - * You should have received a copy of the GNU General Public License
   53.18 - * along with this program. Look for COPYING file in the top folder.
   53.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   53.20 - */
   53.21 -package org.apidesign.vm4brwsr;
   53.22 -
   53.23 -import java.io.IOException;
   53.24 -import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
   53.25 -import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
   53.26 -import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
   53.27 -
   53.28 -abstract class ObfuscationDelegate {
   53.29 -    static ObfuscationDelegate NULL =
   53.30 -            new ObfuscationDelegate() {
   53.31 -                @Override
   53.32 -                public void exportJSProperty(Appendable out,
   53.33 -                                             String destObject,
   53.34 -                                             String propertyName)
   53.35 -                            throws IOException {
   53.36 -                }
   53.37 -
   53.38 -                @Override
   53.39 -                public void exportClass(Appendable out,
   53.40 -                                        String destObject,
   53.41 -                                        String mangledName,
   53.42 -                                        ClassData classData)
   53.43 -                                            throws IOException {
   53.44 -                }
   53.45 -
   53.46 -                @Override
   53.47 -                public void exportMethod(Appendable out,
   53.48 -                                         String destObject,
   53.49 -                                         String mangledName,
   53.50 -                                         MethodData methodData)
   53.51 -                                             throws IOException {
   53.52 -                }
   53.53 -
   53.54 -                @Override
   53.55 -                public void exportField(Appendable out,
   53.56 -                                        String destObject,
   53.57 -                                        String mangledName,
   53.58 -                                        FieldData fieldData)
   53.59 -                                            throws IOException {
   53.60 -                }
   53.61 -            };
   53.62 -
   53.63 -    public abstract void exportJSProperty(
   53.64 -            Appendable out, String destObject, String propertyName)
   53.65 -                throws IOException;
   53.66 -
   53.67 -    public abstract void exportClass(
   53.68 -            Appendable out, String destObject, String mangledName,
   53.69 -            ClassData classData) throws IOException;
   53.70 -
   53.71 -    public abstract void exportMethod(
   53.72 -            Appendable out, String destObject, String mangledName,
   53.73 -            MethodData methodData) throws IOException;
   53.74 -
   53.75 -    public abstract void exportField(
   53.76 -            Appendable out, String destObject, String mangledName,
   53.77 -            FieldData fieldData) throws IOException;
   53.78 -}
    54.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Wed Apr 30 09:26:28 2014 +0200
    54.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Tue May 06 17:46:47 2014 +0200
    54.3 @@ -19,18 +19,34 @@
    54.4  
    54.5  import java.io.IOException;
    54.6  import java.io.InputStream;
    54.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    54.8 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
    54.9 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
   54.10 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
   54.11  
   54.12  /** Generator of JavaScript from bytecode of classes on classpath of the VM.
   54.13   *
   54.14   * @author Jaroslav Tulach <jtulach@netbeans.org>
   54.15   */
   54.16 -class VM extends ByteCodeToJavaScript {
   54.17 -    public VM(Appendable out) {
   54.18 +abstract class VM extends ByteCodeToJavaScript {
   54.19 +    protected final ClassDataCache classDataCache;
   54.20 +
   54.21 +    private final Bck2Brwsr.Resources resources;
   54.22 +    private final ExportedSymbols exportedSymbols;
   54.23 +    private final StringArray invokerMethods;
   54.24 +
   54.25 +    private static final Class<?> FIXED_DEPENDENCIES[] = {
   54.26 +            Class.class,
   54.27 +            ArithmeticException.class,
   54.28 +            VM.class
   54.29 +        };
   54.30 +
   54.31 +    private VM(Appendable out, Bck2Brwsr.Resources resources, StringArray explicitlyExported) {
   54.32          super(out);
   54.33 -    }
   54.34 -
   54.35 -    private VM(Appendable out, ObfuscationDelegate obfuscationDelegate) {
   54.36 -        super(out, obfuscationDelegate);
   54.37 +        this.resources = resources;
   54.38 +        this.classDataCache = new ClassDataCache(resources);
   54.39 +        this.exportedSymbols = new ExportedSymbols(resources, explicitlyExported);
   54.40 +        this.invokerMethods = new StringArray();
   54.41      }
   54.42  
   54.43      static {
   54.44 @@ -48,17 +64,131 @@
   54.45          return false;
   54.46      }
   54.47      
   54.48 -    static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException {
   54.49 -        new VM(out).doCompile(l, names);
   54.50 +    static void compile(Appendable out, 
   54.51 +        Bck2Brwsr config
   54.52 +    ) throws IOException {
   54.53 +        String[] both = config.allClasses();
   54.54 +        
   54.55 +        VM vm = config.isExtension() ? 
   54.56 +            new Extension(out, config.getResources(), both, config.rootClasses())
   54.57 +            : 
   54.58 +            new Standalone(out, config.getResources(), config.rootClasses());
   54.59 +
   54.60 +        final StringArray fixedNames = new StringArray();
   54.61 +
   54.62 +        for (final Class<?> fixedClass: FIXED_DEPENDENCIES) {
   54.63 +            fixedNames.add(fixedClass.getName().replace('.', '/'));
   54.64 +        }
   54.65 +
   54.66 +        vm.doCompile(fixedNames.addAndNew(both), config.allResources());
   54.67      }
   54.68  
   54.69 -    static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names,
   54.70 -                        ObfuscationDelegate obfuscationDelegate) throws IOException {
   54.71 -        new VM(out, obfuscationDelegate).doCompile(l, names);
   54.72 +    private void doCompile(StringArray names, StringArray asBinary) throws IOException {
   54.73 +        generatePrologue();
   54.74 +        append(
   54.75 +                "\n  var invoker = {};");
   54.76 +        generateBody(names);
   54.77 +        for (String invokerMethod: invokerMethods.toArray()) {
   54.78 +            append("\n  invoker." + invokerMethod + " = function(target) {"
   54.79 +                + "\n    return function() {"
   54.80 +                + "\n      return target['" + invokerMethod + "'].apply(target, arguments);"
   54.81 +                + "\n    };"
   54.82 +                + "\n  };"
   54.83 +            );
   54.84 +        }
   54.85 +        
   54.86 +        for (String r : asBinary.toArray()) {
   54.87 +            append("\n  ").append(getExportsObject()).append(".registerResource('");
   54.88 +            append(r).append("', '");
   54.89 +            InputStream is = this.resources.get(r);
   54.90 +            byte[] arr = new byte[is.available()];
   54.91 +            int offset = 0;
   54.92 +            for (;;) {
   54.93 +                if (offset == arr.length) {
   54.94 +                    byte[] tmp = new byte[arr.length * 2];
   54.95 +                    System.arraycopy(arr, 0, tmp, 0, arr.length);
   54.96 +                    arr = tmp;
   54.97 +                }
   54.98 +                int len = is.read(arr, offset, arr.length - offset);
   54.99 +                if (len == -1) {
  54.100 +                    break;
  54.101 +                }
  54.102 +                offset += len;
  54.103 +            }
  54.104 +            if (offset != arr.length) {
  54.105 +                byte[] tmp = new byte[offset];
  54.106 +                System.arraycopy(arr, 0, tmp, 0, offset);
  54.107 +                arr = tmp;
  54.108 +            }
  54.109 +            append(btoa(arr));
  54.110 +            append("');");
  54.111 +        }
  54.112 +        
  54.113 +        append("\n");
  54.114 +        generateEpilogue();
  54.115      }
  54.116  
  54.117 -    protected void doCompile(Bck2Brwsr.Resources l, StringArray names) throws IOException {
  54.118 -        append("(function VM(global) {var fillInVMSkeleton = function(vm) {");
  54.119 +    @JavaScriptBody(args = { "arr" }, body = "return btoa(arr);")
  54.120 +    private static String btoa(byte[] arr) {
  54.121 +        return javax.xml.bind.DatatypeConverter.printBase64Binary(arr);
  54.122 +    }
  54.123 +
  54.124 +    protected abstract void generatePrologue() throws IOException;
  54.125 +
  54.126 +    protected abstract void generateEpilogue() throws IOException;
  54.127 +
  54.128 +    protected abstract String getExportsObject();
  54.129 +
  54.130 +    protected abstract boolean isExternalClass(String className);
  54.131 +
  54.132 +    @Override
  54.133 +    protected final void declaredClass(ClassData classData, String mangledName)
  54.134 +            throws IOException {
  54.135 +        if (exportedSymbols.isExported(classData)) {
  54.136 +            append("\n").append(getExportsObject()).append("['")
  54.137 +                                               .append(mangledName)
  54.138 +                                               .append("'] = ")
  54.139 +                            .append(accessClass(mangledName))
  54.140 +               .append(";\n");
  54.141 +        }
  54.142 +    }
  54.143 +
  54.144 +    protected String generateClass(String className) throws IOException {
  54.145 +        ClassData classData = classDataCache.getClassData(className);
  54.146 +        if (classData == null) {
  54.147 +            throw new IOException("Can't find class " + className);
  54.148 +        }
  54.149 +        return compile(classData);
  54.150 +    }
  54.151 +
  54.152 +    @Override
  54.153 +    protected void declaredField(FieldData fieldData,
  54.154 +                                 String destObject,
  54.155 +                                 String mangledName) throws IOException {
  54.156 +        if (exportedSymbols.isExported(fieldData)) {
  54.157 +            exportMember(destObject, mangledName);
  54.158 +        }
  54.159 +    }
  54.160 +
  54.161 +    @Override
  54.162 +    protected void declaredMethod(MethodData methodData,
  54.163 +                                  String destObject,
  54.164 +                                  String mangledName) throws IOException {
  54.165 +        if (isHierarchyExported(methodData)) {
  54.166 +            exportMember(destObject, mangledName);
  54.167 +        }
  54.168 +    }
  54.169 +
  54.170 +    private void exportMember(String destObject, String memberName)
  54.171 +            throws IOException {
  54.172 +        append("\n").append(destObject).append("['")
  54.173 +                                           .append(memberName)
  54.174 +                                           .append("'] = ")
  54.175 +                        .append(destObject).append(".").append(memberName)
  54.176 +           .append(";\n");
  54.177 +    }
  54.178 +
  54.179 +    private void generateBody(StringArray names) throws IOException {
  54.180          StringArray processed = new StringArray();
  54.181          StringArray initCode = new StringArray();
  54.182          StringArray skipClass = new StringArray();
  54.183 @@ -78,14 +208,14 @@
  54.184                  if (name == null) {
  54.185                      break;
  54.186                  }
  54.187 -                InputStream is = loadClass(l, name);
  54.188 +                InputStream is = resources.get(name + ".class");
  54.189                  if (is == null) {
  54.190                      lazyReference(this, name);
  54.191                      skipClass.add(name);
  54.192                      continue;
  54.193                  }
  54.194                  try {
  54.195 -                    String ic = compile(is);
  54.196 +                    String ic = generateClass(name);
  54.197                      processed.add(name);
  54.198                      initCode.add(ic == null ? "" : ic);
  54.199                  } catch (RuntimeException ex) {
  54.200 @@ -97,14 +227,14 @@
  54.201                  while (resource.startsWith("/")) {
  54.202                      resource = resource.substring(1);
  54.203                  }
  54.204 -                InputStream emul = l.get(resource);
  54.205 +                InputStream emul = resources.get(resource);
  54.206                  if (emul == null) {
  54.207                      throw new IOException("Can't find " + resource);
  54.208                  }
  54.209                  readResource(emul, this);
  54.210              }
  54.211              scripts = new StringArray();
  54.212 -            
  54.213 +
  54.214              StringArray toInit = StringArray.asList(references.toArray());
  54.215              toInit.reverse();
  54.216  
  54.217 @@ -119,6 +249,7 @@
  54.218                  }
  54.219              }
  54.220          }
  54.221 +/*
  54.222          append(
  54.223                "  return vm;\n"
  54.224              + "  };\n"
  54.225 @@ -158,7 +289,9 @@
  54.226              + "    return loader;\n"
  54.227              + "  };\n");
  54.228          append("}(this));");
  54.229 +*/
  54.230      }
  54.231 +
  54.232      private static void readResource(InputStream emul, Appendable out) throws IOException {
  54.233          try {
  54.234              int state = 0;
  54.235 @@ -205,10 +338,6 @@
  54.236          }
  54.237      }
  54.238  
  54.239 -    private static InputStream loadClass(Bck2Brwsr.Resources l, String name) throws IOException {
  54.240 -        return l.get(name + ".class"); // NOI18N
  54.241 -    }
  54.242 -
  54.243      static String toString(String name) throws IOException {
  54.244          StringBuilder sb = new StringBuilder();
  54.245  //        compile(sb, name);
  54.246 @@ -243,8 +372,287 @@
  54.247      }
  54.248  
  54.249      @Override
  54.250 -    String getVMObject() {
  54.251 -        return "vm";
  54.252 +    protected String accessField(String object, String mangledName,
  54.253 +                                 String[] fieldInfoName) throws IOException {
  54.254 +        final FieldData field =
  54.255 +                classDataCache.findField(fieldInfoName[0],
  54.256 +                                         fieldInfoName[1],
  54.257 +                                         fieldInfoName[2]);
  54.258 +        return accessNonVirtualMember(object, mangledName,
  54.259 +                                      (field != null) ? field.cls : null);
  54.260 +    }
  54.261 +
  54.262 +    @Override
  54.263 +    protected String accessStaticMethod(
  54.264 +                             String object,
  54.265 +                             String mangledName,
  54.266 +                             String[] fieldInfoName) throws IOException {
  54.267 +        final MethodData method =
  54.268 +                classDataCache.findMethod(fieldInfoName[0],
  54.269 +                                          fieldInfoName[1],
  54.270 +                                          fieldInfoName[2]);
  54.271 +        return accessNonVirtualMember(object, mangledName,
  54.272 +                                      (method != null) ? method.cls : null);
  54.273 +    }
  54.274 +
  54.275 +    @Override
  54.276 +    protected String accessVirtualMethod(
  54.277 +                             String object,
  54.278 +                             String mangledName,
  54.279 +                             String[] fieldInfoName) throws IOException {
  54.280 +        final ClassData referencedClass =
  54.281 +                classDataCache.getClassData(fieldInfoName[0]);
  54.282 +        final MethodData method =
  54.283 +                classDataCache.findMethod(referencedClass,
  54.284 +                                          fieldInfoName[1],
  54.285 +                                          fieldInfoName[2]);
  54.286 +
  54.287 +        if ((method != null)
  54.288 +                && !isExternalClass(method.cls.getClassName())
  54.289 +                && (((method.access & ByteCodeParser.ACC_FINAL) != 0)
  54.290 +                        || ((referencedClass.getAccessFlags()
  54.291 +                                 & ByteCodeParser.ACC_FINAL) != 0)
  54.292 +                        || !isHierarchyExported(method))) {
  54.293 +            return object + "." + mangledName;
  54.294 +        }
  54.295 +
  54.296 +        return accessThroughInvoker(object, mangledName);
  54.297 +    }
  54.298 +
  54.299 +    private String accessThroughInvoker(String object, String mangledName) {
  54.300 +        if (!invokerMethods.contains(mangledName)) {
  54.301 +            invokerMethods.add(mangledName);
  54.302 +        }
  54.303 +        return "invoker." + mangledName + '(' + object + ')';
  54.304 +    }
  54.305 +
  54.306 +    private boolean isHierarchyExported(final MethodData methodData)
  54.307 +            throws IOException {
  54.308 +        if (exportedSymbols.isExported(methodData)) {
  54.309 +            return true;
  54.310 +        }
  54.311 +        if ((methodData.access & (ByteCodeParser.ACC_PRIVATE
  54.312 +                                      | ByteCodeParser.ACC_STATIC)) != 0) {
  54.313 +            return false;
  54.314 +        }
  54.315 +
  54.316 +        final ExportedMethodFinder exportedMethodFinder =
  54.317 +                new ExportedMethodFinder(exportedSymbols);
  54.318 +
  54.319 +        classDataCache.findMethods(
  54.320 +                methodData.cls,
  54.321 +                methodData.getName(),
  54.322 +                methodData.getInternalSig(),
  54.323 +                exportedMethodFinder);
  54.324 +
  54.325 +        return (exportedMethodFinder.getFound() != null);
  54.326 +    }
  54.327 +
  54.328 +    private String accessNonVirtualMember(String object,
  54.329 +                                          String mangledName,
  54.330 +                                          ClassData declaringClass) {
  54.331 +        return ((declaringClass != null)
  54.332 +                    && !isExternalClass(declaringClass.getClassName()))
  54.333 +                            ? object + "." + mangledName
  54.334 +                            : object + "['" + mangledName + "']";
  54.335 +    }
  54.336 +
  54.337 +    private static final class ExportedMethodFinder
  54.338 +            implements ClassDataCache.TraversalCallback<MethodData> {
  54.339 +        private final ExportedSymbols exportedSymbols;
  54.340 +        private MethodData found;
  54.341 +
  54.342 +        public ExportedMethodFinder(final ExportedSymbols exportedSymbols) {
  54.343 +            this.exportedSymbols = exportedSymbols;
  54.344 +        }
  54.345 +
  54.346 +        @Override
  54.347 +        public boolean traverse(final MethodData methodData) {
  54.348 +            try {
  54.349 +                if (exportedSymbols.isExported(methodData)) {
  54.350 +                    found = methodData;
  54.351 +                    return false;
  54.352 +                }
  54.353 +            } catch (final IOException e) {
  54.354 +            }
  54.355 +
  54.356 +            return true;
  54.357 +        }
  54.358 +
  54.359 +        public MethodData getFound() {
  54.360 +            return found;
  54.361 +        }
  54.362 +    }
  54.363 +
  54.364 +    private static final class Standalone extends VM {
  54.365 +        private Standalone(Appendable out, Bck2Brwsr.Resources resources, StringArray explicitlyExported) {
  54.366 +            super(out, resources, explicitlyExported);
  54.367 +        }
  54.368 +
  54.369 +        @Override
  54.370 +        protected void generatePrologue() throws IOException {
  54.371 +            append("(function VM(global) {var fillInVMSkeleton = function(vm) {");
  54.372 +        }
  54.373 +
  54.374 +        @Override
  54.375 +        protected void generateEpilogue() throws IOException {
  54.376 +            append(
  54.377 +                  "  return vm;\n"
  54.378 +                + "  };\n"
  54.379 +                + "  var extensions = [];\n"
  54.380 +                + "  function mangleClass(name) {\n"
  54.381 +                + "    return name.replace__Ljava_lang_String_2Ljava_lang_CharSequence_2Ljava_lang_CharSequence_2(\n"
  54.382 +                + "      '_', '_1').replace__Ljava_lang_String_2CC('.','_');\n"
  54.383 +                + "  };\n"
  54.384 +                + "  global.bck2brwsr = function() {\n"
  54.385 +                + "    var args = Array.prototype.slice.apply(arguments);\n"
  54.386 +                + "    var resources = {};\n"
  54.387 +                + "    function registerResource(n, a64) {\n"
  54.388 +                + "      var str = atob(a64);\n"
  54.389 +                + "      var arr = [];\n"
  54.390 +                + "      for (var i = 0; i < str.length; i++) {\n"
  54.391 +                + "        var ch = str.charCodeAt(i) & 0xff;\n"
  54.392 +                + "        if (ch > 127) ch -= 256;\n"
  54.393 +                + "        arr.push(ch);\n"
  54.394 +                + "      }\n"
  54.395 +                + "      if (!resources[n]) resources[n] = [arr];\n"
  54.396 +                + "      else resources[n].push(arr);\n"
  54.397 +                + "    }\n"
  54.398 +                + "    var vm = fillInVMSkeleton({ 'registerResource' : registerResource });\n"
  54.399 +                + "    for (var i = 0; i < extensions.length; ++i) {\n"
  54.400 +                + "      extensions[i](vm);\n"
  54.401 +                + "    }\n"
  54.402 +                + "    vm.registerResource = null;\n"
  54.403 +                + "    var knownExtensions = extensions.length;\n"
  54.404 +                + "    var loader = {};\n"
  54.405 +                + "    loader.vm = vm;\n"
  54.406 +                + "    loader.loadClass = function(name) {\n"
  54.407 +                + "      var attr = mangleClass(name);\n"
  54.408 +                + "      var fn = vm[attr];\n"
  54.409 +                + "      if (fn) return fn(false);\n"
  54.410 +                + "      try {\n"
  54.411 +                + "        return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
  54.412 +                + "          load__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
  54.413 +                + "      } catch (err) {\n"
  54.414 +                + "        while (knownExtensions < extensions.length) {\n"
  54.415 +                + "          vm.registerResource = registerResource;\n"
  54.416 +                + "          extensions[knownExtensions++](vm);\n"
  54.417 +                + "          vm.registerResource = null;\n"
  54.418 +                + "        }\n"
  54.419 +                + "        fn = vm[attr];\n"
  54.420 +                + "        if (fn) return fn(false);\n"
  54.421 +                + "        throw err;\n"
  54.422 +                + "      }\n"
  54.423 +                + "    }\n"
  54.424 +                + "    if (vm.loadClass) {\n"
  54.425 +                + "      throw 'Cannot initialize the bck2brwsr VM twice!';\n"
  54.426 +                + "    }\n"
  54.427 +                + "    vm.loadClass = loader.loadClass;\n"
  54.428 +                + "    vm._reload = function(name, byteCode) {;\n"
  54.429 +                + "      var attr = mangleClass(name);\n"
  54.430 +                + "      delete vm[attr];\n"
  54.431 +                + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
  54.432 +                + "        reload__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2_3B(loader, name, args, byteCode);\n"
  54.433 +                + "    };\n"
  54.434 +                + "    vm.loadBytes = function(name, skip) {\n"
  54.435 +                + "      skip = typeof skip == 'number' ? skip : 0;\n"
  54.436 +                + "      var arr = resources[name];\n"
  54.437 +                + "      if (arr) {\n"
  54.438 +                + "        var arrSize = arr.length;\n"
  54.439 +                + "        if (skip < arrSize) return arr[skip];\n"
  54.440 +                + "        skip -= arrSize;\n"
  54.441 +                + "      } else {\n"
  54.442 +                + "        var arrSize = 0;\n"
  54.443 +                + "      };\n"
  54.444 +                + "      var ret = vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
  54.445 +                + "        loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, name, args, skip);\n"
  54.446 +                + "      if (ret !== null) return ret;\n"
  54.447 +                + "      while (knownExtensions < extensions.length) {\n"
  54.448 +                + "        vm.registerResource = registerResource;\n"
  54.449 +                + "        extensions[knownExtensions++](vm);\n"
  54.450 +                + "        vm.registerResource = null;\n"
  54.451 +                + "      }\n"
  54.452 +                + "      var arr = resources[name];\n"
  54.453 +                + "      return (arr && arr.length > arrSize) ? arr[arrSize] : null;\n"
  54.454 +                + "    }\n"
  54.455 +                + "    vm.java_lang_reflect_Array(false);\n"
  54.456 +                + "    vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
  54.457 +                + "      loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, null, args, 0);\n"
  54.458 +                + "    return loader;\n"
  54.459 +                + "  };\n");
  54.460 +            append(
  54.461 +                  "  global.bck2brwsr.registerExtension = function(extension) {\n"
  54.462 +                + "    extensions.push(extension);\n"
  54.463 +                + "    return null;\n"
  54.464 +                + "  };\n");
  54.465 +            append("}(this));");
  54.466 +        }
  54.467 +
  54.468 +        @Override
  54.469 +        protected String getExportsObject() {
  54.470 +            return "vm";
  54.471 +        }
  54.472 +
  54.473 +        @Override
  54.474 +        protected boolean isExternalClass(String className) {
  54.475 +            return false;
  54.476 +        }
  54.477 +    }
  54.478 +
  54.479 +    private static final class Extension extends VM {
  54.480 +        private final StringArray extensionClasses;
  54.481 +
  54.482 +        private Extension(Appendable out, Bck2Brwsr.Resources resources,
  54.483 +                          String[] extClassesArray, StringArray explicitlyExported) {
  54.484 +            super(out, resources, explicitlyExported);
  54.485 +            this.extensionClasses = StringArray.asList(extClassesArray);
  54.486 +        }
  54.487 +
  54.488 +        @Override
  54.489 +        protected void generatePrologue() throws IOException {
  54.490 +            append("bck2brwsr.registerExtension(function(exports) {\n"
  54.491 +                           + "  var vm = {};\n");
  54.492 +            append("  function link(n, inst) {\n"
  54.493 +                           + "    var cls = n['replace__Ljava_lang_String_2CC']"
  54.494 +                                                  + "('/', '_').toString();\n"
  54.495 +                           + "    var dot = n['replace__Ljava_lang_String_2CC']"
  54.496 +                                                  + "('/', '.').toString();\n"
  54.497 +                           + "    exports.loadClass(dot);\n"
  54.498 +                           + "    vm[cls] = exports[cls];\n"
  54.499 +                           + "    return vm[cls](inst);\n"
  54.500 +                           + "  };\n");
  54.501 +        }
  54.502 +
  54.503 +        @Override
  54.504 +        protected void generateEpilogue() throws IOException {
  54.505 +            append("});");
  54.506 +        }
  54.507 +
  54.508 +        @Override
  54.509 +        protected String generateClass(String className) throws IOException {
  54.510 +            if (isExternalClass(className)) {
  54.511 +                append("\n").append(assignClass(
  54.512 +                                            className.replace('/', '_')))
  54.513 +                   .append("function() {\n  return link('")
  54.514 +                   .append(className)
  54.515 +                   .append("', arguments.length == 0 || arguments[0] === true);"
  54.516 +                               + "\n};");
  54.517 +
  54.518 +                return null;
  54.519 +            }
  54.520 +
  54.521 +            return super.generateClass(className);
  54.522 +        }
  54.523 +
  54.524 +        @Override
  54.525 +        protected String getExportsObject() {
  54.526 +            return "exports";
  54.527 +        }
  54.528 +
  54.529 +        @Override
  54.530 +        protected boolean isExternalClass(String className) {
  54.531 +            return !extensionClasses.contains(className);
  54.532 +        }
  54.533      }
  54.534      
  54.535      private static void lazyReference(Appendable out, String n) throws IOException {
    55.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Wed Apr 30 09:26:28 2014 +0200
    55.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Tue May 06 17:46:47 2014 +0200
    55.3 @@ -151,10 +151,5 @@
    55.4          String accessClass(String classOperation) {
    55.5              return "vm." + classOperation;
    55.6          }
    55.7 -
    55.8 -        @Override
    55.9 -        String getVMObject() {
   55.10 -            return "vm";
   55.11 -        }
   55.12      }
   55.13  }
    56.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java	Wed Apr 30 09:26:28 2014 +0200
    56.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Array.java	Tue May 06 17:46:47 2014 +0200
    56.3 @@ -17,6 +17,8 @@
    56.4   */
    56.5  package org.apidesign.vm4brwsr;
    56.6  
    56.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    56.8 +
    56.9  /**
   56.10   *
   56.11   * @author Jaroslav Tulach <jtulach@netbeans.org>
   56.12 @@ -75,6 +77,7 @@
   56.13      }
   56.14      
   56.15      public static double sum() {
   56.16 +        disableClassForName();
   56.17          double sum = 0.0;
   56.18          for (Array[] row : arr()) {
   56.19              int indx = -1;
   56.20 @@ -109,13 +112,50 @@
   56.21      }
   56.22      
   56.23      public static String objectArrayClass() {
   56.24 -        return Object[].class.getName();
   56.25 +        enableClassForName(prevClassForName);
   56.26 +        prevClassForName = null;
   56.27 +        String s = Object[].class.getName();
   56.28 +        disableClassForName();
   56.29 +        return s;
   56.30      }
   56.31      
   56.32      public static boolean instanceOfArray(Object obj) {
   56.33 +        if ("string-array".equals(obj)) {
   56.34 +            obj = new String[] { "Ahoj" };
   56.35 +        }
   56.36          return obj instanceof Object[];
   56.37      }
   56.38      
   56.39 +    public static boolean castArray(int type) {
   56.40 +        try {
   56.41 +            Object orig = new Object();
   56.42 +            Object res = orig;
   56.43 +            if (type == 0) {
   56.44 +                Object[] arr = new Integer[1];
   56.45 +                String[] str = (String[]) arr;
   56.46 +                res = str;
   56.47 +            }
   56.48 +            if (type == 1) {
   56.49 +                Object[] arr = null;
   56.50 +                String[] str = (String[]) arr;
   56.51 +                res = str;
   56.52 +            }
   56.53 +            if (type == 2) {
   56.54 +                Object[] arr = new String[1];
   56.55 +                String[] str = (String[]) arr;
   56.56 +                res = str;
   56.57 +            }
   56.58 +            if (type == 3) {
   56.59 +                Object[] arr = new String[1];
   56.60 +                CharSequence[] str = (CharSequence[]) arr;
   56.61 +                res = str;
   56.62 +            }
   56.63 +            return res != orig;
   56.64 +        } catch (ClassCastException ex) {
   56.65 +            return false;
   56.66 +        }
   56.67 +    }
   56.68 +    
   56.69      public static int sum(int size) {
   56.70          int[] arr = new int[size];
   56.71          return arr[0] + arr[1];
   56.72 @@ -133,6 +173,37 @@
   56.73          return arr[0];
   56.74      }
   56.75      
   56.76 +    @JavaScriptBody(args = {  }, body = 
   56.77 +        "var prev = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2;\n"
   56.78 +      + "if (!prev) throw 'forName not defined';\n"
   56.79 +      + "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2 = function(s) {\n"
   56.80 +      + "  throw 'Do not call me: ' + s;\n"
   56.81 +      + "};\n"
   56.82 +      + "return prev;\n")
   56.83 +    private static Object disableClassForNameImpl() {
   56.84 +        return null;
   56.85 +    }
   56.86 +    
   56.87 +    private static void disableClassForName() {
   56.88 +        if (prevClassForName == null) {
   56.89 +            prevClassForName = disableClassForNameImpl();
   56.90 +        }
   56.91 +    }
   56.92 +    
   56.93 +    @JavaScriptBody(args = { "fn" }, body = 
   56.94 +        "if (fn !== null) vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2 = fn;"
   56.95 +    )
   56.96 +    private static void enableClassForName(Object fn) {
   56.97 +    }
   56.98 +    
   56.99 +    private static Object prevClassForName;
  56.100 +    public static String nameOfClonedComponent() {
  56.101 +        disableClassForName();
  56.102 +        Object[] intArr = new Integer[10];
  56.103 +        intArr = intArr.clone();
  56.104 +        return intArr.getClass().getComponentType().getName();
  56.105 +    }
  56.106 +    
  56.107      public static int multiLen() {
  56.108          return new int[1][0].length;
  56.109      }
    57.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java	Wed Apr 30 09:26:28 2014 +0200
    57.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java	Tue May 06 17:46:47 2014 +0200
    57.3 @@ -43,6 +43,13 @@
    57.4              Double.valueOf(15), true
    57.5          );
    57.6      }
    57.7 +
    57.8 +    @Test public void cloneOnArrayAndComponentType() throws Exception {
    57.9 +        String exp = Array.nameOfClonedComponent();
   57.10 +        assertExec("getComponentType on clone", Array.class, "nameOfClonedComponent__Ljava_lang_String_2", 
   57.11 +            exp
   57.12 +        );
   57.13 +    }
   57.14      
   57.15      @Test public void realOperationOnArrays() throws Exception {
   57.16          assertEquals(Array.sum(), 105.0, "Computes to 105");
   57.17 @@ -75,9 +82,28 @@
   57.18      @Test public void verifyInstanceOfArray() throws Exception {
   57.19          assertExec("Returns 'false'", Array.class, "instanceOfArray__ZLjava_lang_Object_2", Double.valueOf(0), "non-array");
   57.20      }
   57.21 +    @Test public void verifyInstanceOfArrayOnNull() throws Exception {
   57.22 +        assertFalse(Array.instanceOfArray(null), "Null is not an instance of array");
   57.23 +        assertExec("Returns 'false'", Array.class, "instanceOfArray__ZLjava_lang_Object_2", Double.valueOf(0), (Object) null);
   57.24 +    }
   57.25 +    @Test public void verifyInstanceOfArrayStrings() throws Exception {
   57.26 +        assertExec("Returns 'false'", Array.class, "instanceOfArray__ZLjava_lang_Object_2", Double.valueOf(1), "string-array");
   57.27 +    }
   57.28      @Test public void verifyMultiLen() throws Exception {
   57.29          assertExec("Multi len is one", Array.class, "multiLen__I", Double.valueOf(1));
   57.30      }
   57.31 +    @Test public void upCastAnArray() throws Exception {
   57.32 +        assertExec("Cannot cast int to string array", Array.class, "castArray__ZI", Double.valueOf(0), Double.valueOf(0));
   57.33 +    }
   57.34 +    @Test public void upCastANullArray() throws Exception {
   57.35 +        assertExec("Can cast null to string array", Array.class, "castArray__ZI", Double.valueOf(1), Double.valueOf(1));
   57.36 +    }
   57.37 +    @Test public void upCastOK() throws Exception {
   57.38 +        assertExec("Can cast string to string array", Array.class, "castArray__ZI", Double.valueOf(1), Double.valueOf(2));
   57.39 +    }
   57.40 +    @Test public void upCastOK2() throws Exception {
   57.41 +        assertExec("Can cast string to char sequence array", Array.class, "castArray__ZI", Double.valueOf(1), Double.valueOf(3));
   57.42 +    }
   57.43      
   57.44      private static TestVM code;
   57.45      
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumbersAsExtensionTest.java	Tue May 06 17:46:47 2014 +0200
    58.3 @@ -0,0 +1,240 @@
    58.4 +/**
    58.5 + * Back 2 Browser Bytecode Translator
    58.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    58.7 + *
    58.8 + * This program is free software: you can redistribute it and/or modify
    58.9 + * it under the terms of the GNU General Public License as published by
   58.10 + * the Free Software Foundation, version 2 of the License.
   58.11 + *
   58.12 + * This program is distributed in the hope that it will be useful,
   58.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   58.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   58.15 + * GNU General Public License for more details.
   58.16 + *
   58.17 + * You should have received a copy of the GNU General Public License
   58.18 + * along with this program. Look for COPYING file in the top folder.
   58.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   58.20 + */
   58.21 +package org.apidesign.vm4brwsr;
   58.22 +
   58.23 +import javax.script.ScriptEngine;
   58.24 +import static org.testng.Assert.*;
   58.25 +import org.testng.annotations.AfterClass;
   58.26 +import org.testng.annotations.BeforeClass;
   58.27 +import org.testng.annotations.Test;
   58.28 +
   58.29 +/**
   58.30 + *
   58.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   58.32 + */
   58.33 +public class NumbersAsExtensionTest {
   58.34 +    @Test public void integerFromString() throws Exception {
   58.35 +        assertExec("Can convert string to integer", Integer.class, "parseInt__ILjava_lang_String_2",
   58.36 +            Double.valueOf(333), "333"
   58.37 +        );
   58.38 +    }
   58.39 +
   58.40 +    @Test public void doubleFromString() throws Exception {
   58.41 +        assertExec("Can convert string to double", Double.class, "parseDouble__DLjava_lang_String_2",
   58.42 +            Double.valueOf(33.3), "33.3"
   58.43 +        );
   58.44 +    }
   58.45 +
   58.46 +    @Test public void autoboxDouble() throws Exception {
   58.47 +        assertExec("Autoboxing of doubles is OK", Numbers.class, "autoboxDblToString__Ljava_lang_String_2",
   58.48 +            "3.3"
   58.49 +        );
   58.50 +    }
   58.51 +    
   58.52 +    @Test public void javalog1000() throws Exception {
   58.53 +        assertEquals(3.0, Math.log10(1000.0), 0.00003, "log_10(1000) == 3");
   58.54 +    }
   58.55 +
   58.56 +    @Test public void jslog1000() throws Exception {
   58.57 +        assertExec("log_10(1000) == 3", Math.class, "log10__DD", 
   58.58 +            Double.valueOf(3.0), 1000.0
   58.59 +        );
   58.60 +    }
   58.61 +    
   58.62 +    @Test public void javaRem() {
   58.63 +        assertEquals(3, Numbers.rem(303, 10));
   58.64 +    }
   58.65 +    @Test public void jsRem() throws Exception {
   58.66 +        assertExec("Should be three", Numbers.class, "rem__III", 
   58.67 +            Double.valueOf(3.0), 303, 10
   58.68 +        );
   58.69 +    }
   58.70 +    
   58.71 +    @Test public void deserializeInt() throws Exception {
   58.72 +        int exp = Numbers.deserInt();
   58.73 +        assertExec("Should be the same", Numbers.class, "deserInt__I", 
   58.74 +            Double.valueOf(exp)
   58.75 +        );
   58.76 +    }
   58.77 +
   58.78 +    @Test public void deserializeSimpleLong() throws Exception {
   58.79 +        assertExec("Should be 3454", Numbers.class, "deserLong__J_3B", 
   58.80 +            Double.valueOf(3454), 
   58.81 +            new byte[] { (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)13, (byte)126 }
   58.82 +        );
   58.83 +    }
   58.84 +    /* XXX: JavaScript cannot represent as big longs as Java. 
   58.85 +    @Test public void deserializeLargeLong() throws Exception {
   58.86 +        final byte[] arr = new byte[] {
   58.87 +            (byte)64, (byte)8, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0
   58.88 +        };
   58.89 +        long exp = Numbers.deserLong(arr);
   58.90 +        assertExec("Should be " + exp, "org_apidesign_vm4brwsr_Numbers_deserLong__JAB", 
   58.91 +            Double.valueOf(exp), arr);
   58.92 +    }
   58.93 +    */
   58.94 +    
   58.95 +    @Test public void deserializeFloatInJava() throws Exception {
   58.96 +        float f = 54324.32423f;
   58.97 +        float r = Numbers.deserFloat();
   58.98 +        assertEquals(r, f, "Floats are the same");
   58.99 +    }
  58.100 +    
  58.101 +    @Test public void deserializeFloatInJS() throws Exception {
  58.102 +        float f = 54324.32423f;
  58.103 +        assertExec("Should be the same", Numbers.class, "deserFloat__F", 
  58.104 +            Double.valueOf(f)
  58.105 +        );
  58.106 +    }
  58.107 +
  58.108 +    @Test public void deserializeDoubleInJava() throws Exception {
  58.109 +        double f = 3.0;
  58.110 +        double r = Numbers.deserDouble();
  58.111 +        assertEquals(r, f, 0.001, "Doubles are the same");
  58.112 +    }
  58.113 +    
  58.114 +    @Test public void deserializeDoubleInJS() throws Exception {
  58.115 +        double f = 3.0;
  58.116 +        assertExec("Should be the same", Numbers.class, "deserDouble__D", f);
  58.117 +    }
  58.118 +    /*
  58.119 +    @Test public void serDouble() throws IOException {
  58.120 +        double f = 3.0;
  58.121 +        ByteArrayOutputStream os = new ByteArrayOutputStream();
  58.122 +        DataOutputStream d = new DataOutputStream(os);
  58.123 +        d.writeLong(3454);
  58.124 +        d.close();
  58.125 +        
  58.126 +        StringBuilder sb = new StringBuilder();
  58.127 +        byte[] arr = os.toByteArray();
  58.128 +        for (int i = 0; i < arr.length; i++) {
  58.129 +            sb.append("(byte)").append(arr[i]).append(", ");
  58.130 +        }
  58.131 +        fail("" + sb);
  58.132 +    }
  58.133 +*/    
  58.134 +    @Test public void fiveInStringJS() throws Exception {
  58.135 +        String s = Numbers.intToString();
  58.136 +        assertExec("Should be the same: " + s, 
  58.137 +            Numbers.class, "intToString__Ljava_lang_String_2", 
  58.138 +            s
  58.139 +        );
  58.140 +    }
  58.141 +
  58.142 +    @Test public void sevenInStringJS() throws Exception {
  58.143 +        String s = Numbers.floatToString();
  58.144 +        assertExec("Should be the same: " + s, 
  58.145 +            Numbers.class, "floatToString__Ljava_lang_String_2", 
  58.146 +            s
  58.147 +        );
  58.148 +    }
  58.149 +
  58.150 +    @Test public void everyNumberHasJavaLangNumberMethods() throws Exception {
  58.151 +        assertExec("Can we call doubleValue?", 
  58.152 +            Numbers.class, "seven__DI", 
  58.153 +            Double.valueOf(7.0), 0
  58.154 +        );
  58.155 +    }
  58.156 +    @Test public void everyNumberHasJavaLangNumberMethodsInt() throws Exception {
  58.157 +        assertExec("Can we call doubleValue?", 
  58.158 +            Numbers.class, "seven__DI", 
  58.159 +            Double.valueOf(7.0), 1
  58.160 +        );
  58.161 +    }
  58.162 +    @Test public void everyNumberHasJavaLangNumberMethodsLong() throws Exception {
  58.163 +        assertExec("Can we call doubleValue?", 
  58.164 +            Numbers.class, "seven__DI", 
  58.165 +            Double.valueOf(7.0), 2
  58.166 +        );
  58.167 +    }
  58.168 +    @Test public void everyNumberHasJavaLangNumberMethodsShort() throws Exception {
  58.169 +        assertExec("Can we call doubleValue?", 
  58.170 +            Numbers.class, "seven__DI", 
  58.171 +            Double.valueOf(7.0), 3
  58.172 +        );
  58.173 +    }
  58.174 +    @Test public void everyNumberHasJavaLangNumberMethodsByte() throws Exception {
  58.175 +        assertExec("Can we call doubleValue?", 
  58.176 +            Numbers.class, "seven__DI", 
  58.177 +            Double.valueOf(7.0), 4
  58.178 +        );
  58.179 +    }
  58.180 +    @Test public void valueOfNumber() throws Exception {
  58.181 +        assertExec("Can we call JavaScripts valueOf?", 
  58.182 +            Numbers.class, "seven__DI", 
  58.183 +            Double.valueOf(7.0), 8
  58.184 +        );
  58.185 +    }
  58.186 +    @Test public void valueOfLongNumber() throws Exception {
  58.187 +        assertExec("Can we call JavaScripts valueOf?", 
  58.188 +            Numbers.class, "seven__DI", 
  58.189 +            Double.valueOf(Long.MAX_VALUE / 5), 9
  58.190 +        );
  58.191 +    }
  58.192 +    @Test public void valueOfLongCharA() throws Exception {
  58.193 +        assertExec("Can we call JavaScripts valueOf on Character?", 
  58.194 +            Numbers.class, "seven__DI", 
  58.195 +            Double.valueOf('A'), 65
  58.196 +        );
  58.197 +    }
  58.198 +
  58.199 +    @Test public void valueOfLongBooleanTrue() throws Exception {
  58.200 +        assertExec("Can we call JavaScripts valueOf on Boolean?", 
  58.201 +            Numbers.class, "bseven__ZI", 
  58.202 +            true, 31
  58.203 +        );
  58.204 +    }
  58.205 +    @Test public void valueOfLongBooleanFalse() throws Exception {
  58.206 +        assertExec("Can we call JavaScripts valueOf on Boolean?", 
  58.207 +            Numbers.class, "bseven__ZI", 
  58.208 +            false, 30
  58.209 +        );
  58.210 +    }
  58.211 +
  58.212 +    private static TestVM code;
  58.213 +
  58.214 +    @BeforeClass
  58.215 +    public static void compileTheCode() throws Exception {
  58.216 +        ScriptEngine[] eng = { null };
  58.217 +        code = TestVM.compileClassAsExtension(null, eng, "org/apidesign/vm4brwsr/Numbers", null, null);
  58.218 +    }
  58.219 +    @AfterClass
  58.220 +    public static void releaseTheCode() {
  58.221 +        code = null;
  58.222 +    }
  58.223 +
  58.224 +    private static void assertExec(
  58.225 +        String msg, Class<?> clazz, String method, Object expRes, Object... args) throws Exception
  58.226 +    {
  58.227 +        Object ret = code.execCode(msg, clazz, method, expRes, args);
  58.228 +        if (ret == null) {
  58.229 +            return;
  58.230 +        }
  58.231 +        if (expRes instanceof Double && ret instanceof Double) {
  58.232 +            double expD = ((Double)expRes).doubleValue();
  58.233 +            double retD = ((Double)ret).doubleValue();
  58.234 +            assertEquals(retD, expD, 0.000004, msg + " "
  58.235 +                    + code.toString());
  58.236 +            return;
  58.237 +        }
  58.238 +        assertEquals(ret, expRes, msg + " " + code.toString());
  58.239 +    }
  58.240 +
  58.241 +
  58.242 +    
  58.243 +}
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Resources.java	Tue May 06 17:46:47 2014 +0200
    59.3 @@ -0,0 +1,87 @@
    59.4 +/**
    59.5 + * Back 2 Browser Bytecode Translator
    59.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    59.7 + *
    59.8 + * This program is free software: you can redistribute it and/or modify
    59.9 + * it under the terms of the GNU General Public License as published by
   59.10 + * the Free Software Foundation, version 2 of the License.
   59.11 + *
   59.12 + * This program is distributed in the hope that it will be useful,
   59.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   59.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   59.15 + * GNU General Public License for more details.
   59.16 + *
   59.17 + * You should have received a copy of the GNU General Public License
   59.18 + * along with this program. Look for COPYING file in the top folder.
   59.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   59.20 + */
   59.21 +package org.apidesign.vm4brwsr;
   59.22 +
   59.23 +import java.io.IOException;
   59.24 +import java.io.InputStream;
   59.25 +import java.net.URL;
   59.26 +import java.util.Enumeration;
   59.27 +
   59.28 +/**
   59.29 + *
   59.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   59.31 + */
   59.32 +public class Resources {
   59.33 +    public static String loadKO() throws IOException {
   59.34 +        InputStream is = Resources.class.getResourceAsStream("ko.js");
   59.35 +        return readIS(is, false);
   59.36 +    }
   59.37 +    
   59.38 +    static String loadClazz() throws IOException {
   59.39 +        InputStream is = Resources.class.getResourceAsStream("Bck2BrwsrToolkit.class");
   59.40 +        return readIS(is, false);
   59.41 +    }
   59.42 +
   59.43 +    private static String readIS(InputStream is, boolean asString) throws IOException {
   59.44 +        if (is == null) {
   59.45 +            return "No resource found!";
   59.46 +        }
   59.47 +        byte[] arr = new byte[4092];
   59.48 +        int len = is.read(arr);
   59.49 +        if (len < 5) {
   59.50 +            return "No data read! Len: " + len;
   59.51 +        }
   59.52 +        
   59.53 +        if (asString) {
   59.54 +            return new String(arr, 0, len, "UTF-8").toString().toString();
   59.55 +        }
   59.56 +        
   59.57 +        StringBuilder sb = new StringBuilder();
   59.58 +        sb.append("[");
   59.59 +        for (int i = 0; i < len; i++) {
   59.60 +            sb.append(arr[i]).append(", ");
   59.61 +        }
   59.62 +        
   59.63 +        return sb.toString().toString();
   59.64 +    }
   59.65 +    static long bytesToLong(byte b1, byte b2, int shift) {
   59.66 +        return (((long)b1 << 56) +
   59.67 +                ((long)b2 & 255) << 48) >> shift;
   59.68 +    }
   59.69 +
   59.70 +    static String loadHello() throws IOException {
   59.71 +        Enumeration<URL> en;
   59.72 +        try {
   59.73 +            en = Resources.class.getClassLoader().getResources("META-INF/ahoj");
   59.74 +        } catch (SecurityException ex) {
   59.75 +            return "SecurityException";
   59.76 +        }
   59.77 +        StringBuilder sb = new StringBuilder();
   59.78 +        while (en.hasMoreElements()) {
   59.79 +            URL url = en.nextElement();
   59.80 +            sb.append(readIS(url.openStream(), true));
   59.81 +        }
   59.82 +        return sb.toString().toString();
   59.83 +    }
   59.84 +    static String loadJustHello() throws IOException {
   59.85 +        URL url = Resources.class.getResource("/META-INF/ahoj");
   59.86 +        StringBuilder sb = new StringBuilder();
   59.87 +        sb.append(readIS(url.openStream(), true));
   59.88 +        return sb.toString().toString();
   59.89 +    }
   59.90 +}
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ResourcesTest.java	Tue May 06 17:46:47 2014 +0200
    60.3 @@ -0,0 +1,80 @@
    60.4 +/**
    60.5 + * Back 2 Browser Bytecode Translator
    60.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    60.7 + *
    60.8 + * This program is free software: you can redistribute it and/or modify
    60.9 + * it under the terms of the GNU General Public License as published by
   60.10 + * the Free Software Foundation, version 2 of the License.
   60.11 + *
   60.12 + * This program is distributed in the hope that it will be useful,
   60.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   60.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   60.15 + * GNU General Public License for more details.
   60.16 + *
   60.17 + * You should have received a copy of the GNU General Public License
   60.18 + * along with this program. Look for COPYING file in the top folder.
   60.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   60.20 + */
   60.21 +package org.apidesign.vm4brwsr;
   60.22 +
   60.23 +import java.io.UnsupportedEncodingException;
   60.24 +import org.testng.annotations.AfterClass;
   60.25 +import org.testng.annotations.BeforeClass;
   60.26 +import org.testng.annotations.Test;
   60.27 +
   60.28 +/** Tests related to loading resources from the VM.
   60.29 + *
   60.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   60.31 + */
   60.32 +public class ResourcesTest {
   60.33 +    @Test public void loadPrecompiledResource() throws Exception {
   60.34 +        String exp = Resources.loadKO();
   60.35 +        
   60.36 +        assertExec("Loading a precompiled resource:",
   60.37 +            Resources.class, "loadKO__Ljava_lang_String_2", 
   60.38 +            exp
   60.39 +        );
   60.40 +    }
   60.41 +
   60.42 +    @Test public void loadBinaryPrecompiledResource() throws Exception {
   60.43 +        String exp = Resources.loadClazz();
   60.44 +        
   60.45 +        assertExec("Loading a precompiled resource:",
   60.46 +            Resources.class, "loadClazz__Ljava_lang_String_2", 
   60.47 +            exp
   60.48 +        );
   60.49 +    }
   60.50 +    
   60.51 +    private static TestVM code;
   60.52 +    
   60.53 +    @BeforeClass 
   60.54 +    public static void compileTheCode() throws Exception {
   60.55 +        StringBuilder sb = new StringBuilder();
   60.56 +        code = TestVM.compileClassAndResources(sb, null, 
   60.57 +            "org/apidesign/vm4brwsr/Resources", 
   60.58 +            "org/apidesign/vm4brwsr/ko.js",
   60.59 +            "org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class"
   60.60 +        );
   60.61 +    }
   60.62 +    @AfterClass
   60.63 +    public static void releaseTheCode() {
   60.64 +        code = null;
   60.65 +    }
   60.66 +
   60.67 +    private void assertExec(
   60.68 +        String msg, Class<?> clazz, String method, 
   60.69 +        Object ret, Object... args
   60.70 +    ) throws Exception {
   60.71 +        code.assertExec(msg, clazz, method, ret, args);
   60.72 +    }
   60.73 +    
   60.74 +    public static String parseBase64Binary(String s) throws UnsupportedEncodingException {
   60.75 +        final byte[] arr = javax.xml.bind.DatatypeConverter.parseBase64Binary(s);
   60.76 +        StringBuilder sb = new StringBuilder();
   60.77 +        for (int i = 0; i < arr.length; i++) {
   60.78 +            int ch = arr[i];
   60.79 +            sb.append((char)ch);
   60.80 +        }
   60.81 +        return sb.toString();
   60.82 +    }
   60.83 +}
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ResourcesWithExtensionsTest.java	Tue May 06 17:46:47 2014 +0200
    61.3 @@ -0,0 +1,85 @@
    61.4 +/**
    61.5 + * Back 2 Browser Bytecode Translator
    61.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    61.7 + *
    61.8 + * This program is free software: you can redistribute it and/or modify
    61.9 + * it under the terms of the GNU General Public License as published by
   61.10 + * the Free Software Foundation, version 2 of the License.
   61.11 + *
   61.12 + * This program is distributed in the hope that it will be useful,
   61.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   61.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   61.15 + * GNU General Public License for more details.
   61.16 + *
   61.17 + * You should have received a copy of the GNU General Public License
   61.18 + * along with this program. Look for COPYING file in the top folder.
   61.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   61.20 + */
   61.21 +package org.apidesign.vm4brwsr;
   61.22 +
   61.23 +import java.io.UnsupportedEncodingException;
   61.24 +import javax.script.ScriptEngine;
   61.25 +import org.testng.annotations.AfterClass;
   61.26 +import org.testng.annotations.BeforeClass;
   61.27 +import org.testng.annotations.Test;
   61.28 +
   61.29 +/** Tests related to loading resources from the VM.
   61.30 + *
   61.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   61.32 + */
   61.33 +public class ResourcesWithExtensionsTest {
   61.34 +    @Test public void checkHello() throws Exception {
   61.35 +        String exp = "Hello ";
   61.36 +        
   61.37 +        assertExec("Loading a precompiled resource:",
   61.38 +            Resources.class, "loadJustHello__Ljava_lang_String_2", 
   61.39 +            exp
   61.40 +        );
   61.41 +    }
   61.42 +
   61.43 +    @Test public void checkHelloWorld() throws Exception {
   61.44 +        String exp = "Hello World!";
   61.45 +        
   61.46 +        assertExec("Loading precompiled resources:",
   61.47 +            Resources.class, "loadHello__Ljava_lang_String_2", 
   61.48 +            exp
   61.49 +        );
   61.50 +    }
   61.51 +
   61.52 +    private static TestVM code;
   61.53 +    
   61.54 +    @BeforeClass 
   61.55 +    public static void compileTheCode() throws Exception {
   61.56 +        StringBuilder sb = new StringBuilder();
   61.57 +        ScriptEngine[] eng = { null };
   61.58 +        code = TestVM.compileClassAsExtension(sb, eng, 
   61.59 +            "org/apidesign/vm4brwsr/Resources", 
   61.60 +            "META-INF/ahoj", "Hello "
   61.61 +        );
   61.62 +        code = TestVM.compileClassAsExtension(sb, eng, 
   61.63 +            "org/apidesign/vm4brwsr/Resources", 
   61.64 +            "META-INF/ahoj", "World!"
   61.65 +        );
   61.66 +    }
   61.67 +    @AfterClass
   61.68 +    public static void releaseTheCode() {
   61.69 +        code = null;
   61.70 +    }
   61.71 +
   61.72 +    private void assertExec(
   61.73 +        String msg, Class<?> clazz, String method, 
   61.74 +        Object ret, Object... args
   61.75 +    ) throws Exception {
   61.76 +        code.assertExec(msg, clazz, method, ret, args);
   61.77 +    }
   61.78 +    
   61.79 +    public static String parseBase64Binary(String s) throws UnsupportedEncodingException {
   61.80 +        final byte[] arr = javax.xml.bind.DatatypeConverter.parseBase64Binary(s);
   61.81 +        StringBuilder sb = new StringBuilder();
   61.82 +        for (int i = 0; i < arr.length; i++) {
   61.83 +            int ch = arr[i];
   61.84 +            sb.append((char)ch);
   61.85 +        }
   61.86 +        return sb.toString();
   61.87 +    }
   61.88 +}
    62.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Wed Apr 30 09:26:28 2014 +0200
    62.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Tue May 06 17:46:47 2014 +0200
    62.3 @@ -17,6 +17,7 @@
    62.4   */
    62.5  package org.apidesign.vm4brwsr;
    62.6  
    62.7 +import java.io.ByteArrayInputStream;
    62.8  import java.io.File;
    62.9  import java.io.FileWriter;
   62.10  import java.io.IOException;
   62.11 @@ -135,6 +136,82 @@
   62.12              return null;
   62.13          }
   62.14      }
   62.15 +    
   62.16 +    static TestVM compileClassAsExtension(
   62.17 +        StringBuilder sb, ScriptEngine[] eng, 
   62.18 +        String name, final String resourceName, final String resourceContent
   62.19 +    ) throws ScriptException, IOException {
   62.20 +        if (sb == null) {
   62.21 +            sb = new StringBuilder();
   62.22 +        }
   62.23 +        if (eng[0] == null) {
   62.24 +            ScriptEngineManager sem = new ScriptEngineManager();
   62.25 +            ScriptEngine js = sem.getEngineByExtension("js");
   62.26 +            eng[0] = js;
   62.27 +            Bck2Brwsr.generate(sb, new EmulationResources());
   62.28 +        }
   62.29 +        Bck2Brwsr b2b = Bck2Brwsr.newCompiler().
   62.30 +            resources(new EmulationResources() {
   62.31 +                @Override
   62.32 +                public InputStream get(String name) throws IOException {
   62.33 +                    if (name.equals(resourceName)) {
   62.34 +                        return new ByteArrayInputStream(resourceContent.getBytes("UTF-8"));
   62.35 +                    }
   62.36 +                    return super.get(name);
   62.37 +                }
   62.38 +            }).
   62.39 +            addRootClasses(name).library(true);
   62.40 +        if (resourceName != null) {
   62.41 +            b2b = b2b.addResources(resourceName);
   62.42 +        }
   62.43 +        b2b.generate(sb);
   62.44 +        try {
   62.45 +            defineAtoB(eng[0]);
   62.46 +            Object res = eng[0].eval(sb.toString());
   62.47 +            assertTrue(eng[0] instanceof Invocable, "It is invocable object: " + res);
   62.48 +            return new TestVM((Invocable) eng[0], sb);
   62.49 +        } catch (Exception ex) {
   62.50 +            if (sb.length() > 2000) {
   62.51 +                sb = dumpJS(sb);
   62.52 +            }
   62.53 +            fail("Could not evaluate:" + ex.getClass() + ":" + ex.getMessage() + "\n" + sb, ex);
   62.54 +            return null;
   62.55 +        }
   62.56 +    }
   62.57 +    
   62.58 +    static TestVM compileClassAndResources(StringBuilder sb, ScriptEngine[] eng, String name, String... resources) throws ScriptException, IOException {
   62.59 +        if (sb == null) {
   62.60 +            sb = new StringBuilder();
   62.61 +        }
   62.62 +        Bck2Brwsr b2b = Bck2Brwsr.newCompiler().
   62.63 +            resources(new EmulationResources()).
   62.64 +            addRootClasses(name).
   62.65 +            addResources(resources).
   62.66 +            library(false);
   62.67 +        b2b.generate(sb);
   62.68 +        ScriptEngineManager sem = new ScriptEngineManager();
   62.69 +        ScriptEngine js = sem.getEngineByExtension("js");
   62.70 +        if (eng != null) {
   62.71 +            eng[0] = js;
   62.72 +        }
   62.73 +        try {
   62.74 +            defineAtoB(js);
   62.75 +            
   62.76 +            Object res = js.eval(sb.toString());
   62.77 +            assertTrue(js instanceof Invocable, "It is invocable object: " + res);
   62.78 +            return new TestVM((Invocable) js, sb);
   62.79 +        } catch (Exception ex) {
   62.80 +            if (sb.length() > 2000) {
   62.81 +                sb = dumpJS(sb);
   62.82 +            }
   62.83 +            fail("Could not evaluate:" + ex.getClass() + ":" + ex.getMessage() + "\n" + sb, ex);
   62.84 +            return null;
   62.85 +        }
   62.86 +    }
   62.87 +
   62.88 +    private static void defineAtoB(ScriptEngine js) throws ScriptException {
   62.89 +        js.eval("atob = function(s) { return new String(org.apidesign.vm4brwsr.ResourcesTest.parseBase64Binary(s)); }");
   62.90 +    }
   62.91  
   62.92      Object loadClass(String loadClass, String name) throws ScriptException, NoSuchMethodException {
   62.93          return code.invokeMethod(bck2brwsr, "loadClass", Exceptions.class.getName());
    63.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java	Wed Apr 30 09:26:28 2014 +0200
    63.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java	Tue May 06 17:46:47 2014 +0200
    63.3 @@ -43,9 +43,4 @@
    63.4      @Override
    63.5      protected void requireScript(String resourcePath) {
    63.6      }
    63.7 -
    63.8 -    @Override
    63.9 -    String getVMObject() {
   63.10 -        return "global";
   63.11 -    }
   63.12  }
    64.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java	Wed Apr 30 09:26:28 2014 +0200
    64.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java	Tue May 06 17:46:47 2014 +0200
    64.3 @@ -43,6 +43,7 @@
    64.4      private final boolean fail;
    64.5      private final HtmlFragment html;
    64.6      private final Http.Resource[] http;
    64.7 +    private final InvocationContext c;
    64.8      Object value;
    64.9  
   64.10      Bck2BrwsrCase(Method m, String type, Launcher l, boolean fail, HtmlFragment html, Http.Resource[] http) {
   64.11 @@ -52,12 +53,12 @@
   64.12          this.fail = fail;
   64.13          this.html = html;
   64.14          this.http = http;
   64.15 +        this.c = l != null ? l.createInvocation(m.getDeclaringClass(), m.getName()) : null;
   64.16      }
   64.17  
   64.18      @Test(groups = "run")
   64.19      public void executeCode() throws Throwable {
   64.20          if (l != null) {
   64.21 -            InvocationContext c = l.createInvocation(m.getDeclaringClass(), m.getName());
   64.22              if (html != null) {
   64.23                  c.setHtmlFragment(html.value());
   64.24              }