Merging the closure branch as it seems to be in a state when it is ready to work and not break anything
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 }