# HG changeset patch
# User Jaroslav Tulach
# Date 1410625985 -7200
# Node ID e709c530c2276df3966ed7daf63e19c779c0609a
# Parent 7a9492920b6122ed6cf85abccfb7dc360249fc4c# Parent baa80d712c776b28cabfab4134e171fa9e5d1215
Lambda's work OK in AOT mode. Defender methods work OK. Merging.
diff -r 7a9492920b61 -r e709c530c227 launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java
--- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java Tue Sep 09 12:45:22 2014 +0200
+++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java Sat Sep 13 18:33:05 2014 +0200
@@ -77,26 +77,9 @@
}
if (s != null) {
File root = new File(s);
- List arr = new ArrayList<>();
- List classes = new ArrayList<>();
- listDir(root, null, classes, arr);
StringWriter w = new StringWriter();
try {
- Bck2Brwsr.newCompiler()
- .addRootClasses(classes.toArray(new String[0]))
- .addResources(arr.toArray(new String[0]))
- .library()
- //.obfuscation(ObfuscationLevel.FULL)
- .resources(new EmulationResources() {
- @Override
- public InputStream get(String resource) throws IOException {
- if (r != null) {
- final URL url = r.get(resource, 0);
- return url == null ? null : url.openStream();
- }
- return super.get(resource);
- }
- })
+ Bck2BrwsrJars.configureFrom(null, root)
.generate(w);
w.flush();
return w.toString();
@@ -109,23 +92,6 @@
return null;
}
-
- private static void listDir(File f, String pref, List classes, List resources) throws IOException {
- File[] arr = f.listFiles();
- if (arr == null) {
- if (f.getName().endsWith(".class")) {
- classes.add(pref + f.getName().substring(0, f.getName().length() - 6));
- } else {
- resources.add(pref + f.getName());
- }
- } else {
- for (File ch : arr) {
-
- listDir(ch, pref == null ? "" : pref + f.getName() + "/", classes, resources);
- }
- }
- }
-
static void compileVM(StringBuilder sb, final Res r) throws IOException {
final Bck2Brwsr rt;
try {
@@ -155,26 +121,4 @@
}
}).generate(sb);
}
-
- static class EmulationResources implements Bck2Brwsr.Resources {
-
- @Override
- public InputStream get(String name) throws IOException {
- Enumeration en = Bck2BrwsrJars.class.getClassLoader().getResources(name);
- URL u = null;
- while (en.hasMoreElements()) {
- u = en.nextElement();
- }
- if (u == null) {
- LOG.log(Level.WARNING, "Cannot find {0}", name);
- return null;
- }
- if (u.toExternalForm().contains("/rt.jar!")) {
- LOG.log(Level.WARNING, "{0}No bootdelegation for ", name);
- return null;
- }
- return u.openStream();
- }
- }
-
}
diff -r 7a9492920b61 -r e709c530c227 rt/aot/pom.xml
--- a/rt/aot/pom.xml Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/aot/pom.xml Sat Sep 13 18:33:05 2014 +0200
@@ -27,5 +27,11 @@
${project.version}jar
+
+ net.orfjackal.retrolambda
+ retrolambda
+ 1.6.1
+ jar
+
diff -r 7a9492920b61 -r e709c530c227 rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/Bck2BrwsrJars.java
--- a/rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/Bck2BrwsrJars.java Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/Bck2BrwsrJars.java Sat Sep 13 18:33:05 2014 +0200
@@ -18,15 +18,19 @@
package org.apidesign.bck2brwsr.aot;
import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -43,7 +47,7 @@
*/
public final class Bck2BrwsrJars {
private static final Logger LOG = Logger.getLogger(Bck2BrwsrJars.class.getName());
-
+
private Bck2BrwsrJars() {
}
@@ -64,24 +68,30 @@
* @throws IOException if something goes wrong
*/
public static Bck2Brwsr configureFrom(Bck2Brwsr c, File jar) throws IOException {
+ if (jar.isDirectory()) {
+ return configureDir(c, jar);
+ }
final JarFile jf = new JarFile(jar);
- List classes = new ArrayList<>();
+ final List classes = new ArrayList<>();
List resources = new ArrayList<>();
Set exported = new HashSet<>();
-
- listJAR(jf, classes, resources, exported);
-
- String cp = jf.getManifest().getMainAttributes().getValue("Class-Path"); // NOI18N
- String[] classpath = cp == null ? new String[0] : cp.split(" ");
-
class JarRes extends EmulationResources implements Bck2Brwsr.Resources {
-
+ JarRes() {
+ super(classes);
+ }
@Override
public InputStream get(String resource) throws IOException {
InputStream is = jf.getInputStream(new ZipEntry(resource));
return is == null ? super.get(resource) : is;
}
}
+ JarRes jarRes = new JarRes();
+
+ listJAR(jf, jarRes, resources, exported);
+
+ String cp = jf.getManifest().getMainAttributes().getValue("Class-Path"); // NOI18N
+ String[] classpath = cp == null ? new String[0] : cp.split(" ");
+
if (c == null) {
c = Bck2Brwsr.newCompiler();
}
@@ -91,11 +101,11 @@
.addClasses(classes.toArray(new String[classes.size()]))
.addExported(exported.toArray(new String[exported.size()]))
.addResources(resources.toArray(new String[resources.size()]))
- .resources(new JarRes());
+ .resources(jarRes);
}
private static void listJAR(
- JarFile j, List classes,
+ JarFile j, EmulationResources classes,
List resources, Set keep
) throws IOException {
Enumeration en = j.entries();
@@ -114,7 +124,7 @@
keep.add(pkg);
}
if (n.endsWith(".class")) {
- classes.add(n.substring(0, n.length() - 6));
+ classes.addClassResource(n);
} else {
resources.add(n);
if (n.startsWith("META-INF/services/") && keep != null) {
@@ -142,11 +152,59 @@
}
}
}
+
+ static byte[] readFrom(InputStream is) throws IOException {
+ int expLen = is.available();
+ if (expLen < 1) {
+ expLen = 1;
+ }
+ byte[] arr = new byte[expLen];
+ int pos = 0;
+ for (;;) {
+ int read = is.read(arr, pos, arr.length - pos);
+ if (read == -1) {
+ break;
+ }
+ pos += read;
+ if (pos == arr.length) {
+ byte[] tmp = new byte[arr.length * 2];
+ System.arraycopy(arr, 0, tmp, 0, arr.length);
+ arr = tmp;
+ }
+ }
+ if (pos != arr.length) {
+ byte[] tmp = new byte[pos];
+ System.arraycopy(arr, 0, tmp, 0, pos);
+ arr = tmp;
+ }
+ return arr;
+ }
+
static class EmulationResources implements Bck2Brwsr.Resources {
+ private final List classes;
+ private final Map converted = new HashMap<>();
+ private final BytecodeProcessor proc;
+
+ protected EmulationResources(List classes) {
+ this.classes = classes;
+ BytecodeProcessor p;
+ try {
+ Class> bpClass = Class.forName("org.apidesign.bck2brwsr.aot.RetroLambda");
+ p = (BytecodeProcessor) bpClass.newInstance();
+ } catch (Throwable t) {
+ p = null;
+ }
+ this.proc = p;
+ }
@Override
public InputStream get(String name) throws IOException {
+ byte[] arr = converted.get(name);
+ if (arr != null) {
+ return new ByteArrayInputStream(arr);
+ }
+
Enumeration en = Bck2BrwsrJars.class.getClassLoader().getResources(name);
URL u = null;
while (en.hasMoreElements()) {
@@ -162,6 +220,83 @@
}
return u.openStream();
}
+
+ private void addClassResource(String n) throws IOException {
+ if (proc != null) {
+ try (InputStream is = this.get(n)) {
+ Map conv = proc.process(n, readFrom(is), this);
+ if (conv != null) {
+ boolean found = false;
+ for (Map.Entry entrySet : conv.entrySet()) {
+ String res = entrySet.getKey();
+ byte[] bytes = entrySet.getValue();
+ if (res.equals(n)) {
+ found = true;
+ }
+ assert res.endsWith(".class") : "Wrong resource: " + res;
+ converted.put(res, bytes);
+ classes.add(res.substring(0, res.length() - 6));
+ }
+ if (!found) {
+ throw new IOException("Cannot find " + n + " among " + conv);
+ }
+ return;
+ }
+ }
+ }
+ classes.add(n.substring(0, n.length() - 6));
+ }
+ }
+
+ private static Bck2Brwsr configureDir(Bck2Brwsr c, final File dir) throws IOException {
+ List arr = new ArrayList<>();
+ List classes = new ArrayList<>();
+ class DirRes extends EmulationResources {
+ public DirRes(List classes) {
+ super(classes);
+ }
+
+ @Override
+ public InputStream get(String name) throws IOException {
+ InputStream is = super.get(name);
+ if (is != null) {
+ return is;
+ }
+ File r = new File(dir, name.replace('/', File.separatorChar));
+ if (r.exists()) {
+ return new FileInputStream(r);
+ }
+ return null;
+ }
+ }
+ DirRes dirRes = new DirRes(classes);
+ listDir(dir, null, dirRes, arr);
+ if (c == null) {
+ c = Bck2Brwsr.newCompiler();
+ }
+ return c
+ .addRootClasses(classes.toArray(new String[0]))
+ .addResources(arr.toArray(new String[0]))
+ .library()
+ //.obfuscation(ObfuscationLevel.FULL)
+ .resources(dirRes);
+ }
+
+ private static void listDir(
+ File f, String pref, EmulationResources res, List resources
+ ) throws IOException {
+ File[] arr = f.listFiles();
+ if (arr == null) {
+ if (f.getName().endsWith(".class")) {
+ res.addClassResource(pref + f.getName());
+ } else {
+ resources.add(pref + f.getName());
+ }
+ } else {
+ for (File ch : arr) {
+ listDir(ch, pref == null ? "" : pref + f.getName() + "/", res, resources);
+ }
+ }
}
}
diff -r 7a9492920b61 -r e709c530c227 rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/BytecodeProcessor.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/BytecodeProcessor.java Sat Sep 13 18:33:05 2014 +0200
@@ -0,0 +1,40 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012 Jaroslav Tulach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://opensource.org/licenses/GPL-2.0.
+ */
+package org.apidesign.bck2brwsr.aot;
+
+import java.io.IOException;
+import java.util.Map;
+import org.apidesign.vm4brwsr.Bck2Brwsr;
+
+/** Replace bytecode of a single class with many new bytecodes.
+ *
+ * @author Jaroslav Tulach
+ */
+interface BytecodeProcessor {
+ /** Does the conversion.
+ *
+ * @param className the resource of the class to replace
+ * @param byteCode the bytecode of the class
+ * @param resources access to other resources in the system
+ * @return map of resource to bytecode which must include at least
+ * one element of name className
+ * @throws IOException
+ */
+ public Map process(String className, byte[] byteCode, Bck2Brwsr.Resources resources)
+ throws IOException;
+}
diff -r 7a9492920b61 -r e709c530c227 rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/RetroLambda.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/RetroLambda.java Sat Sep 13 18:33:05 2014 +0200
@@ -0,0 +1,125 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012 Jaroslav Tulach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://opensource.org/licenses/GPL-2.0.
+ */
+package org.apidesign.bck2brwsr.aot;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import net.orfjackal.retrolambda.LambdaClassBackporter;
+import net.orfjackal.retrolambda.LambdaClassDumper;
+import net.orfjackal.retrolambda.LambdaClassSaver;
+import net.orfjackal.retrolambda.LambdaReifier;
+import net.orfjackal.retrolambda.LambdaUsageBackporter;
+import net.orfjackal.retrolambda.asm.Opcodes;
+import org.apidesign.bck2brwsr.core.ExtraJavaScript;
+import org.apidesign.vm4brwsr.Bck2Brwsr;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ExtraJavaScript(processByteCode = false, resource="")
+final class RetroLambda extends LambdaClassSaver implements BytecodeProcessor {
+ private Map converted;
+
+ public RetroLambda() {
+ super(null, Opcodes.V1_7);
+ }
+
+ @Override
+ public void saveIfLambda(String className, byte[] bytecode) {
+ if (LambdaReifier.isLambdaClassToReify(className)) {
+ try {
+ byte[] backportedBytecode = LambdaClassBackporter.transform(bytecode, Opcodes.V1_7);
+ putBytecode(className + ".class", backportedBytecode);
+ } catch (Throwable t) {
+ // print to stdout to keep in sync with other log output
+ throw new IllegalStateException("ERROR: Failed to backport lambda class: " + className);
+ }
+ }
+ }
+
+ private void putBytecode(String className, byte[] backportedBytecode) {
+ assert className.endsWith(".class") : "Full resource: " + className;
+ if (converted == null) {
+ converted = new HashMap<>();
+ }
+ converted.put(className, backportedBytecode);
+ }
+
+ @Override
+ public Map process(
+ String className, byte[] byteCode, Bck2Brwsr.Resources resources
+ ) throws IOException {
+ int minor = byteCode[4] << 8 | byteCode[5];
+ int major = byteCode[6] << 8 | byteCode[7];
+ if (major <= 51) {
+ return null;
+ }
+
+ ClassLoader prev = Thread.currentThread().getContextClassLoader();
+ try (LambdaClassDumper dumper = new LambdaClassDumper(this)) {
+ Thread.currentThread().setContextClassLoader(new ResLdr(resources));
+ dumper.install();
+
+ byte[] newB = LambdaUsageBackporter.transform(byteCode, Opcodes.V1_7);
+ if (!Arrays.equals(newB, byteCode)) {
+ putBytecode(className, newB);
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ } finally {
+ Thread.currentThread().setContextClassLoader(prev);
+ }
+
+ Map ret = converted;
+ converted = null;
+ return ret;
+ }
+
+ private static final class ResLdr extends ClassLoader {
+ private final Bck2Brwsr.Resources res;
+
+ public ResLdr(Bck2Brwsr.Resources res) {
+ this.res = res;
+ }
+
+ @Override
+ public Class> loadClass(String name) throws ClassNotFoundException {
+ Class> c = findLoadedClass(name);
+ if (c != null) {
+ return c;
+ }
+ if (name.startsWith("java.")) {
+ return super.loadClass(name);
+ }
+ String r = name.replace('.', '/') + ".class";
+ try (InputStream is = res.get(r)) {
+ if (is == null) {
+ throw new ClassNotFoundException(name);
+ }
+ byte[] arr = Bck2BrwsrJars.readFrom(is);
+ return defineClass(name, arr, 0, arr.length);
+ } catch (IOException e) {
+ return super.loadClass(name);
+ }
+ }
+ }
+}
diff -r 7a9492920b61 -r e709c530c227 rt/emul/mini/src/main/java/java/lang/Class.java
--- a/rt/emul/mini/src/main/java/java/lang/Class.java Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/emul/mini/src/main/java/java/lang/Class.java Sat Sep 13 18:33:05 2014 +0200
@@ -94,6 +94,11 @@
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;
+ /* Backing store of user-defined values pertaining to this class.
+ * Maintained by the ClassValue class.
+ */
+ transient Object classValueMap;
+
/*
* Constructor. Only the Java Virtual Machine creates Class
* objects.
diff -r 7a9492920b61 -r e709c530c227 rt/emul/mini/src/main/java/java/lang/ClassLoader.java
--- a/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Sat Sep 13 18:33:05 2014 +0200
@@ -499,13 +499,13 @@
* @since 1.1
*/
protected final Class> findLoadedClass(String name) {
- if (!checkName(name))
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException ex) {
return null;
- return findLoadedClass0(name);
+ }
}
- private native final Class findLoadedClass0(String name);
-
/**
* Sets the signers of a class. This should be invoked after defining a
* class.
@@ -884,10 +884,6 @@
return false;
}
- private boolean checkName(String name) {
- throw new UnsupportedOperationException();
- }
-
private Class findBootstrapClassOrNull(String name) {
throw new UnsupportedOperationException();
}
diff -r 7a9492920b61 -r e709c530c227 rt/emul/mini/src/main/java/java/lang/NoSuchMethodError.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/emul/mini/src/main/java/java/lang/NoSuchMethodError.java Sat Sep 13 18:33:05 2014 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown if an application tries to call a specified method of a
+ * class (either static or instance), and that class no longer has a
+ * definition of that method.
+ *
+ * Normally, this error is caught by the compiler; this error can
+ * only occur at run time if the definition of a class has
+ * incompatibly changed.
+ *
+ * @author unascribed
+ * @since JDK1.0
+ */
+public
+class NoSuchMethodError extends IncompatibleClassChangeError {
+ private static final long serialVersionUID = -3765521442372831335L;
+
+ /**
+ * Constructs a NoSuchMethodError with no detail message.
+ */
+ public NoSuchMethodError() {
+ super();
+ }
+
+ /**
+ * Constructs a NoSuchMethodError with the
+ * specified detail message.
+ *
+ * @param s the detail message.
+ */
+ public NoSuchMethodError(String s) {
+ super(s);
+ }
+}
diff -r 7a9492920b61 -r e709c530c227 rt/emul/mini/src/main/java/java/lang/VirtualMachineError.java
--- a/rt/emul/mini/src/main/java/java/lang/VirtualMachineError.java Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/emul/mini/src/main/java/java/lang/VirtualMachineError.java Sat Sep 13 18:33:05 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,8 +33,9 @@
* @author Frank Yellin
* @since JDK1.0
*/
-abstract public
-class VirtualMachineError extends Error {
+abstract public class VirtualMachineError extends Error {
+ private static final long serialVersionUID = 4161983926571568670L;
+
/**
* Constructs a VirtualMachineError with no detail message.
*/
@@ -46,9 +47,43 @@
* Constructs a VirtualMachineError with the specified
* detail message.
*
- * @param s the detail message.
+ * @param message the detail message.
*/
- public VirtualMachineError(String s) {
- super(s);
+ public VirtualMachineError(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a {@code VirtualMachineError} with the specified
+ * detail message and cause.
Note that the detail message
+ * associated with {@code cause} is not automatically
+ * incorporated in this error's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A {@code null} value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.8
+ */
+ public VirtualMachineError(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs an a {@code VirtualMachineError} with the specified
+ * cause and a detail message of {@code (cause==null ? null :
+ * cause.toString())} (which typically contains the class and
+ * detail message of {@code cause}).
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A {@code null} value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.8
+ */
+ public VirtualMachineError(Throwable cause) {
+ super(cause);
}
}
diff -r 7a9492920b61 -r e709c530c227 rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java
--- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Sat Sep 13 18:33:05 2014 +0200
@@ -53,7 +53,7 @@
+ "var arr = new Array();\n"
+ "function check(m, verify) {\n"
+ " if (m.indexOf(prefix) === 0) {\n"
- + " if (!c[m].cls) return;\n"
+ + " if (!c[m] || !c[m].cls) return;\n"
+ " if (verify) {\n"
+ " for (var i = 0; i < arr.length; i += 3) {\n"
+ " if (arr[i] === m) return;\n"
diff -r 7a9492920b61 -r e709c530c227 rt/pom.xml
--- a/rt/pom.xml Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/pom.xml Sat Sep 13 18:33:05 2014 +0200
@@ -19,4 +19,14 @@
vmtestaot
+
+
+
+ 1.8
+
+
+ vm8
+
+
+
diff -r 7a9492920b61 -r e709c530c227 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Sat Sep 13 18:33:05 2014 +0200
@@ -28,6 +28,7 @@
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Arrays;
import org.apidesign.bck2brwsr.core.JavaScriptBody;
import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
@@ -58,6 +59,9 @@
public static final int CONSTANT_METHOD = 10;
public static final int CONSTANT_INTERFACEMETHOD = 11;
public static final int CONSTANT_NAMEANDTYPE = 12;
+ public static final int CONSTANT_METHODHANDLE = 15;
+ public static final int CONSTANT_METHODTYPE = 16;
+ public static final int CONSTANT_INVOKEDYNAMIC = 18;
/* Access Flags */
public static final int ACC_PUBLIC = 0x00000001;
@@ -287,7 +291,7 @@
public static final int opc_invokespecial = 183;
public static final int opc_invokestatic = 184;
public static final int opc_invokeinterface = 185;
-// public static final int opc_xxxunusedxxx = 186;
+ public static final int opc_invokedynamic = 186;
public static final int opc_new = 187;
public static final int opc_newarray = 188;
public static final int opc_anewarray = 189;
@@ -495,7 +499,7 @@
*/
private static class CPX {
- int cpx;
+ final int cpx;
CPX(int cpx) {
this.cpx = cpx;
@@ -507,9 +511,9 @@
*
* @author Sucheta Dambalkar (Adopted code from jdis)
*/
- private static class CPX2 {
+ static class CPX2 {
- int cpx1, cpx2;
+ final int cpx1, cpx2;
CPX2(int cpx1, int cpx2) {
this.cpx1 = cpx1;
@@ -538,6 +542,7 @@
private FieldData[] fields;
private MethodData[] methods;
private InnerClassData[] innerClasses;
+ private BootMethodData[] bootMethods;
private int attributes_count;
private AttrData[] attrs;
private int source_cpx = 0;
@@ -621,6 +626,12 @@
AttrData attr = new AttrData(this);
attr.read(name_cpx);
attrs[k] = attr;
+ } else if (getTag(name_cpx) == CONSTANT_UTF8
+ && getString(name_cpx).equals("BootstrapMethods")) {
+ AttrData attr = new AttrData(this);
+ bootMethods = readBootstrapMethods(in);
+ attr.read(name_cpx);
+ attrs[k] = attr;
} else {
AttrData attr = new AttrData(this);
attr.read(name_cpx, in);
@@ -630,6 +641,22 @@
in.close();
} // end ClassData.read()
+ BootMethodData[] readBootstrapMethods(DataInputStream in) throws IOException {
+ int attr_len = in.readInt(); //attr_lengt
+ int number = in.readShort();
+ BootMethodData[] arr = new BootMethodData[number];
+ for (int i = 0; i < number; i++) {
+ int ref = in.readShort();
+ int len = in.readShort();
+ int[] args = new int[len];
+ for (int j = 0; j < len; j++) {
+ args[j] = in.readShort();
+ }
+ arr[i] = new BootMethodData(this, ref, args);
+ }
+ return arr;
+ }
+
/**
* Reads and stores constant pool info.
*/
@@ -668,7 +695,15 @@
case CONSTANT_NAMEANDTYPE:
cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
break;
-
+ case CONSTANT_METHODHANDLE:
+ cpool[i] = new CPX2(in.readByte(), in.readUnsignedShort());
+ break;
+ case CONSTANT_METHODTYPE:
+ cpool[i] = new CPX(in.readUnsignedShort());
+ break;
+ case CONSTANT_INVOKEDYNAMIC:
+ cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
+ break;
case 0:
default:
throw new ClassFormatError("invalid constant type: " + (int) tags[i]);
@@ -1107,8 +1142,12 @@
case CONSTANT_NAMEANDTYPE:
return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2);
+ case CONSTANT_METHODHANDLE:
+ return "K" + ((CPX2)x).cpx1 + "@" + stringValue(((CPX2)x).cpx2, textual);
+ case CONSTANT_METHODTYPE:
+ return stringValue(((CPX)x).cpx, true);
default:
- return "UnknownTag"; //TBD
+ return "UnknownTag" + tag; //TBD
}
}
@@ -1191,6 +1230,10 @@
return null;
}
}
+
+ public BootMethodData getBootMethod(int indx) {
+ return bootMethods != null ? bootMethods[indx] : null;
+ }
/**
* Returns total constant pool entry count.
@@ -1549,6 +1592,31 @@
return accflags;
}
} // end InnerClassData
+
+ static class BootMethodData {
+ private final ClassData clazz;
+ final int method;
+ private final int[] args;
+
+ private BootMethodData(ClassData clazz, int method, int[] args) {
+ this.clazz = clazz;
+ this.method = method;
+ this.args = args;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(clazz.stringValue(method, true));
+ sb.append('(');
+ for (int indx : args) {
+ sb.append("\n ");
+ sb.append(clazz.stringValue(indx, true));
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+ }
/**
* Strores LineNumberTable data information.
@@ -1800,7 +1868,7 @@
stackMap[i] = new StackMapData(in, this);
}
}
-
+
/**
* Return access of the method.
*/
diff -r 7a9492920b61 -r e709c530c227 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sat Sep 13 18:33:05 2014 +0200
@@ -19,7 +19,7 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.Locale;
+import org.apidesign.bck2brwsr.core.JavaScriptBody;
import static org.apidesign.vm4brwsr.ByteCodeParser.*;
/** Translator of the code inside class files to JavaScript.
@@ -258,9 +258,22 @@
append("\n ").append(destObject).append(".").append(mn).append(".cls = CLS;");
}
append("\n c.constructor = CLS;");
- append("\n function fillInstOf(x) {");
+ append("\n function ").append(className).append("fillInstOf(x) {");
String instOfName = "$instOf_" + className;
append("\n Object.defineProperty(x, '").append(instOfName).append("', { value : true });");
+ if (jc.isInterface()) {
+ for (MethodData m : jc.getMethods()) {
+ if ((m.getAccess() & ACC_ABSTRACT) == 0
+ && (m.getAccess() & ACC_STATIC) == 0
+ && (m.getAccess() & ACC_PRIVATE) == 0) {
+ final String mn = findMethodName(m, new StringBuilder());
+ append("\n try {");
+ append("\n if (!x['").append(mn).append("']) Object.defineProperty(x, '").append(mn).append("', { value : c['").append(mn).append("']});");
+ append("\n } catch (ignore) {");
+ append("\n }");
+ }
+ }
+ }
for (String superInterface : jc.getSuperInterfaces()) {
String intrfc = superInterface.replace('/', '_');
append("\n vm.").append(intrfc).append("(false)['fillInstOf'](x);");
@@ -268,8 +281,8 @@
}
append("\n }");
append("\n try {");
- append("\n Object.defineProperty(c, 'fillInstOf', { value: fillInstOf });");
- append("\n fillInstOf(c);");
+ append("\n Object.defineProperty(c, 'fillInstOf', { value: ").append(className).append("fillInstOf });");
+ append("\n ").append(className).append("fillInstOf(c);");
append("\n } catch (ignore) {");
append("\n }");
// obfuscationDelegate.exportJSProperty(this, "c", instOfName);
@@ -1051,6 +1064,49 @@
case opc_invokestatic:
i = invokeStaticMethod(byteCodes, i, smapper, true);
break;
+ case opc_invokedynamic: {
+ int indx = readUShortArg(byteCodes, i);
+ println("invoke dynamic: " + indx);
+ ByteCodeParser.CPX2 c2 = jc.getCpoolEntry(indx);
+ BootMethodData bm = jc.getBootMethod(c2.cpx1);
+ CPX2 methodHandle = jc.getCpoolEntry(bm.method);
+ println(" type: " + methodHandle.cpx1);
+ String[] mi = jc.getFieldInfoName(methodHandle.cpx2);
+ String mcn = mangleClassName(mi[0]);
+ char[] returnType = {'V'};
+ StringBuilder cnt = new StringBuilder();
+ String mn = findMethodName(mi, cnt, returnType);
+ println(" mi[0]: " + mi[0]);
+ println(" mi[1]: " + mi[1]);
+ println(" mi[2]: " + mi[2]);
+ println(" mn : " + mn);
+ println(" name and type: " + jc.stringValue(c2.cpx2, true));
+ CPX2 nameAndType = jc.getCpoolEntry(c2.cpx2);
+ String type = jc.StringValue(nameAndType.cpx2);
+ String object = accessClass(mcn) + "(false)";
+ if (mn.startsWith("cons_")) {
+ object += ".constructor";
+ }
+ append("var metHan = ");
+ append(accessStaticMethod(object, mn, mi));
+ append('(');
+ String lookup = accessClass("java_lang_invoke_MethodHandles") + "(false).findFor__Ljava_lang_invoke_MethodHandles$Lookup_2Ljava_lang_Class_2(CLS.$class)";
+ append(lookup);
+ append(", '").append(mi[1]).append("', ");
+ String methodType = accessClass("java_lang_invoke_MethodType") + "(false).fromMethodDescriptorString__Ljava_lang_invoke_MethodType_2Ljava_lang_String_2Ljava_lang_ClassLoader_2(";
+ append(methodType).append("'").append(type).append("', null)");
+// if (numArguments > 0) {
+// append(vars[0]);
+// for (int j = 1; j < numArguments; ++j) {
+// append(", ");
+// append(vars[j]);
+// }
+// }
+ append(");");
+ emit(smapper, this, "throw 'Invoke dynamic: ' + @1 + ': ' + metHan;", "" + indx);
+ i += 4;
+ break;
+ }
case opc_new: {
int indx = readUShortArg(byteCodes, i);
String ci = jc.getClassName(indx);
@@ -1557,7 +1613,7 @@
sb.append(ch);
} else {
sb.append("_0");
- String hex = Integer.toHexString(ch).toLowerCase(Locale.ENGLISH);
+ String hex = Integer.toHexString(ch).toLowerCase();
for (int m = hex.length(); m < 4; m++) {
sb.append("0");
}
@@ -2310,4 +2366,9 @@
append(Integer.toString(cc));
}
}
+
+ @JavaScriptBody(args = "msg", body = "")
+ private static void println(String msg) {
+ System.err.println(msg);
+ }
}
diff -r 7a9492920b61 -r e709c530c227 rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java
--- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Tue Sep 09 12:45:22 2014 +0200
+++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Sat Sep 13 18:33:05 2014 +0200
@@ -123,10 +123,18 @@
}
static TestVM compileClass(StringBuilder sb, ScriptEngine[] eng, String... names) throws ScriptException, IOException {
+ return compileClass(sb, eng, new EmulationResources(), names);
+ }
+ static TestVM compileClass(
+ StringBuilder sb,
+ ScriptEngine[] eng,
+ Bck2Brwsr.Resources resources,
+ String... names
+ ) throws ScriptException, IOException {
if (sb == null) {
sb = new StringBuilder();
}
- Bck2Brwsr.generate(sb, new EmulationResources(), names);
+ Bck2Brwsr.generate(sb, resources, names);
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine js = sem.getEngineByExtension("js");
if (eng != null) {
diff -r 7a9492920b61 -r e709c530c227 rt/vm8/pom.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/vm8/pom.xml Sat Sep 13 18:33:05 2014 +0200
@@ -0,0 +1,74 @@
+
+
+ 4.0.0
+
+ org.apidesign.bck2brwsr
+ rt
+ 1.0-SNAPSHOT
+
+ vm8
+ Bck2Brwsr on JDK8
+ jar
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ brwsr
+
+
+
+
+
+
+
+ org.testng
+ testng
+ test
+
+
+ org.apidesign.bck2brwsr
+ vm4brwsr
+ ${project.version}
+ test
+ jar
+
+
+ org.ow2.asm
+ asm-debug-all
+ 4.1
+ test
+ jar
+
+
+ ${project.groupId}
+ emul
+ ${project.version}
+ test
+
+
+ org.apidesign.bck2brwsr
+ vmtest
+ ${project.version}
+ test
+ jar
+
+
+ ${project.groupId}
+ launcher.http
+ ${project.version}
+ test
+
+
+
\ No newline at end of file
diff -r 7a9492920b61 -r e709c530c227 rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/Defaults.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/Defaults.java Sat Sep 13 18:33:05 2014 +0200
@@ -0,0 +1,65 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012 Jaroslav Tulach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://opensource.org/licenses/GPL-2.0.
+ */
+package org.apidesign.bck2brwsr.vm8;
+
+public interface Defaults {
+ public static int staticValue() {
+ return 42;
+ }
+
+ public default int value() {
+ return 42;
+ }
+
+ public static Defaults create(int type) {
+ class X implements Defaults {
+ }
+ class Y implements Defaults {
+ @Override
+ public int value() {
+ return 7;
+ }
+ }
+ class Z implements DoubleDefaults {
+ }
+ switch (type) {
+ case 0: return new X();
+ case 1: return new Y();
+ default: return new Z();
+ }
+ }
+
+ public static int defaultValue() {
+ return create(0).value();
+ }
+
+ public static int myValue() {
+ return create(1).value();
+ }
+
+ public static int sndValue() {
+ return create(2).value();
+ }
+
+ public interface DoubleDefaults extends Defaults {
+ @Override
+ public default int value() {
+ return 84;
+ }
+ }
+}
diff -r 7a9492920b61 -r e709c530c227 rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/DefaultsTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/DefaultsTest.java Sat Sep 13 18:33:05 2014 +0200
@@ -0,0 +1,41 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012 Jaroslav Tulach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://opensource.org/licenses/GPL-2.0.
+ */
+package org.apidesign.bck2brwsr.vm8;
+
+import org.apidesign.bck2brwsr.vmtest.Compare;
+import org.apidesign.bck2brwsr.vmtest.VMTest;
+import org.testng.annotations.Factory;
+
+public class DefaultsTest {
+ @Compare public int callStatic() throws Exception {
+ return Defaults.defaultValue();
+ }
+
+ @Compare public int overridenValue() throws Exception {
+ return Defaults.myValue();
+ }
+
+ @Compare public int doubleDefault() throws Exception {
+ return Defaults.sndValue();
+ }
+
+ @Factory public static Object[] create() {
+ return VMTest.create(DefaultsTest.class);
+ }
+
+}
diff -r 7a9492920b61 -r e709c530c227 rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/Lambdas.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/Lambdas.java Sat Sep 13 18:33:05 2014 +0200
@@ -0,0 +1,36 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012 Jaroslav Tulach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://opensource.org/licenses/GPL-2.0.
+ */
+package org.apidesign.bck2brwsr.vm8;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class Lambdas {
+ private static void fewTimes(Runnable r, int cnt) {
+ while (cnt-- > 0) {
+ r.run();
+ }
+ }
+
+ public static String compound() {
+ StringBuilder sb = new StringBuilder();
+ fewTimes(() -> sb.append('X'), 10);
+ return sb.toString();
+ }
+}
diff -r 7a9492920b61 -r e709c530c227 rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/LambdasTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/vm8/src/test/java/org/apidesign/bck2brwsr/vm8/LambdasTest.java Sat Sep 13 18:33:05 2014 +0200
@@ -0,0 +1,37 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012 Jaroslav Tulach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://opensource.org/licenses/GPL-2.0.
+ */
+package org.apidesign.bck2brwsr.vm8;
+
+import org.apidesign.bck2brwsr.vmtest.Compare;
+import org.apidesign.bck2brwsr.vmtest.VMTest;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class LambdasTest {
+ @Compare public String StringverifyJSTime() throws Exception {
+ return Lambdas.compound();
+ }
+
+ @Factory public static Object[] create() {
+ return VMTest.create(LambdasTest.class);
+ }
+}
+