+ *
+ * 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.emul.fake;
+
+import org.testng.annotations.Test;
+
+public class JavaLangTest {
+ @Test
+ public void checkPackage() throws Exception {
+ JavaUtilTest.assertSignatures(Package.class);
+ }
+}
diff --git a/rt/emul/mini/src/main/java/java/lang/Class.java b/rt/emul/mini/src/main/java/java/lang/Class.java
index b953b9156..2664a092c 100644
--- a/rt/emul/mini/src/main/java/java/lang/Class.java
+++ b/rt/emul/mini/src/main/java/java/lang/Class.java
@@ -36,6 +36,7 @@
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.net.URL;
+import java.util.Objects;
import org.apidesign.bck2brwsr.core.Exported;
import org.apidesign.bck2brwsr.core.JavaScriptBody;
import org.apidesign.bck2brwsr.core.JavaScriptOnly;
@@ -1955,5 +1956,18 @@ private static void bck2BrwsrCnvrtVM() {
)
private static void castEx() {
}
-
+
+ public Package getPackage() {
+ if (isPrimitive() || isArray()) {
+ return null;
+ }
+
+ String jvmName = jvmName();
+ int lastSlash = jvmName.lastIndexOf('/');
+ if (lastSlash == -1) {
+ return Package.getPackage("");
+ }
+ String name = jvmName.substring(0, lastSlash).replace('/', '.');
+ return Package.getPackage(name);
+ }
}
diff --git a/rt/emul/mini/src/main/java/java/lang/reflect/AnnotatedElement.java b/rt/emul/mini/src/main/java/java/lang/reflect/AnnotatedElement.java
index dc2448316..8338fb87f 100644
--- a/rt/emul/mini/src/main/java/java/lang/reflect/AnnotatedElement.java
+++ b/rt/emul/mini/src/main/java/java/lang/reflect/AnnotatedElement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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
@@ -31,9 +31,170 @@
* Represents an annotated element of the program currently running in this
* VM. This interface allows annotations to be read reflectively. All
* annotations returned by methods in this interface are immutable and
- * serializable. It is permissible for the caller to modify the
- * arrays returned by accessors for array-valued enum members; it will
- * have no affect on the arrays returned to other callers.
+ * serializable. The arrays returned by methods of this interface may be modified
+ * by callers without affecting the arrays returned to other callers.
+ *
+ * The {@link #getAnnotationsByType(Class)} and {@link
+ * #getDeclaredAnnotationsByType(Class)} methods support multiple
+ * annotations of the same type on an element. If the argument to
+ * either method is a repeatable annotation type (JLS 9.6), then the
+ * method will "look through" a container annotation (JLS 9.7), if
+ * present, and return any annotations inside the container. Container
+ * annotations may be generated at compile-time to wrap multiple
+ * annotations of the argument type.
+ *
+ *
The terms directly present , indirectly present ,
+ * present , and associated are used throughout this
+ * interface to describe precisely which annotations are returned by
+ * methods:
+ *
+ *
+ *
+ * An annotation A is directly present on an
+ * element E if E has a {@code
+ * RuntimeVisibleAnnotations} or {@code
+ * RuntimeVisibleParameterAnnotations} or {@code
+ * RuntimeVisibleTypeAnnotations} attribute, and the attribute
+ * contains A .
+ *
+ * An annotation A is indirectly present on an
+ * element E if E has a {@code RuntimeVisibleAnnotations} or
+ * {@code RuntimeVisibleParameterAnnotations} or {@code RuntimeVisibleTypeAnnotations}
+ * attribute, and A 's type is repeatable, and the attribute contains
+ * exactly one annotation whose value element contains A and whose
+ * type is the containing annotation type of A 's type.
+ *
+ * An annotation A is present on an element E if either:
+ *
+ *
+ *
+ * A is directly present on E ; or
+ *
+ * No annotation of A 's type is directly present on
+ * E , and E is a class, and A 's type is
+ * inheritable, and A is present on the superclass of E .
+ *
+ *
+ *
+ * An annotation A is associated with an element E
+ * if either:
+ *
+ *
+ *
+ * A is directly or indirectly present on E ; or
+ *
+ * No annotation of A 's type is directly or indirectly
+ * present on E , and E is a class, and A 's type
+ * is inheritable, and A is associated with the superclass of
+ * E .
+ *
+ *
+ *
+ *
+ *
+ * The table below summarizes which kind of annotation presence
+ * different methods in this interface examine.
+ *
+ *
+ * Overview of kind of presence detected by different AnnotatedElement methods
+ * Kind of Presence
+ * Method Directly Present Indirectly Present Present Associated
+ * {@code T} {@link #getAnnotation(Class) getAnnotation(Class<T>)}
+ * X
+ *
+ * {@code Annotation[]} {@link #getAnnotations getAnnotations()}
+ * X
+ *
+ * {@code T[]} {@link #getAnnotationsByType(Class) getAnnotationsByType(Class<T>)}
+ * X
+ *
+ * {@code T} {@link #getDeclaredAnnotation(Class) getDeclaredAnnotation(Class<T>)}
+ * X
+ *
+ * {@code Annotation[]} {@link #getDeclaredAnnotations getDeclaredAnnotations()}
+ * X
+ *
+ * {@code T[]} {@link #getDeclaredAnnotationsByType(Class) getDeclaredAnnotationsByType(Class<T>)}
+ * X X
+ *
+ *
+ *
+ * For an invocation of {@code get[Declared]AnnotationsByType( Class <
+ * T >)}, the order of annotations which are directly or indirectly
+ * present on an element E is computed as if indirectly present
+ * annotations on E are directly present on E in place
+ * of their container annotation, in the order in which they appear in
+ * the value element of the container annotation.
+ *
+ *
There are several compatibility concerns to keep in mind if an
+ * annotation type T is originally not repeatable and
+ * later modified to be repeatable.
+ *
+ * The containing annotation type for T is TC .
+ *
+ *
+ *
+ * Modifying T to be repeatable is source and binary
+ * compatible with existing uses of T and with existing uses
+ * of TC .
+ *
+ * That is, for source compatibility, source code with annotations of
+ * type T or of type TC will still compile. For binary
+ * compatibility, class files with annotations of type T or of
+ * type TC (or with other kinds of uses of type T or of
+ * type TC ) will link against the modified version of T
+ * if they linked against the earlier version.
+ *
+ * (An annotation type TC may informally serve as an acting
+ * containing annotation type before T is modified to be
+ * formally repeatable. Alternatively, when T is made
+ * repeatable, TC can be introduced as a new type.)
+ *
+ * If an annotation type TC is present on an element, and
+ * T is modified to be repeatable with TC as its
+ * containing annotation type then:
+ *
+ *
+ *
+ * The change to T is behaviorally compatible with respect
+ * to the {@code get[Declared]Annotation(Class)} (called with an
+ * argument of T or TC ) and {@code
+ * get[Declared]Annotations()} methods because the results of the
+ * methods will not change due to TC becoming the containing
+ * annotation type for T .
+ *
+ * The change to T changes the results of the {@code
+ * get[Declared]AnnotationsByType(Class)} methods called with an
+ * argument of T , because those methods will now recognize an
+ * annotation of type TC as a container annotation for T
+ * and will "look through" it to expose annotations of type T .
+ *
+ *
+ *
+ * If an annotation of type T is present on an
+ * element and T is made repeatable and more annotations of
+ * type T are added to the element:
+ *
+ *
+ *
+ * The addition of the annotations of type T is both
+ * source compatible and binary compatible.
+ *
+ * The addition of the annotations of type T changes the results
+ * of the {@code get[Declared]Annotation(Class)} methods and {@code
+ * get[Declared]Annotations()} methods, because those methods will now
+ * only see a container annotation on the element and not see an
+ * annotation of type T .
+ *
+ * The addition of the annotations of type T changes the
+ * results of the {@code get[Declared]AnnotationsByType(Class)}
+ * methods, because their results will expose the additional
+ * annotations of type T whereas previously they exposed only a
+ * single annotation of type T .
+ *
+ *
+ *
+ *
*
* If an annotation returned by a method in this interface contains
* (directly or indirectly) a {@link Class}-valued member referring to
@@ -45,14 +206,20 @@
* a {@link EnumConstantNotPresentException} if the enum constant in the
* annotation is no longer present in the enum type.
*
- *
Finally, Attempting to read a member whose definition has evolved
+ *
If an annotation type T is (meta-)annotated with an
+ * {@code @Repeatable} annotation whose value element indicates a type
+ * TC , but TC does not declare a {@code value()} method
+ * with a return type of T {@code []}, then an exception of type
+ * {@link java.lang.annotation.AnnotationFormatError} is thrown.
+ *
+ *
Finally, attempting to read a member whose definition has evolved
* incompatibly will result in a {@link
* java.lang.annotation.AnnotationTypeMismatchException} or an
* {@link java.lang.annotation.IncompleteAnnotationException}.
*
* @see java.lang.EnumConstantNotPresentException
* @see java.lang.TypeNotPresentException
- * @see java.lang.annotation.AnnotationFormatError
+ * @see AnnotationFormatError
* @see java.lang.annotation.AnnotationTypeMismatchException
* @see java.lang.annotation.IncompleteAnnotationException
* @since 1.5
@@ -61,9 +228,15 @@
public interface AnnotatedElement {
/**
* Returns true if an annotation for the specified type
- * is present on this element, else false. This method
+ * is present on this element, else false. This method
* is designed primarily for convenient access to marker annotations.
*
+ *
The truth value returned by this method is equivalent to:
+ * {@code getAnnotation(annotationClass) != null}
+ *
+ *
The body of the default method is specified to be the code
+ * above.
+ *
* @param annotationClass the Class object corresponding to the
* annotation type
* @return true if an annotation for the specified annotation
@@ -71,12 +244,15 @@ public interface AnnotatedElement {
* @throws NullPointerException if the given annotation class is null
* @since 1.5
*/
- boolean isAnnotationPresent(Class extends Annotation> annotationClass);
+ default boolean isAnnotationPresent(Class extends Annotation> annotationClass) {
+ return getAnnotation(annotationClass) != null;
+ }
/**
* Returns this element's annotation for the specified type if
- * such an annotation is present, else null.
+ * such an annotation is present , else null.
*
+ * @param the type of the annotation to query for and return if present
* @param annotationClass the Class object corresponding to the
* annotation type
* @return this element's annotation for the specified annotation type if
@@ -87,25 +263,185 @@ public interface AnnotatedElement {
T getAnnotation(Class annotationClass);
/**
- * Returns all annotations present on this element. (Returns an array
- * of length zero if this element has no annotations.) The caller of
- * this method is free to modify the returned array; it will have no
- * effect on the arrays returned to other callers.
+ * Returns annotations that are present on this element.
*
- * @return all annotations present on this element
+ * If there are no annotations present on this element, the return
+ * value is an array of length 0.
+ *
+ * The caller of this method is free to modify the returned array; it will
+ * have no effect on the arrays returned to other callers.
+ *
+ * @return annotations present on this element
* @since 1.5
*/
Annotation[] getAnnotations();
/**
- * Returns all annotations that are directly present on this
- * element. Unlike the other methods in this interface, this method
- * ignores inherited annotations. (Returns an array of length zero if
- * no annotations are directly present on this element.) The caller of
- * this method is free to modify the returned array; it will have no
- * effect on the arrays returned to other callers.
- *
- * @return All annotations directly present on this element
+ * Returns annotations that are associated with this element.
+ *
+ * If there are no annotations associated with this element, the return
+ * value is an array of length 0.
+ *
+ * The difference between this method and {@link #getAnnotation(Class)}
+ * is that this method detects if its argument is a repeatable
+ * annotation type (JLS 9.6), and if so, attempts to find one or
+ * more annotations of that type by "looking through" a container
+ * annotation.
+ *
+ * The caller of this method is free to modify the returned array; it will
+ * have no effect on the arrays returned to other callers.
+ *
+ * @implSpec The default implementation first calls {@link
+ * #getDeclaredAnnotationsByType(Class)} passing {@code
+ * annotationClass} as the argument. If the returned array has
+ * length greater than zero, the array is returned. If the returned
+ * array is zero-length and this {@code AnnotatedElement} is a
+ * class and the argument type is an inheritable annotation type,
+ * and the superclass of this {@code AnnotatedElement} is non-null,
+ * then the returned result is the result of calling {@link
+ * #getAnnotationsByType(Class)} on the superclass with {@code
+ * annotationClass} as the argument. Otherwise, a zero-length
+ * array is returned.
+ *
+ * @param the type of the annotation to query for and return if present
+ * @param annotationClass the Class object corresponding to the
+ * annotation type
+ * @return all this element's annotations for the specified annotation type if
+ * associated with this element, else an array of length zero
+ * @throws NullPointerException if the given annotation class is null
+ * @since 1.8
+ */
+ default T[] getAnnotationsByType(Class annotationClass) {
+ /*
+ * Definition of associated: directly or indirectly present OR
+ * neither directly nor indirectly present AND the element is
+ * a Class, the annotation type is inheritable, and the
+ * annotation type is associated with the superclass of the
+ * element.
+ */
+ T[] result = getDeclaredAnnotationsByType(annotationClass);
+
+ Class extends Annotation> Inherited;
+ try {
+ Inherited = Class.forName("java.lang.annotation.Inherited").asSubclass(Annotation.class);
+ } catch (ClassNotFoundException ex) {
+ Inherited = Annotation.class;
+ }
+
+ if (result.length == 0 && // Neither directly nor indirectly present
+ this instanceof Class && // the element is a class
+ annotationClass.getAnnotation(Inherited) != null) { // Inheritable
+ Class> superClass = ((Class>) this).getSuperclass();
+ if (superClass != null) {
+ // Determine if the annotation is associated with the
+ // superclass
+ result = superClass.getAnnotationsByType(annotationClass);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns this element's annotation for the specified type if
+ * such an annotation is directly present , else null.
+ *
+ * This method ignores inherited annotations. (Returns null if no
+ * annotations are directly present on this element.)
+ *
+ * @implSpec The default implementation first performs a null check
+ * and then loops over the results of {@link
+ * #getDeclaredAnnotations} returning the first annotation whose
+ * annotation type matches the argument type.
+ *
+ * @param the type of the annotation to query for and return if directly present
+ * @param annotationClass the Class object corresponding to the
+ * annotation type
+ * @return this element's annotation for the specified annotation type if
+ * directly present on this element, else null
+ * @throws NullPointerException if the given annotation class is null
+ * @since 1.8
+ */
+ default T getDeclaredAnnotation(Class annotationClass) {
+ annotationClass.getClass();
+ // Loop over all directly-present annotations looking for a matching one
+ for (Annotation annotation : getDeclaredAnnotations()) {
+ if (annotationClass.equals(annotation.annotationType())) {
+ // More robust to do a dynamic cast at runtime instead
+ // of compile-time only.
+ return annotationClass.cast(annotation);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns this element's annotation(s) for the specified type if
+ * such annotations are either directly present or
+ * indirectly present . This method ignores inherited
+ * annotations.
+ *
+ * If there are no specified annotations directly or indirectly
+ * present on this element, the return value is an array of length
+ * 0.
+ *
+ * The difference between this method and {@link
+ * #getDeclaredAnnotation(Class)} is that this method detects if its
+ * argument is a repeatable annotation type (JLS 9.6), and if so,
+ * attempts to find one or more annotations of that type by "looking
+ * through" a container annotation if one is present.
+ *
+ * The caller of this method is free to modify the returned array; it will
+ * have no effect on the arrays returned to other callers.
+ *
+ * @implSpec The default implementation may call {@link
+ * #getDeclaredAnnotation(Class)} one or more times to find a
+ * directly present annotation and, if the annotation type is
+ * repeatable, to find a container annotation. If annotations of
+ * the annotation type {@code annotationClass} are found to be both
+ * directly and indirectly present, then {@link
+ * #getDeclaredAnnotations()} will get called to determine the
+ * order of the elements in the returned array.
+ *
+ * Alternatively, the default implementation may call {@link
+ * #getDeclaredAnnotations()} a single time and the returned array
+ * examined for both directly and indirectly present
+ * annotations. The results of calling {@link
+ * #getDeclaredAnnotations()} are assumed to be consistent with the
+ * results of calling {@link #getDeclaredAnnotation(Class)}.
+ *
+ * @param the type of the annotation to query for and return
+ * if directly or indirectly present
+ * @param annotationClass the Class object corresponding to the
+ * annotation type
+ * @return all this element's annotations for the specified annotation type if
+ * directly or indirectly present on this element, else an array of length zero
+ * @throws NullPointerException if the given annotation class is null
+ * @since 1.8
+ */
+ default T[] getDeclaredAnnotationsByType(Class annotationClass) {
+ annotationClass.getClass();
+// return AnnotationSupport.
+// getDirectlyAndIndirectlyPresent(Arrays.stream(getDeclaredAnnotations()).
+// collect(Collectors.toMap(Annotation::annotationType,
+// Function.identity(),
+// ((first,second) -> first),
+// LinkedHashMap::new)),
+// annotationClass);
+ return (T[])new Annotation[0];
+ }
+
+ /**
+ * Returns annotations that are directly present on this element.
+ * This method ignores inherited annotations.
+ *
+ * If there are no annotations directly present on this element,
+ * the return value is an array of length 0.
+ *
+ * The caller of this method is free to modify the returned array; it will
+ * have no effect on the arrays returned to other callers.
+ *
+ * @return annotations directly present on this element
* @since 1.5
*/
Annotation[] getDeclaredAnnotations();
diff --git a/rt/vm/pom.xml b/rt/vm/pom.xml
index a24cdc54d..d8a3f336a 100644
--- a/rt/vm/pom.xml
+++ b/rt/vm/pom.xml
@@ -67,7 +67,7 @@
-
+
org.apache.maven.plugins
maven-javadoc-plugin
@@ -119,4 +119,26 @@
test
+
+
+ target15
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ javac
+ 8
+ 1.5
+ 1.5
+
+ -Xlint:deprecation
+
+
+
+
+
+
+
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/AbstractStackMapper.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/AbstractStackMapper.java
new file mode 100644
index 000000000..6b77edad1
--- /dev/null
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/AbstractStackMapper.java
@@ -0,0 +1,128 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012-2018 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.vm4brwsr;
+
+import java.io.IOException;
+import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray;
+
+abstract class AbstractStackMapper {
+ public abstract void clear();
+
+ public abstract void syncWithFrameStack(final TypeArray frameStack);
+
+ public final CharSequence pushI() {
+ return pushT(VarType.INTEGER);
+ }
+
+ public final CharSequence pushL() {
+ return pushT(VarType.LONG);
+ }
+
+ public final CharSequence pushF() {
+ return pushT(VarType.FLOAT);
+ }
+
+ public final CharSequence pushD() {
+ return pushT(VarType.DOUBLE);
+ }
+
+ public final CharSequence pushA() {
+ return pushT(VarType.REFERENCE);
+ }
+
+ public abstract CharSequence pushT(final int type);
+
+ abstract void assign(Appendable out, int varType, CharSequence s) throws IOException;
+
+ abstract void replace(Appendable out, int varType, String format, CharSequence... arr)
+ throws IOException;
+
+ abstract void flush(Appendable out) throws IOException;
+
+ public abstract boolean isDirty();
+
+ public final CharSequence popI(Appendable out) throws IOException {
+ return popT(out, VarType.INTEGER);
+ }
+
+ public final CharSequence popL(Appendable out) throws IOException {
+ return popT(out, VarType.LONG);
+ }
+
+ public final CharSequence popF(Appendable out) throws IOException {
+ return popT(out, VarType.FLOAT);
+ }
+
+ public final CharSequence popD(Appendable out) throws IOException {
+ return popT(out, VarType.DOUBLE);
+ }
+
+ public final CharSequence popA(Appendable out) throws IOException {
+ return popT(out, VarType.REFERENCE);
+ }
+
+ public abstract CharSequence popT(Appendable out, final int type) throws IOException;
+
+ public abstract CharSequence popValue(Appendable out) throws IOException;
+
+ public abstract Variable pop(Appendable out) throws IOException;
+
+ public abstract void pop(Appendable out, final int count) throws IOException;
+
+ public final CharSequence getI(Appendable out, final int indexFromTop) throws IOException {
+ return getT(out, indexFromTop, VarType.INTEGER);
+ }
+
+ public final CharSequence getL(Appendable out, final int indexFromTop) throws IOException {
+ return getT(out, indexFromTop, VarType.LONG);
+ }
+
+ public final CharSequence getF(Appendable out, final int indexFromTop) throws IOException {
+ return getT(out, indexFromTop, VarType.FLOAT);
+ }
+
+ public final CharSequence getD(Appendable out, final int indexFromTop) throws IOException {
+ return getT(out, indexFromTop, VarType.DOUBLE);
+ }
+
+ public final CharSequence getA(Appendable out, final int indexFromTop) throws IOException {
+ return getT(out, indexFromTop, VarType.REFERENCE);
+ }
+
+ public final CharSequence getT(Appendable out, final int indexFromTop, final int type) throws IOException {
+ return getT(out, indexFromTop, type, true);
+ }
+ public abstract CharSequence getT(Appendable out, final int indexFromTop, final int type, boolean clear) throws IOException;
+
+ public abstract Variable get(Appendable out, final int indexFromTop) throws IOException;
+
+ public static Variable getVariable(final int typeAndIndex) {
+ final int type = typeAndIndex & 0xff;
+ final int index = typeAndIndex >> 8;
+
+ return Variable.getStackVariable(type, index);
+ }
+
+ abstract boolean alwaysUseGt();
+
+ abstract int initCode(Appendable out) throws IOException;
+
+ abstract void finishStatement(Appendable out) throws IOException;
+
+ abstract void caughtException(Appendable out, String e) throws IOException;
+}
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
index e5324ba10..5412214b2 100644
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
@@ -406,6 +406,13 @@ private String compileImpl(Appendable out, final String cn) throws IOException {
return "";
}
+ private boolean versionCheck() throws IOException {
+ if (jc.getMajor_version() < 50) {
+ return false;
+ }
+ return true;
+ }
+
private StringArray findJavaScriptResources(byte[] arr, final String cn) throws IOException {
if (arr == null) {
return null;
@@ -498,25 +505,18 @@ private boolean generateMethod(Appendable out, String destObject, String name, M
out.append(") {").append("\n");
final byte[] byteCodes = m.getCode();
- if (byteCodes == null || jc.getMajor_version() < 50) {
- if (byteCodes == null) {
- byte[] defaultAttr = m.getDefaultAttribute();
- if (defaultAttr != null) {
- out.append(" return ");
- AnnotationParser ap = new GenerateAnno(out, true, false);
- ap.parseDefault(defaultAttr, jc);
- out.append(";\n");
- } else {
- if (debug(out, " throw 'no code found for ")) {
- out.append(jc.getClassName()).append('.')
- .append(m.getName()).append("';\n");
- }
- }
+ if (byteCodes == null) {
+ byte[] defaultAttr = m.getDefaultAttribute();
+ if (defaultAttr != null) {
+ out.append(" return ");
+ AnnotationParser ap = new GenerateAnno(out, true, false);
+ ap.parseDefault(defaultAttr, jc);
+ out.append(";\n");
} else {
- out.append(" throw 'Class file version for " + jc.getClassName() + " is " + jc.getMajor_version() + "."
- + jc.getMinor_version() + " - recompile with -target 1.6 (at least)';\n"
- );
-
+ if (debug(out, " throw 'no code found for ")) {
+ out.append(jc.getClassName()).append('.')
+ .append(m.getName()).append("';\n");
+ }
}
if (defineProp) {
out.append("}});");
@@ -526,7 +526,12 @@ private boolean generateMethod(Appendable out, String destObject, String name, M
return defineProp;
}
- final StackMapper smapper = new StackMapper();
+ final AbstractStackMapper smapper;
+ if (versionCheck()) {
+ smapper = new StackMapper();
+ } else {
+ smapper = new OldStackMapper();
+ }
if (!m.isStatic()) {
out.append(" var ").append(" lcA0 = this;\n");
@@ -550,7 +555,7 @@ private boolean generateMethod(Appendable out, String destObject, String name, M
return defineProp;
}
- static int generateIf(Appendable out, StackMapper mapper, byte[] byteCodes,
+ static int generateIf(Appendable out, AbstractStackMapper mapper, byte[] byteCodes,
int i, final CharSequence v2, final CharSequence v1,
final String test, int topMostLabel
) throws IOException {
@@ -559,7 +564,7 @@ static int generateIf(Appendable out, StackMapper mapper, byte[] byteCodes,
out.append("if ((").append(v1)
.append(") ").append(test).append(" (")
.append(v2).append(")) ");
- goTo(out, i, indx, topMostLabel);
+ goTo(out, i, indx, topMostLabel, mapper.alwaysUseGt());
return i + 2;
}
@@ -1108,13 +1113,13 @@ private static String outputArg(Appendable out, String[] args, int indx) throws
}
final void emitNoFlush(
- Appendable out, StackMapper sm,
+ Appendable out, AbstractStackMapper sm,
final String format, final CharSequence... params
) throws IOException {
emitImpl(out, format, params);
}
static final void emit(
- final Appendable out, StackMapper sm, final String format, final CharSequence... params
+ final Appendable out, AbstractStackMapper sm, final String format, final CharSequence... params
) throws IOException {
sm.flush(out);
emitImpl(out, format, params);
@@ -1144,8 +1149,9 @@ static void emitImpl(final Appendable out,
out.append(format, processed, length);
}
- void generateCatch(Appendable out, TrapData[] traps, int current, int topMostLabel) throws IOException {
+ void generateCatch(Appendable out, AbstractStackMapper mapper, TrapData[] traps, int current, int topMostLabel, boolean useGt) throws IOException {
out.append("} catch (e) {\n");
+ out.append(" e = vm.java_lang_Class(false).bck2BrwsrThrwrbl(e);\n");
int finallyPC = -1;
for (TrapData e : traps) {
if (e == null) {
@@ -1154,11 +1160,10 @@ void generateCatch(Appendable out, TrapData[] traps, int current, int topMostLab
if (e.catch_cpx != 0) { //not finally
final String classInternalName = jc.getClassName(e.catch_cpx);
addReference(out, classInternalName);
- out.append("e = vm.java_lang_Class(false).bck2BrwsrThrwrbl(e);");
- out.append("if (e['$instOf_" + mangleClassName(classInternalName) + "']) {");
- out.append("var stA0 = e;");
- goTo(out, current, e.handler_pc, topMostLabel);
- out.append("}\n");
+ out.append(" if (e['$instOf_" + mangleClassName(classInternalName) + "']) {\n");
+ mapper.caughtException(out, "e");
+ goTo(out, current, e.handler_pc, topMostLabel, useGt);
+ out.append(" }\n");
} else {
finallyPC = e.handler_pc;
}
@@ -1166,13 +1171,18 @@ void generateCatch(Appendable out, TrapData[] traps, int current, int topMostLab
if (finallyPC == -1) {
out.append("throw e;");
} else {
- out.append("var stA0 = e;");
- goTo(out, current, finallyPC, topMostLabel);
+ mapper.caughtException(out, "e");
+ goTo(out, current, finallyPC, topMostLabel, useGt);
}
out.append("\n}");
}
- static void goTo(Appendable out, int current, int to, int canBack) throws IOException {
+ static void goTo(Appendable out, int current, int to, int canBack, boolean useGt) throws IOException {
+ if (useGt) {
+ out.append("{ gt = " + to + "; continue X_0; }");
+ return;
+ }
+
if (to < current) {
if (canBack < to) {
out.append("{ gt = 0; continue X_" + to + "; }");
@@ -1185,14 +1195,14 @@ static void goTo(Appendable out, int current, int to, int canBack) throws IOExce
}
static void emitIf(
- Appendable out, StackMapper sm, String pattern, CharSequence param, int current, int to, int canBack
+ Appendable out, AbstractStackMapper sm, String pattern, CharSequence param, int current, int to, int canBack
) throws IOException {
sm.flush(out);
emitImpl(out, pattern, param);
- goTo(out, current, to, canBack);
+ goTo(out, current, to, canBack, sm.alwaysUseGt());
}
- void generateNewArray(Appendable out, int atype, final StackMapper smapper) throws IOException, IllegalStateException {
+ void generateNewArray(Appendable out, int atype, final AbstractStackMapper smapper) throws IOException, IllegalStateException {
String jvmType;
switch (atype) {
case 4: jvmType = "[Z"; break;
@@ -1207,10 +1217,10 @@ void generateNewArray(Appendable out, int atype, final StackMapper smapper) thro
}
emit(out, smapper,
"var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2Ljava_lang_Object_2I'](true, '@3', null, @1);",
- smapper.popI(), smapper.pushA(), jvmType);
+ smapper.popI(out), smapper.pushA(), jvmType);
}
- void generateANewArray(Appendable out, int type, final StackMapper smapper) throws IOException {
+ void generateANewArray(Appendable out, int type, final AbstractStackMapper smapper) throws IOException {
String typeName = jc.getClassName(type);
String ref = "null";
if (typeName.startsWith("[")) {
@@ -1221,10 +1231,10 @@ void generateANewArray(Appendable out, int type, final StackMapper smapper) thro
}
emit(out, smapper,
"var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2Ljava_lang_Object_2I'](false, @3, @4, @1);",
- smapper.popI(), smapper.pushA(), typeName, ref);
+ smapper.popI(out), smapper.pushA(), typeName, ref);
}
- int generateMultiANewArray(Appendable out, int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException {
+ int generateMultiANewArray(Appendable out, int type, final byte[] byteCodes, int i, final AbstractStackMapper smapper) throws IOException {
String typeName = jc.getClassName(type);
int dim = readUByte(byteCodes, ++i);
StringBuilder dims = new StringBuilder();
@@ -1233,7 +1243,7 @@ int generateMultiANewArray(Appendable out, int type, final byte[] byteCodes, int
if (d != 0) {
dims.insert(1, ",");
}
- dims.insert(1, smapper.popI());
+ dims.insert(1, smapper.popI(out));
}
dims.append(']');
String fn = "null";
@@ -1247,7 +1257,7 @@ int generateMultiANewArray(Appendable out, int type, final byte[] byteCodes, int
return i;
}
- int generateTableSwitch(Appendable out, int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException {
+ int generateTableSwitch(Appendable out, int i, final byte[] byteCodes, final AbstractStackMapper smapper, int topMostLabel) throws IOException {
int table = i / 4 * 4 + 4;
int dflt = i + readInt4(byteCodes, table);
table += 4;
@@ -1255,29 +1265,29 @@ int generateTableSwitch(Appendable out, int i, final byte[] byteCodes, final Sta
table += 4;
int high = readInt4(byteCodes, table);
table += 4;
- final CharSequence swVar = smapper.popValue();
+ final CharSequence swVar = smapper.popValue(out);
smapper.flush(out);
out.append("switch (").append(swVar).append(") {\n");
while (low <= high) {
int offset = i + readInt4(byteCodes, table);
table += 4;
- out.append(" case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n');
+ out.append(" case " + low).append(":"); goTo(out, i, offset, topMostLabel, smapper.alwaysUseGt()); out.append('\n');
low++;
}
out.append(" default: ");
- goTo(out, i, dflt, topMostLabel);
+ goTo(out, i, dflt, topMostLabel, smapper.alwaysUseGt());
out.append("\n}");
i = table - 1;
return i;
}
- int generateLookupSwitch(Appendable out, int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException {
+ int generateLookupSwitch(Appendable out, int i, final byte[] byteCodes, final AbstractStackMapper smapper, int topMostLabel) throws IOException {
int table = i / 4 * 4 + 4;
int dflt = i + readInt4(byteCodes, table);
table += 4;
int n = readInt4(byteCodes, table);
table += 4;
- final CharSequence swVar = smapper.popValue();
+ final CharSequence swVar = smapper.popValue(out);
smapper.flush(out);
out.append("switch (").append(swVar).append(") {\n");
while (n-- > 0) {
@@ -1285,21 +1295,21 @@ int generateLookupSwitch(Appendable out, int i, final byte[] byteCodes, final St
table += 4;
int offset = i + readInt4(byteCodes, table);
table += 4;
- out.append(" case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n');
+ out.append(" case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel, smapper.alwaysUseGt()); out.append('\n');
}
out.append(" default: ");
- goTo(out, i, dflt, topMostLabel);
+ goTo(out, i, dflt, topMostLabel, smapper.alwaysUseGt());
out.append("\n}");
i = table - 1;
return i;
}
- void generateInstanceOf(Appendable out, int indx, final StackMapper smapper) throws IOException {
+ void generateInstanceOf(Appendable out, int indx, final AbstractStackMapper smapper) throws IOException {
String type = jc.getClassName(indx);
if (!type.startsWith("[")) {
emit(out, smapper,
"var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;",
- smapper.popA(), smapper.pushI(),
+ smapper.popA(out), smapper.pushI(),
mangleClassName(type));
} else {
int cnt = 0;
@@ -1312,24 +1322,24 @@ void generateInstanceOf(Appendable out, int indx, final StackMapper smapper) thr
type = "vm." + mangleClassName(component);
emit(out, smapper,
"var @2 = Array.prototype['isInstance__ZLjava_lang_Object_2ILjava_lang_Object_2'](@1, @4, @3);",
- smapper.popA(), smapper.pushI(),
+ smapper.popA(out), smapper.pushI(),
type, "" + cnt
);
} else {
emit(out, smapper,
"var @2 = Array.prototype['isInstance__ZLjava_lang_Object_2Ljava_lang_String_2'](@1, '@3');",
- smapper.popA(), smapper.pushI(), type
+ smapper.popA(out), smapper.pushI(), type
);
}
}
}
- void generateCheckcast(Appendable out, int indx, final StackMapper smapper) throws IOException {
+ void generateCheckcast(Appendable out, int indx, final AbstractStackMapper smapper) throws IOException {
String type = jc.getClassName(indx);
if (!type.startsWith("[")) {
emitNoFlush(out, smapper,
"if (@1 !== null && !@1['$instOf_@2']) vm.java_lang_Class(false).castEx(@1, '@3');",
- smapper.getT(0, VarType.REFERENCE, false), mangleClassName(type), type.replace('/', '.'));
+ smapper.getT(out, 0, VarType.REFERENCE, false), mangleClassName(type), type.replace('/', '.'));
} else {
int cnt = 0;
while (type.charAt(cnt) == '[') {
@@ -1341,12 +1351,12 @@ void generateCheckcast(Appendable out, int indx, final StackMapper smapper) thro
type = "vm." + mangleClassName(component);
emitNoFlush(out, smapper,
"if (@1 !== null && !Array.prototype['isInstance__ZLjava_lang_Object_2ILjava_lang_Object_2'](@1, @3, @2)) vm.java_lang_Class(false).castEx(@1, '');",
- smapper.getT(0, VarType.REFERENCE, false), type, "" + cnt
+ smapper.getT(out, 0, VarType.REFERENCE, false), type, "" + cnt
);
} else {
emitNoFlush(out, smapper,
"if (@1 !== null && !Array.prototype['isInstance__ZLjava_lang_Object_2Ljava_lang_String_2'](@1, '@2')) vm.java_lang_Class(false).castEx(@1, '');",
- smapper.getT(0, VarType.REFERENCE, false), type
+ smapper.getT(out, 0, VarType.REFERENCE, false), type
);
}
}
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java
index 4486ab964..28cc0e137 100644
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassDataCache.java
@@ -1,217 +1,222 @@
-/**
- * Back 2 Browser Bytecode Translator
- * Copyright (C) 2012-2018 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.vm4brwsr;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-import org.apidesign.bck2brwsr.core.ExtraJavaScript;
-import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
-import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
-import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
-
-@ExtraJavaScript(processByteCode = false, resource="")
-final class ClassDataCache {
- private static final Object MISSING_CLASS = new Object();
-
- private final Bck2Brwsr.Resources resources;
- private final Map classDataMap;
-
- ClassDataCache(final Bck2Brwsr.Resources resources) {
- this.resources = resources;
-
- classDataMap = new HashMap();
- }
-
- ClassData getClassData(String className) throws IOException {
- if (className.startsWith("[")) {
- // required for accessVirtualMethod, shouldn't be problematic for
- // calls from other sources
- className = "java/lang/Object";
- }
- Object cacheEntry = classDataMap.get(className);
- if (cacheEntry == null) {
- final InputStream is = loadClass(resources, className);
- try {
- cacheEntry = (is != null) ? new ClassData(is) : MISSING_CLASS;
- } catch (IOException ex) {
- throw new IOException("Cannot process " + className, ex);
- }
- classDataMap.put(className, cacheEntry);
- }
-
- return (cacheEntry != MISSING_CLASS) ? (ClassData) cacheEntry : null;
- }
-
- MethodData findMethod(final String startingClass,
- final String name,
- final String signature) throws IOException {
- return findMethod(getClassData(startingClass), name, signature);
- }
-
- FieldData findField(final String startingClass,
- final String name,
- final String signature) throws IOException {
- return findField(getClassData(startingClass), name, signature);
- }
-
- MethodData findMethod(final ClassData startingClass,
- final String name,
- final String signature) throws IOException {
- final FindFirstTraversalCallback ffTraversalCallback =
- new FindFirstTraversalCallback();
-
- findMethods(startingClass, name, signature, ffTraversalCallback);
- return ffTraversalCallback.getFirst();
- }
-
- FieldData findField(final ClassData startingClass,
- final String name,
- final String signature) throws IOException {
- final FindFirstTraversalCallback ffTraversalCallback =
- new FindFirstTraversalCallback();
-
- findFields(startingClass, name, signature, ffTraversalCallback);
- return ffTraversalCallback.getFirst();
- }
-
- void findMethods(final ClassData startingClass,
- final String methodName,
- final String methodSignature,
- final TraversalCallback mdTraversalCallback)
- throws IOException {
- traverseHierarchy(
- startingClass,
- new FindMethodsTraversalCallback(methodName, methodSignature,
- mdTraversalCallback));
- }
-
- void findFields(final ClassData startingClass,
- final String fieldName,
- final String fieldSignature,
- final TraversalCallback fdTraversalCallback)
- throws IOException {
- traverseHierarchy(
- startingClass,
- new FindFieldsTraversalCallback(fieldName, fieldSignature,
- fdTraversalCallback));
- }
-
- private boolean traverseHierarchy(
- ClassData currentClass,
- final TraversalCallback cdTraversalCallback)
- throws IOException {
- while (currentClass != null) {
- if (!cdTraversalCallback.traverse(currentClass)) {
- return false;
- }
-
- for (final String superIfaceName:
- currentClass.getSuperInterfaces()) {
- if (!traverseHierarchy(getClassData(superIfaceName),
- cdTraversalCallback)) {
- return false;
- }
- }
-
- final String superClassName = currentClass.getSuperClassName();
- if (superClassName == null) {
- break;
- }
-
- currentClass = getClassData(superClassName);
- }
-
- return true;
- }
-
- interface TraversalCallback {
- boolean traverse(T object);
- }
-
- private final class FindFirstTraversalCallback
- implements TraversalCallback {
- private T firstObject;
-
- @Override
- public boolean traverse(final T object) {
- firstObject = object;
- return false;
- }
-
- public T getFirst() {
- return firstObject;
- }
- }
-
- private final class FindMethodsTraversalCallback
- implements TraversalCallback {
- private final String methodName;
- private final String methodSignature;
- private final TraversalCallback mdTraversalCallback;
-
- public FindMethodsTraversalCallback(
- final String methodName,
- final String methodSignature,
- final TraversalCallback mdTraversalCallback) {
- this.methodName = methodName;
- this.methodSignature = methodSignature;
- this.mdTraversalCallback = mdTraversalCallback;
- }
-
- @Override
- public boolean traverse(final ClassData classData) {
- final MethodData methodData =
- classData.findMethod(methodName, methodSignature);
- return (methodData != null)
- ? mdTraversalCallback.traverse(methodData)
- : true;
- }
- }
-
- private final class FindFieldsTraversalCallback
- implements TraversalCallback {
- private final String fieldName;
- private final String fieldSignature;
- private final TraversalCallback fdTraversalCallback;
-
- public FindFieldsTraversalCallback(
- final String fieldName,
- final String fieldSignature,
- final TraversalCallback fdTraversalCallback) {
- this.fieldName = fieldName;
- this.fieldSignature = fieldSignature;
- this.fdTraversalCallback = fdTraversalCallback;
- }
-
- @Override
- public boolean traverse(final ClassData classData) {
- final FieldData fieldData =
- classData.findField(fieldName, fieldSignature);
- return (fieldData != null)
- ? fdTraversalCallback.traverse(fieldData)
- : true;
- }
- }
-
- private static InputStream loadClass(Bck2Brwsr.Resources l, String name)
- throws IOException {
- return l.get(name + ".class"); // NOI18N
- }
-}
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012-2018 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.vm4brwsr;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import org.apidesign.bck2brwsr.core.ExtraJavaScript;
+import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
+import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
+import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
+
+@ExtraJavaScript(processByteCode = false, resource="")
+final class ClassDataCache {
+ private static final Object MISSING_CLASS = new Object();
+
+ private final Bck2Brwsr.Resources resources;
+ private final Map classDataMap;
+
+ ClassDataCache(final Bck2Brwsr.Resources resources) {
+ this.resources = resources;
+
+ classDataMap = new HashMap();
+ }
+
+ ClassData getClassData(String className) throws IOException {
+ if (className.startsWith("[")) {
+ // required for accessVirtualMethod, shouldn't be problematic for
+ // calls from other sources
+ className = "java/lang/Object";
+ }
+ Object cacheEntry = classDataMap.get(className);
+ if (cacheEntry == null) {
+ InputStream is = null;
+ try {
+ is = loadClass(resources, className);
+ } catch (IOException loadOrNot) {
+ is = null;
+ }
+ try {
+ cacheEntry = (is != null) ? new ClassData(is) : MISSING_CLASS;
+ } catch (IOException ex) {
+ throw new IOException("Cannot process " + className, ex);
+ }
+ classDataMap.put(className, cacheEntry);
+ }
+
+ return (cacheEntry != MISSING_CLASS) ? (ClassData) cacheEntry : null;
+ }
+
+ MethodData findMethod(final String startingClass,
+ final String name,
+ final String signature) throws IOException {
+ return findMethod(getClassData(startingClass), name, signature);
+ }
+
+ FieldData findField(final String startingClass,
+ final String name,
+ final String signature) throws IOException {
+ return findField(getClassData(startingClass), name, signature);
+ }
+
+ MethodData findMethod(final ClassData startingClass,
+ final String name,
+ final String signature) throws IOException {
+ final FindFirstTraversalCallback ffTraversalCallback =
+ new FindFirstTraversalCallback();
+
+ findMethods(startingClass, name, signature, ffTraversalCallback);
+ return ffTraversalCallback.getFirst();
+ }
+
+ FieldData findField(final ClassData startingClass,
+ final String name,
+ final String signature) throws IOException {
+ final FindFirstTraversalCallback ffTraversalCallback =
+ new FindFirstTraversalCallback();
+
+ findFields(startingClass, name, signature, ffTraversalCallback);
+ return ffTraversalCallback.getFirst();
+ }
+
+ void findMethods(final ClassData startingClass,
+ final String methodName,
+ final String methodSignature,
+ final TraversalCallback mdTraversalCallback)
+ throws IOException {
+ traverseHierarchy(
+ startingClass,
+ new FindMethodsTraversalCallback(methodName, methodSignature,
+ mdTraversalCallback));
+ }
+
+ void findFields(final ClassData startingClass,
+ final String fieldName,
+ final String fieldSignature,
+ final TraversalCallback fdTraversalCallback)
+ throws IOException {
+ traverseHierarchy(
+ startingClass,
+ new FindFieldsTraversalCallback(fieldName, fieldSignature,
+ fdTraversalCallback));
+ }
+
+ private boolean traverseHierarchy(
+ ClassData currentClass,
+ final TraversalCallback cdTraversalCallback)
+ throws IOException {
+ while (currentClass != null) {
+ if (!cdTraversalCallback.traverse(currentClass)) {
+ return false;
+ }
+
+ for (final String superIfaceName:
+ currentClass.getSuperInterfaces()) {
+ if (!traverseHierarchy(getClassData(superIfaceName),
+ cdTraversalCallback)) {
+ return false;
+ }
+ }
+
+ final String superClassName = currentClass.getSuperClassName();
+ if (superClassName == null) {
+ break;
+ }
+
+ currentClass = getClassData(superClassName);
+ }
+
+ return true;
+ }
+
+ interface TraversalCallback {
+ boolean traverse(T object);
+ }
+
+ private final class FindFirstTraversalCallback
+ implements TraversalCallback {
+ private T firstObject;
+
+ @Override
+ public boolean traverse(final T object) {
+ firstObject = object;
+ return false;
+ }
+
+ public T getFirst() {
+ return firstObject;
+ }
+ }
+
+ private final class FindMethodsTraversalCallback
+ implements TraversalCallback {
+ private final String methodName;
+ private final String methodSignature;
+ private final TraversalCallback mdTraversalCallback;
+
+ public FindMethodsTraversalCallback(
+ final String methodName,
+ final String methodSignature,
+ final TraversalCallback mdTraversalCallback) {
+ this.methodName = methodName;
+ this.methodSignature = methodSignature;
+ this.mdTraversalCallback = mdTraversalCallback;
+ }
+
+ @Override
+ public boolean traverse(final ClassData classData) {
+ final MethodData methodData =
+ classData.findMethod(methodName, methodSignature);
+ return (methodData != null)
+ ? mdTraversalCallback.traverse(methodData)
+ : true;
+ }
+ }
+
+ private final class FindFieldsTraversalCallback
+ implements TraversalCallback {
+ private final String fieldName;
+ private final String fieldSignature;
+ private final TraversalCallback fdTraversalCallback;
+
+ public FindFieldsTraversalCallback(
+ final String fieldName,
+ final String fieldSignature,
+ final TraversalCallback fdTraversalCallback) {
+ this.fieldName = fieldName;
+ this.fieldSignature = fieldSignature;
+ this.fdTraversalCallback = fdTraversalCallback;
+ }
+
+ @Override
+ public boolean traverse(final ClassData classData) {
+ final FieldData fieldData =
+ classData.findField(fieldName, fieldSignature);
+ return (fieldData != null)
+ ? fdTraversalCallback.traverse(fieldData)
+ : true;
+ }
+ }
+
+ private static InputStream loadClass(Bck2Brwsr.Resources l, String name)
+ throws IOException {
+ return l.get(name + ".class"); // NOI18N
+ }
+}
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/IndyHandler.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/IndyHandler.java
index 4d46658d7..10df45a10 100644
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/IndyHandler.java
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/IndyHandler.java
@@ -32,12 +32,12 @@ abstract class IndyHandler {
static class Ctx {
final Appendable out;
- final StackMapper stackMapper;
+ final AbstractStackMapper stackMapper;
final ByteCodeToJavaScript byteCodeToJavaScript;
final ByteCodeParser.BootMethodData bm;
final String[] mt;
- Ctx(Appendable out, StackMapper m, ByteCodeToJavaScript bc, String[] methodAndType, ByteCodeParser.BootMethodData bm) {
+ Ctx(Appendable out, AbstractStackMapper m, ByteCodeToJavaScript bc, String[] methodAndType, ByteCodeParser.BootMethodData bm) {
this.out = out;
this.stackMapper = m;
this.byteCodeToJavaScript = bc;
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/LoopCode.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LoopCode.java
index 4f34043ab..43dcd6e2c 100644
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/LoopCode.java
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LoopCode.java
@@ -42,7 +42,7 @@ public void run() {
void loopCode(
final ByteCodeParser.StackMapIterator stackMapIterator,
final byte[] byteCodes, ByteCodeParser.TrapDataIterator trap,
- final StackMapper smapper,
+ final AbstractStackMapper smapper,
final LocalsMapper lmapper
) throws IllegalStateException, NumberFormatException, IOException {
int lastStackFrame;
@@ -57,7 +57,7 @@ void loopCode(
lastStackFrame = -1;
out.append("\n var gt = 0;\n");
}
- int openBraces = 0;
+ int openBraces = smapper.initCode(out);
int topMostLabel = 0;
for (int i = 0; i < byteCodes.length; i++) {
int prev = i;
@@ -66,11 +66,13 @@ void loopCode(
boolean changeInCatch = trap.advanceTo(i);
if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
if (previousTrap != null) {
- byteCodeToJavaScript.generateCatch(out, previousTrap, i, topMostLabel);
+ byteCodeToJavaScript.generateCatch(out, smapper, previousTrap, i, topMostLabel, smapper.alwaysUseGt());
previousTrap = null;
}
}
- if (lastStackFrame != stackMapIterator.getFrameIndex()) {
+ if (smapper.alwaysUseGt()) {
+ // no op
+ } else if (lastStackFrame != stackMapIterator.getFrameIndex()) {
smapper.flush(out);
if (i != 0) {
out.append(" }\n");
@@ -95,6 +97,9 @@ void loopCode(
out.append("try {");
previousTrap = trap.current();
}
+ if (smapper.alwaysUseGt()) {
+ out.append(" if (gt <= " + i + ") {\n");
+ }
final int c = ByteCodeToJavaScript.readUByte(byteCodes, i);
switch (c) {
case ByteCodeParser.opc_nop:
@@ -204,7 +209,7 @@ void loopCode(
++i;
final int indx = wide ? ByteCodeToJavaScript.readUShort(byteCodes, i++) : ByteCodeToJavaScript.readUByte(byteCodes, i);
wide = false;
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(indx), smapper.popI());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(indx), smapper.popI(out));
break;
}
case ByteCodeParser.opc_lstore:
@@ -212,7 +217,7 @@ void loopCode(
++i;
final int indx = wide ? ByteCodeToJavaScript.readUShort(byteCodes, i++) : ByteCodeToJavaScript.readUByte(byteCodes, i);
wide = false;
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(indx), smapper.popL());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(indx), smapper.popL(out));
break;
}
case ByteCodeParser.opc_fstore:
@@ -220,7 +225,7 @@ void loopCode(
++i;
final int indx = wide ? ByteCodeToJavaScript.readUShort(byteCodes, i++) : ByteCodeToJavaScript.readUByte(byteCodes, i);
wide = false;
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(indx), smapper.popF());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(indx), smapper.popF(out));
break;
}
case ByteCodeParser.opc_dstore:
@@ -228,7 +233,7 @@ void loopCode(
++i;
final int indx = wide ? ByteCodeToJavaScript.readUShort(byteCodes, i++) : ByteCodeToJavaScript.readUByte(byteCodes, i);
wide = false;
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(indx), smapper.popD());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(indx), smapper.popD(out));
break;
}
case ByteCodeParser.opc_astore:
@@ -236,176 +241,176 @@ void loopCode(
++i;
final int indx = wide ? ByteCodeToJavaScript.readUShort(byteCodes, i++) : ByteCodeToJavaScript.readUByte(byteCodes, i);
wide = false;
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(indx), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(indx), smapper.popA(out));
break;
}
case ByteCodeParser.opc_astore_0:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(0), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(0), smapper.popA(out));
break;
case ByteCodeParser.opc_istore_0:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(0), smapper.popI());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(0), smapper.popI(out));
break;
case ByteCodeParser.opc_lstore_0:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(0), smapper.popL());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(0), smapper.popL(out));
break;
case ByteCodeParser.opc_fstore_0:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(0), smapper.popF());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(0), smapper.popF(out));
break;
case ByteCodeParser.opc_dstore_0:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(0), smapper.popD());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(0), smapper.popD(out));
break;
case ByteCodeParser.opc_astore_1:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(1), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(1), smapper.popA(out));
break;
case ByteCodeParser.opc_istore_1:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(1), smapper.popI());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(1), smapper.popI(out));
break;
case ByteCodeParser.opc_lstore_1:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(1), smapper.popL());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(1), smapper.popL(out));
break;
case ByteCodeParser.opc_fstore_1:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(1), smapper.popF());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(1), smapper.popF(out));
break;
case ByteCodeParser.opc_dstore_1:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(1), smapper.popD());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(1), smapper.popD(out));
break;
case ByteCodeParser.opc_astore_2:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(2), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(2), smapper.popA(out));
break;
case ByteCodeParser.opc_istore_2:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(2), smapper.popI());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(2), smapper.popI(out));
break;
case ByteCodeParser.opc_lstore_2:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(2), smapper.popL());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(2), smapper.popL(out));
break;
case ByteCodeParser.opc_fstore_2:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(2), smapper.popF());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(2), smapper.popF(out));
break;
case ByteCodeParser.opc_dstore_2:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(2), smapper.popD());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(2), smapper.popD(out));
break;
case ByteCodeParser.opc_astore_3:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(3), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setA(3), smapper.popA(out));
break;
case ByteCodeParser.opc_istore_3:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(3), smapper.popI());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setI(3), smapper.popI(out));
break;
case ByteCodeParser.opc_lstore_3:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(3), smapper.popL());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setL(3), smapper.popL(out));
break;
case ByteCodeParser.opc_fstore_3:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(3), smapper.popF());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setF(3), smapper.popF(out));
break;
case ByteCodeParser.opc_dstore_3:
- ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(3), smapper.popD());
+ ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", lmapper.setD(3), smapper.popD(out));
break;
case ByteCodeParser.opc_iadd:
- smapper.replace(out, VarType.INTEGER, "(((@1) + (@2)) | 0)", smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, "(((@1) + (@2)) | 0)", smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_ladd:
- smapper.replace(out, VarType.LONG, numbers.add64(), smapper.getL(1), smapper.popL());
+ smapper.replace(out, VarType.LONG, numbers.add64(), smapper.getL(out, 1), smapper.popL(out));
break;
case ByteCodeParser.opc_fadd:
- smapper.replace(out, VarType.FLOAT, "(@1 + @2)", smapper.getF(1), smapper.popF());
+ smapper.replace(out, VarType.FLOAT, "(@1 + @2)", smapper.getF(out, 1), smapper.popF(out));
break;
case ByteCodeParser.opc_dadd:
- smapper.replace(out, VarType.DOUBLE, "(@1 + @2)", smapper.getD(1), smapper.popD());
+ smapper.replace(out, VarType.DOUBLE, "(@1 + @2)", smapper.getD(out, 1), smapper.popD(out));
break;
case ByteCodeParser.opc_isub:
- smapper.replace(out, VarType.INTEGER, "(((@1) - (@2)) | 0)", smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, "(((@1) - (@2)) | 0)", smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_lsub:
- smapper.replace(out, VarType.LONG, numbers.sub64(), smapper.getL(1), smapper.popL());
+ smapper.replace(out, VarType.LONG, numbers.sub64(), smapper.getL(out, 1), smapper.popL(out));
break;
case ByteCodeParser.opc_fsub:
- smapper.replace(out, VarType.FLOAT, "(@1 - @2)", smapper.getF(1), smapper.popF());
+ smapper.replace(out, VarType.FLOAT, "(@1 - @2)", smapper.getF(out, 1), smapper.popF(out));
break;
case ByteCodeParser.opc_dsub:
- smapper.replace(out, VarType.DOUBLE, "(@1 - @2)", smapper.getD(1), smapper.popD());
+ smapper.replace(out, VarType.DOUBLE, "(@1 - @2)", smapper.getD(out, 1), smapper.popD(out));
break;
case ByteCodeParser.opc_imul:
- smapper.replace(out, VarType.INTEGER, numbers.mul32(), smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, numbers.mul32(), smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_lmul:
- smapper.replace(out, VarType.LONG, numbers.mul64(), smapper.getL(1), smapper.popL());
+ smapper.replace(out, VarType.LONG, numbers.mul64(), smapper.getL(out, 1), smapper.popL(out));
break;
case ByteCodeParser.opc_fmul:
- smapper.replace(out, VarType.FLOAT, "(@1 * @2)", smapper.getF(1), smapper.popF());
+ smapper.replace(out, VarType.FLOAT, "(@1 * @2)", smapper.getF(out, 1), smapper.popF(out));
break;
case ByteCodeParser.opc_dmul:
- smapper.replace(out, VarType.DOUBLE, "(@1 * @2)", smapper.getD(1), smapper.popD());
+ smapper.replace(out, VarType.DOUBLE, "(@1 * @2)", smapper.getD(out, 1), smapper.popD(out));
break;
case ByteCodeParser.opc_idiv:
- smapper.replace(out, VarType.INTEGER, numbers.div32(), smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, numbers.div32(), smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_ldiv:
- smapper.replace(out, VarType.LONG, numbers.div64(), smapper.getL(1), smapper.popL());
+ smapper.replace(out, VarType.LONG, numbers.div64(), smapper.getL(out, 1), smapper.popL(out));
break;
case ByteCodeParser.opc_fdiv:
- smapper.replace(out, VarType.FLOAT, "(@1 / @2)", smapper.getF(1), smapper.popF());
+ smapper.replace(out, VarType.FLOAT, "(@1 / @2)", smapper.getF(out, 1), smapper.popF(out));
break;
case ByteCodeParser.opc_ddiv:
- smapper.replace(out, VarType.DOUBLE, "(@1 / @2)", smapper.getD(1), smapper.popD());
+ smapper.replace(out, VarType.DOUBLE, "(@1 / @2)", smapper.getD(out, 1), smapper.popD(out));
break;
case ByteCodeParser.opc_irem:
- smapper.replace(out, VarType.INTEGER, numbers.mod32(), smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, numbers.mod32(), smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_lrem:
- smapper.replace(out, VarType.LONG, numbers.mod64(), smapper.getL(1), smapper.popL());
+ smapper.replace(out, VarType.LONG, numbers.mod64(), smapper.getL(out, 1), smapper.popL(out));
break;
case ByteCodeParser.opc_frem:
- smapper.replace(out, VarType.FLOAT, "(@1 % @2)", smapper.getF(1), smapper.popF());
+ smapper.replace(out, VarType.FLOAT, "(@1 % @2)", smapper.getF(out, 1), smapper.popF(out));
break;
case ByteCodeParser.opc_drem:
- smapper.replace(out, VarType.DOUBLE, "(@1 % @2)", smapper.getD(1), smapper.popD());
+ smapper.replace(out, VarType.DOUBLE, "(@1 % @2)", smapper.getD(out, 1), smapper.popD(out));
break;
case ByteCodeParser.opc_iand:
- smapper.replace(out, VarType.INTEGER, "(@1 & @2)", smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, "(@1 & @2)", smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_land:
- smapper.replace(out, VarType.LONG, numbers.and64(), smapper.getL(1), smapper.popL());
+ smapper.replace(out, VarType.LONG, numbers.and64(), smapper.getL(out, 1), smapper.popL(out));
break;
case ByteCodeParser.opc_ior:
- smapper.replace(out, VarType.INTEGER, "(@1 | @2)", smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, "(@1 | @2)", smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_lor:
- smapper.replace(out, VarType.LONG, numbers.or64(), smapper.getL(1), smapper.popL());
+ smapper.replace(out, VarType.LONG, numbers.or64(), smapper.getL(out, 1), smapper.popL(out));
break;
case ByteCodeParser.opc_ixor:
- smapper.replace(out, VarType.INTEGER, "(@1 ^ @2)", smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, "(@1 ^ @2)", smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_lxor:
- smapper.replace(out, VarType.LONG, numbers.xor64(), smapper.getL(1), smapper.popL());
+ smapper.replace(out, VarType.LONG, numbers.xor64(), smapper.getL(out, 1), smapper.popL(out));
break;
case ByteCodeParser.opc_ineg:
- smapper.replace(out, VarType.INTEGER, "(-(@1) | 0)", smapper.getI(0));
+ smapper.replace(out, VarType.INTEGER, "(-(@1) | 0)", smapper.getI(out, 0));
break;
case ByteCodeParser.opc_lneg:
- smapper.replace(out, VarType.LONG, numbers.neg64(), smapper.getL(0));
+ smapper.replace(out, VarType.LONG, numbers.neg64(), smapper.getL(out, 0));
break;
case ByteCodeParser.opc_fneg:
- smapper.replace(out, VarType.FLOAT, "(-@1)", smapper.getF(0));
+ smapper.replace(out, VarType.FLOAT, "(-@1)", smapper.getF(out, 0));
break;
case ByteCodeParser.opc_dneg:
- smapper.replace(out, VarType.DOUBLE, "(-@1)", smapper.getD(0));
+ smapper.replace(out, VarType.DOUBLE, "(-@1)", smapper.getD(out, 0));
break;
case ByteCodeParser.opc_ishl:
- smapper.replace(out, VarType.INTEGER, "(@1 << @2)", smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, "(@1 << @2)", smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_lshl:
- smapper.replace(out, VarType.LONG, numbers.shl64(), smapper.getL(1), smapper.popI());
+ smapper.replace(out, VarType.LONG, numbers.shl64(), smapper.getL(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_ishr:
- smapper.replace(out, VarType.INTEGER, "(@1 >> @2)", smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, "(@1 >> @2)", smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_lshr:
- smapper.replace(out, VarType.LONG, numbers.shr64(), smapper.getL(1), smapper.popI());
+ smapper.replace(out, VarType.LONG, numbers.shr64(), smapper.getL(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_iushr:
- smapper.replace(out, VarType.INTEGER, "(@1 >>> @2)", smapper.getI(1), smapper.popI());
+ smapper.replace(out, VarType.INTEGER, "(@1 >>> @2)", smapper.getI(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_lushr:
- smapper.replace(out, VarType.LONG, numbers.ushr64(), smapper.getL(1), smapper.popI());
+ smapper.replace(out, VarType.LONG, numbers.ushr64(), smapper.getL(out, 1), smapper.popI(out));
break;
case ByteCodeParser.opc_iinc:
{
@@ -425,63 +430,63 @@ void loopCode(
ByteCodeToJavaScript.emit(out, smapper, "return;");
break;
case ByteCodeParser.opc_ireturn:
- ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popI());
+ ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popI(out));
break;
case ByteCodeParser.opc_lreturn:
- ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popL());
+ ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popL(out));
break;
case ByteCodeParser.opc_freturn:
- ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popF());
+ ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popF(out));
break;
case ByteCodeParser.opc_dreturn:
- ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popD());
+ ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popD(out));
break;
case ByteCodeParser.opc_areturn:
- ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "return @1;", smapper.popA(out));
break;
case ByteCodeParser.opc_i2l:
- smapper.replace(out, VarType.LONG, "(@1).toLong()", smapper.getI(0));
+ smapper.replace(out, VarType.LONG, "(@1).toLong()", smapper.getI(out, 0));
break;
case ByteCodeParser.opc_i2f:
- smapper.replace(out, VarType.FLOAT, "@1", smapper.getI(0));
+ smapper.replace(out, VarType.FLOAT, "@1", smapper.getI(out, 0));
break;
case ByteCodeParser.opc_i2d:
- smapper.replace(out, VarType.DOUBLE, "@1", smapper.getI(0));
+ smapper.replace(out, VarType.DOUBLE, "@1", smapper.getI(out, 0));
break;
case ByteCodeParser.opc_l2i:
- smapper.replace(out, VarType.INTEGER, "((@1) | 0)", smapper.getL(0));
+ smapper.replace(out, VarType.INTEGER, "((@1) | 0)", smapper.getL(out, 0));
break;
// max int check?
case ByteCodeParser.opc_l2f:
- smapper.replace(out, VarType.FLOAT, numbers.toFP(), smapper.getL(0));
+ smapper.replace(out, VarType.FLOAT, numbers.toFP(), smapper.getL(out, 0));
break;
case ByteCodeParser.opc_l2d:
- smapper.replace(out, VarType.DOUBLE, numbers.toFP(), smapper.getL(0));
+ smapper.replace(out, VarType.DOUBLE, numbers.toFP(), smapper.getL(out, 0));
break;
case ByteCodeParser.opc_f2d:
- smapper.replace(out, VarType.DOUBLE, "@1", smapper.getF(0));
+ smapper.replace(out, VarType.DOUBLE, "@1", smapper.getF(out, 0));
break;
case ByteCodeParser.opc_d2f:
- smapper.replace(out, VarType.FLOAT, "@1", smapper.getD(0));
+ smapper.replace(out, VarType.FLOAT, "@1", smapper.getD(out, 0));
break;
case ByteCodeParser.opc_f2i:
- smapper.replace(out, VarType.INTEGER, "((@1) | 0)", smapper.getF(0));
+ smapper.replace(out, VarType.INTEGER, "((@1) | 0)", smapper.getF(out, 0));
break;
case ByteCodeParser.opc_f2l:
- smapper.replace(out, VarType.LONG, "(@1).toLong()", smapper.getF(0));
+ smapper.replace(out, VarType.LONG, "(@1).toLong()", smapper.getF(out, 0));
break;
case ByteCodeParser.opc_d2i:
- smapper.replace(out, VarType.INTEGER, "((@1)| 0)", smapper.getD(0));
+ smapper.replace(out, VarType.INTEGER, "((@1)| 0)", smapper.getD(out, 0));
break;
case ByteCodeParser.opc_d2l:
- smapper.replace(out, VarType.LONG, "(@1).toLong()", smapper.getD(0));
+ smapper.replace(out, VarType.LONG, "(@1).toLong()", smapper.getD(out, 0));
break;
case ByteCodeParser.opc_i2b:
- smapper.replace(out, VarType.INTEGER, "(((@1) << 24) >> 24)", smapper.getI(0));
+ smapper.replace(out, VarType.INTEGER, "(((@1) << 24) >> 24)", smapper.getI(out, 0));
break;
case ByteCodeParser.opc_i2c:
case ByteCodeParser.opc_i2s:
- smapper.replace(out, VarType.INTEGER, "(((@1) << 16) >> 16)", smapper.getI(0));
+ smapper.replace(out, VarType.INTEGER, "(((@1) << 16) >> 16)", smapper.getI(out, 0));
break;
case ByteCodeParser.opc_aconst_null:
smapper.assign(out, VarType.REFERENCE, "null");
@@ -558,101 +563,101 @@ void loopCode(
break;
}
case ByteCodeParser.opc_lcmp:
- smapper.replace(out, VarType.INTEGER, numbers.compare64(), smapper.popL(), smapper.getL(0));
+ smapper.replace(out, VarType.INTEGER, numbers.compare64(), smapper.popL(out), smapper.getL(out, 0));
break;
case ByteCodeParser.opc_fcmpl:
case ByteCodeParser.opc_fcmpg:
- ByteCodeToJavaScript.emit(out, smapper, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popF(), smapper.popF(), smapper.pushI());
+ ByteCodeToJavaScript.emit(out, smapper, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popF(out), smapper.popF(out), smapper.pushI());
break;
case ByteCodeParser.opc_dcmpl:
case ByteCodeParser.opc_dcmpg:
- ByteCodeToJavaScript.emit(out, smapper, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popD(), smapper.popD(), smapper.pushI());
+ ByteCodeToJavaScript.emit(out, smapper, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popD(out), smapper.popD(out), smapper.pushI());
break;
case ByteCodeParser.opc_if_acmpeq:
- i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popA(), smapper.popA(), "===", topMostLabel);
+ i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popA(out), smapper.popA(out), "===", topMostLabel);
break;
case ByteCodeParser.opc_if_acmpne:
- i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popA(), smapper.popA(), "!==", topMostLabel);
+ i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popA(out), smapper.popA(out), "!==", topMostLabel);
break;
case ByteCodeParser.opc_if_icmpeq:
- i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(), smapper.popI(), "==", topMostLabel);
+ i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(out), smapper.popI(out), "==", topMostLabel);
break;
case ByteCodeParser.opc_ifeq:
{
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) == 0) ", smapper.popI(), i, indx, topMostLabel);
+ ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) == 0) ", smapper.popI(out), i, indx, topMostLabel);
i += 2;
break;
}
case ByteCodeParser.opc_ifne:
{
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) != 0) ", smapper.popI(), i, indx, topMostLabel);
+ ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) != 0) ", smapper.popI(out), i, indx, topMostLabel);
i += 2;
break;
}
case ByteCodeParser.opc_iflt:
{
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) < 0) ", smapper.popI(), i, indx, topMostLabel);
+ ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) < 0) ", smapper.popI(out), i, indx, topMostLabel);
i += 2;
break;
}
case ByteCodeParser.opc_ifle:
{
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) <= 0) ", smapper.popI(), i, indx, topMostLabel);
+ ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) <= 0) ", smapper.popI(out), i, indx, topMostLabel);
i += 2;
break;
}
case ByteCodeParser.opc_ifgt:
{
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) > 0) ", smapper.popI(), i, indx, topMostLabel);
+ ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) > 0) ", smapper.popI(out), i, indx, topMostLabel);
i += 2;
break;
}
case ByteCodeParser.opc_ifge:
{
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) >= 0) ", smapper.popI(), i, indx, topMostLabel);
+ ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) >= 0) ", smapper.popI(out), i, indx, topMostLabel);
i += 2;
break;
}
case ByteCodeParser.opc_ifnonnull:
{
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) !== null) ", smapper.popA(), i, indx, topMostLabel);
+ ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) !== null) ", smapper.popA(out), i, indx, topMostLabel);
i += 2;
break;
}
case ByteCodeParser.opc_ifnull:
{
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) === null) ", smapper.popA(), i, indx, topMostLabel);
+ ByteCodeToJavaScript.emitIf(out, smapper, "if ((@1) === null) ", smapper.popA(out), i, indx, topMostLabel);
i += 2;
break;
}
case ByteCodeParser.opc_if_icmpne:
- i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(), smapper.popI(), "!=", topMostLabel);
+ i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(out), smapper.popI(out), "!=", topMostLabel);
break;
case ByteCodeParser.opc_if_icmplt:
- i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(), smapper.popI(), "<", topMostLabel);
+ i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(out), smapper.popI(out), "<", topMostLabel);
break;
case ByteCodeParser.opc_if_icmple:
- i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(), smapper.popI(), "<=", topMostLabel);
+ i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(out), smapper.popI(out), "<=", topMostLabel);
break;
case ByteCodeParser.opc_if_icmpgt:
- i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(), smapper.popI(), ">", topMostLabel);
+ i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(out), smapper.popI(out), ">", topMostLabel);
break;
case ByteCodeParser.opc_if_icmpge:
- i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(), smapper.popI(), ">=", topMostLabel);
+ i = byteCodeToJavaScript.generateIf(out, smapper, byteCodes, i, smapper.popI(out), smapper.popI(out), ">=", topMostLabel);
break;
case ByteCodeParser.opc_goto:
{
smapper.flush(out);
int indx = i + ByteCodeToJavaScript.readShortArg(byteCodes, i);
- ByteCodeToJavaScript.goTo(out, i, indx, topMostLabel);
+ ByteCodeToJavaScript.goTo(out, i, indx, topMostLabel, smapper.alwaysUseGt());
i += 2;
break;
}
@@ -720,52 +725,52 @@ void loopCode(
break;
}
case ByteCodeParser.opc_arraylength:
- smapper.replace(out, VarType.INTEGER, "(@1).length", smapper.getA(0));
+ smapper.replace(out, VarType.INTEGER, "(@1).length", smapper.getA(out, 0));
break;
case ByteCodeParser.opc_lastore:
- ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popL(), smapper.popI(), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popL(out), smapper.popI(out), smapper.popA(out));
break;
case ByteCodeParser.opc_fastore:
- ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popF(), smapper.popI(), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popF(out), smapper.popI(out), smapper.popA(out));
break;
case ByteCodeParser.opc_dastore:
- ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popD(), smapper.popI(), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popD(out), smapper.popI(out), smapper.popA(out));
break;
case ByteCodeParser.opc_aastore:
- ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popA(), smapper.popI(), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popA(out), smapper.popI(out), smapper.popA(out));
break;
case ByteCodeParser.opc_iastore:
case ByteCodeParser.opc_bastore:
case ByteCodeParser.opc_castore:
case ByteCodeParser.opc_sastore:
- ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popI(), smapper.popI(), smapper.popA());
+ ByteCodeToJavaScript.emit(out, smapper, "Array.at(@3, @2, @1);", smapper.popI(out), smapper.popI(out), smapper.popA(out));
break;
case ByteCodeParser.opc_laload:
- smapper.replace(out, VarType.LONG, "(@2[@1] || Array.at(@2, @1))", smapper.popI(), smapper.getA(0));
+ smapper.replace(out, VarType.LONG, "(@2[@1] || Array.at(@2, @1))", smapper.popI(out), smapper.getA(out, 0));
break;
case ByteCodeParser.opc_faload:
- smapper.replace(out, VarType.FLOAT, "(@2[@1] || Array.at(@2, @1))", smapper.popI(), smapper.getA(0));
+ smapper.replace(out, VarType.FLOAT, "(@2[@1] || Array.at(@2, @1))", smapper.popI(out), smapper.getA(out, 0));
break;
case ByteCodeParser.opc_daload:
- smapper.replace(out, VarType.DOUBLE, "(@2[@1] || Array.at(@2, @1))", smapper.popI(), smapper.getA(0));
+ smapper.replace(out, VarType.DOUBLE, "(@2[@1] || Array.at(@2, @1))", smapper.popI(out), smapper.getA(out, 0));
break;
case ByteCodeParser.opc_aaload:
- smapper.replace(out, VarType.REFERENCE, "(@2[@1] || Array.at(@2, @1))", smapper.popI(), smapper.getA(0));
+ smapper.replace(out, VarType.REFERENCE, "(@2[@1] || Array.at(@2, @1))", smapper.popI(out), smapper.getA(out, 0));
break;
case ByteCodeParser.opc_iaload:
case ByteCodeParser.opc_baload:
case ByteCodeParser.opc_caload:
case ByteCodeParser.opc_saload:
- smapper.replace(out, VarType.INTEGER, "(@2[@1] || Array.at(@2, @1))", smapper.popI(), smapper.getA(0));
+ smapper.replace(out, VarType.INTEGER, "(@2[@1] || Array.at(@2, @1))", smapper.popI(out), smapper.getA(out, 0));
break;
case ByteCodeParser.opc_pop:
case ByteCodeParser.opc_pop2:
- smapper.pop(1);
+ smapper.pop(out, 1);
byteCodeToJavaScript.debug(out, "/* pop */");
break;
case ByteCodeParser.opc_dup:
{
- final Variable v = smapper.get(0);
+ final Variable v = smapper.get(out, 0);
if (smapper.isDirty()) {
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", smapper.pushT(v.getType()), v);
} else {
@@ -775,11 +780,11 @@ void loopCode(
}
case ByteCodeParser.opc_dup2:
{
- final Variable vi1 = smapper.get(0);
+ final Variable vi1 = smapper.get(out, 0);
if (vi1.isCategory2()) {
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2;", smapper.pushT(vi1.getType()), vi1);
} else {
- final Variable vi2 = smapper.get(1);
+ final Variable vi2 = smapper.get(out, 1);
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4;", smapper.pushT(vi2.getType()), vi2, smapper.pushT(vi1.getType()), vi1);
}
break;
@@ -788,9 +793,9 @@ void loopCode(
{
final Variable vi1 = smapper.pop(out);
final Variable vi2 = smapper.pop(out);
- final Variable vo3 = smapper.pushT(vi1.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo3 = smapper.pushT(vi1.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1);
break;
}
@@ -799,17 +804,17 @@ void loopCode(
final Variable vi1 = smapper.pop(out);
final Variable vi2 = smapper.pop(out);
if (vi1.isCategory2()) {
- final Variable vo3 = smapper.pushT(vi1.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo3 = smapper.pushT(vi1.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1);
} else {
final Variable vi3 = smapper.pop(out);
- final Variable vo5 = smapper.pushT(vi2.getType());
- final Variable vo4 = smapper.pushT(vi1.getType());
- final Variable vo3 = smapper.pushT(vi3.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo5 = smapper.pushT(vi2.getType());
+ final CharSequence vo4 = smapper.pushT(vi1.getType());
+ final CharSequence vo3 = smapper.pushT(vi3.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6,", vo1, vi1, vo2, vi2, vo3, vi3);
ByteCodeToJavaScript.emit(out, smapper, " @1 = @2, @3 = @4;", vo4, vo1, vo5, vo2);
}
@@ -820,16 +825,16 @@ void loopCode(
final Variable vi1 = smapper.pop(out);
final Variable vi2 = smapper.pop(out);
if (vi2.isCategory2()) {
- final Variable vo3 = smapper.pushT(vi1.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo3 = smapper.pushT(vi1.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1);
} else {
final Variable vi3 = smapper.pop(out);
- final Variable vo4 = smapper.pushT(vi1.getType());
- final Variable vo3 = smapper.pushT(vi3.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo4 = smapper.pushT(vi1.getType());
+ final CharSequence vo3 = smapper.pushT(vi3.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
}
break;
@@ -840,36 +845,36 @@ void loopCode(
final Variable vi2 = smapper.pop(out);
if (vi1.isCategory2()) {
if (vi2.isCategory2()) {
- final Variable vo3 = smapper.pushT(vi1.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo3 = smapper.pushT(vi1.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1);
} else {
final Variable vi3 = smapper.pop(out);
- final Variable vo4 = smapper.pushT(vi1.getType());
- final Variable vo3 = smapper.pushT(vi3.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo4 = smapper.pushT(vi1.getType());
+ final CharSequence vo3 = smapper.pushT(vi3.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
}
} else {
final Variable vi3 = smapper.pop(out);
if (vi3.isCategory2()) {
- final Variable vo5 = smapper.pushT(vi2.getType());
- final Variable vo4 = smapper.pushT(vi1.getType());
- final Variable vo3 = smapper.pushT(vi3.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo5 = smapper.pushT(vi2.getType());
+ final CharSequence vo4 = smapper.pushT(vi1.getType());
+ final CharSequence vo3 = smapper.pushT(vi3.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6,", vo1, vi1, vo2, vi2, vo3, vi3);
ByteCodeToJavaScript.emit(out, smapper, " @1 = @2, @3 = @4;", vo4, vo1, vo5, vo2);
} else {
final Variable vi4 = smapper.pop(out);
- final Variable vo6 = smapper.pushT(vi2.getType());
- final Variable vo5 = smapper.pushT(vi1.getType());
- final Variable vo4 = smapper.pushT(vi4.getType());
- final Variable vo3 = smapper.pushT(vi3.getType());
- final Variable vo2 = smapper.pushT(vi2.getType());
- final Variable vo1 = smapper.pushT(vi1.getType());
+ final CharSequence vo6 = smapper.pushT(vi2.getType());
+ final CharSequence vo5 = smapper.pushT(vi1.getType());
+ final CharSequence vo4 = smapper.pushT(vi4.getType());
+ final CharSequence vo3 = smapper.pushT(vi3.getType());
+ final CharSequence vo2 = smapper.pushT(vi2.getType());
+ final CharSequence vo1 = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vi4);
ByteCodeToJavaScript.emit(out, smapper, " @1 = @2, @3 = @4;", vo5, vo1, vo6, vo2);
}
@@ -878,11 +883,11 @@ void loopCode(
}
case ByteCodeParser.opc_swap:
{
- final Variable vi1 = smapper.get(0);
- final Variable vi2 = smapper.get(1);
- final Variable tmp = smapper.pushT(vi1.getType());
+ final Variable vi1 = smapper.get(out, 0);
+ final Variable vi2 = smapper.get(out, 1);
+ final CharSequence tmp = smapper.pushT(vi1.getType());
ByteCodeToJavaScript.emit(out, smapper, "var @1 = @2, @2 = @3, @3 = @1;", tmp, vi1, vi2);
- smapper.pop(1);
+ smapper.pop(out, 1);
break;
}
case ByteCodeParser.opc_bipush:
@@ -901,10 +906,10 @@ void loopCode(
if (field == null) {
final String mangleClass = ByteCodeToJavaScript.mangleClassName(fi[0]);
final String mangleClassAccess = byteCodeToJavaScript.accessClassFalse(mangleClass);
- smapper.replace(out, type, "@2.call(@1)", smapper.getA(0), byteCodeToJavaScript.accessField(mangleClassAccess, null, fi));
+ smapper.replace(out, type, "@2.call(@1)", smapper.getA(out, 0), byteCodeToJavaScript.accessField(mangleClassAccess, null, fi));
} else {
final String fieldOwner = ByteCodeToJavaScript.mangleClassName(field.cls.getClassName());
- smapper.replace(out, type, "@1@2", smapper.getA(0), byteCodeToJavaScript.accessField(fieldOwner, field, fi));
+ smapper.replace(out, type, "@1@2", smapper.getA(out, 0), byteCodeToJavaScript.accessField(fieldOwner, field, fi));
}
i += 2;
byteCodeToJavaScript.addReference(out, fi[0]);
@@ -919,10 +924,10 @@ void loopCode(
if (field == null) {
final String mangleClass = ByteCodeToJavaScript.mangleClassName(fi[0]);
final String mangleClassAccess = byteCodeToJavaScript.accessClassFalse(mangleClass);
- ByteCodeToJavaScript.emit(out, smapper, "@3.call(@2, @1);", smapper.popT(type), smapper.popA(), byteCodeToJavaScript.accessField(mangleClassAccess, null, fi));
+ ByteCodeToJavaScript.emit(out, smapper, "@3.call(@2, @1);", smapper.popT(out, type), smapper.popA(out), byteCodeToJavaScript.accessField(mangleClassAccess, null, fi));
} else {
final String fieldOwner = ByteCodeToJavaScript.mangleClassName(field.cls.getClassName());
- ByteCodeToJavaScript.emit(out, smapper, "@2@3 = @1;", smapper.popT(type), smapper.popA(), byteCodeToJavaScript.accessField(fieldOwner, field, fi));
+ ByteCodeToJavaScript.emit(out, smapper, "@2@3 = @1;", smapper.popT(out, type), smapper.popA(out), byteCodeToJavaScript.accessField(fieldOwner, field, fi));
}
i += 2;
byteCodeToJavaScript.addReference(out, fi[0]);
@@ -946,7 +951,7 @@ void loopCode(
int indx = ByteCodeToJavaScript.readUShortArg(byteCodes, i);
String[] fi = jc.getFieldInfoName(indx);
final int type = VarType.fromFieldType(fi[2].charAt(0));
- ByteCodeToJavaScript.emit(out, smapper, "@1._@2(@3);", byteCodeToJavaScript.accessClassFalse(ByteCodeToJavaScript.mangleClassName(fi[0])), fi[1], smapper.popT(type));
+ ByteCodeToJavaScript.emit(out, smapper, "@1._@2(@3);", byteCodeToJavaScript.accessClassFalse(ByteCodeToJavaScript.mangleClassName(fi[0])), fi[1], smapper.popT(out, type));
i += 2;
byteCodeToJavaScript.addReference(out, fi[0]);
break;
@@ -967,21 +972,21 @@ void loopCode(
}
case ByteCodeParser.opc_athrow:
{
- final CharSequence v = smapper.popA();
+ final CharSequence v = smapper.popA(out);
smapper.clear();
ByteCodeToJavaScript.emit(out, smapper, "{ var @1 = @2; throw @2; }", smapper.pushA(), v);
break;
}
case ByteCodeParser.opc_monitorenter:
{
- byteCodeToJavaScript.debug(null, "/* monitor enter */");
- smapper.popA();
+ byteCodeToJavaScript.debug(out, "/* monitor enter */");
+ smapper.popA(out);
break;
}
case ByteCodeParser.opc_monitorexit:
{
- byteCodeToJavaScript.debug(null, "/* monitor exit */");
- smapper.popA();
+ byteCodeToJavaScript.debug(out, "/* monitor exit */");
+ smapper.popA(out);
break;
}
case ByteCodeParser.opc_wide:
@@ -999,9 +1004,10 @@ void loopCode(
if (modified) {
out.append("\n");
}
+ smapper.finishStatement(out);
}
if (previousTrap != null) {
- byteCodeToJavaScript.generateCatch(out, previousTrap, byteCodes.length, topMostLabel);
+ byteCodeToJavaScript.generateCatch(out, smapper, previousTrap, byteCodes.length, topMostLabel, smapper.alwaysUseGt());
}
if (didBranches) {
out.append("\n }\n");
@@ -1011,7 +1017,7 @@ void loopCode(
}
}
- private void handleIndy(int indx, String[] methodAndType, String[] mi, ByteCodeParser.BootMethodData bm, StackMapper mapper) throws IOException {
+ private void handleIndy(int indx, String[] methodAndType, String[] mi, ByteCodeParser.BootMethodData bm, AbstractStackMapper mapper) throws IOException {
for (IndyHandler h : byteCodeToJavaScript.getIndyHandlers()) {
if (h.factoryClazz.equals(mi[0]) && h.factoryMethod.equals(mi[1])) {
IndyHandler.Ctx ctx = new IndyHandler.Ctx(out, mapper, byteCodeToJavaScript, methodAndType, bm);
@@ -1033,7 +1039,7 @@ private void handleIndy(int indx, String[] methodAndType, String[] mi, ByteCodeP
mapper.pushT(type);
}
- int invokeVirtualMethod(Appendable out, byte[] byteCodes, int i, final StackMapper mapper) throws IOException {
+ int invokeVirtualMethod(Appendable out, byte[] byteCodes, int i, final AbstractStackMapper mapper) throws IOException {
int methodIndex = ByteCodeToJavaScript.readUShortArg(byteCodes, i);
String[] mi = jc.getFieldInfoName(methodIndex);
char[] returnType = {'V'};
@@ -1042,7 +1048,7 @@ int invokeVirtualMethod(Appendable out, byte[] byteCodes, int i, final StackMapp
final int numArguments = cnt.length() + 1;
final CharSequence[] vars = new CharSequence[numArguments];
for (int j = numArguments - 1; j >= 0; --j) {
- vars[j] = mapper.popValue();
+ vars[j] = mapper.popValue(out);
}
if (returnType[0] != 'V') {
mapper.flush(out);
@@ -1063,7 +1069,7 @@ int invokeVirtualMethod(Appendable out, byte[] byteCodes, int i, final StackMapp
return i;
}
- int invokeStaticMethod(Appendable out, byte[] byteCodes, int i, final StackMapper mapper, boolean isStatic) throws IOException {
+ int invokeStaticMethod(Appendable out, byte[] byteCodes, int i, final AbstractStackMapper mapper, boolean isStatic) throws IOException {
int methodIndex = ByteCodeToJavaScript.readUShortArg(byteCodes, i);
String[] mi = jc.getFieldInfoName(methodIndex);
char[] returnType = {'V'};
@@ -1072,7 +1078,7 @@ int invokeStaticMethod(Appendable out, byte[] byteCodes, int i, final StackMappe
final int numArguments = isStatic ? cnt.length() : cnt.length() + 1;
final CharSequence[] vars = new CharSequence[numArguments];
for (int j = numArguments - 1; j >= 0; --j) {
- vars[j] = mapper.popValue();
+ vars[j] = mapper.popValue(out);
}
if ("java/lang/Object".equals(mi[0]) && "".equals(mi[1])) {
return i + 2;
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/MetafactoryHandler.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/MetafactoryHandler.java
index 64440b0fd..8e10ee382 100644
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/MetafactoryHandler.java
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/MetafactoryHandler.java
@@ -78,14 +78,14 @@ protected boolean handle(Ctx ctx) throws IOException {
fixedArgsCount = cnt.length();
final CharSequence[] vars = new CharSequence[fixedArgsCount];
for (int j = fixedArgsCount - 1; j >= 0; --j) {
- vars[j] = ctx.stackMapper.popValue();
+ vars[j] = ctx.stackMapper.popValue(ctx.out);
}
assert returnType[0] == 'L';
ctx.stackMapper.flush(ctx.out);
- final Variable samVar = ctx.stackMapper.pushA();
+ final CharSequence samVar = ctx.stackMapper.pushA();
ctx.out.append("var ").append(samVar).append(" = ").append(interfaceToCreate).append(".constructor.$class.$lambda([");
String sep = "";
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/OldStackMapper.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/OldStackMapper.java
new file mode 100644
index 000000000..1ed514849
--- /dev/null
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/OldStackMapper.java
@@ -0,0 +1,132 @@
+/**
+ * Back 2 Browser Bytecode Translator
+ * Copyright (C) 2012-2018 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.vm4brwsr;
+
+import java.io.IOException;
+
+final class OldStackMapper extends AbstractStackMapper {
+ int counter;
+ int flushed;
+
+ OldStackMapper() {
+ }
+
+ @Override
+ public void clear() {
+ }
+
+ @Override
+ public void syncWithFrameStack(ByteCodeParser.TypeArray frameStack) {
+ }
+
+ @Override
+ int initCode(Appendable out) throws IOException {
+ out.append(" var gt = 0;\n");
+ out.append(" var stack = [];\n");
+ out.append(" X_0: for (;;) {\n");
+ return 1;
+ }
+
+ @Override
+ public CharSequence pushT(int type) {
+ return Variable.getStackVariable(VarType.REFERENCE, ++counter);
+ }
+
+ @Override
+ void assign(Appendable out, int varType, CharSequence s) throws IOException {
+ out.append("stack.push(").append(s).append(");");
+ }
+
+ @Override
+ void replace(Appendable out, int varType, String format, CharSequence... arr) throws IOException {
+ out.append("stack[stack.length - 1] = ");
+ ByteCodeToJavaScript.emitImpl(out, format, arr);
+ out.append(";\n");
+ }
+
+ @Override
+ void flush(Appendable out) throws IOException {
+ }
+
+ @Override
+ void finishStatement(Appendable out) throws IOException {
+ while (flushed < counter) {
+ out.append("stack.push(").append(Variable.getStackVariable(VarType.REFERENCE, ++flushed)).append(");\n");
+ }
+ out.append("}\n");
+ }
+
+ @Override
+ public boolean isDirty() {
+ return false;
+ }
+
+ @Override
+ public CharSequence popT(Appendable out, int type) throws IOException {
+ Variable v = Variable.getStackVariable(VarType.REFERENCE, ++counter);
+ out.append("var ").append(v).append(" = stack.pop();\n");
+ flushed = counter;
+ return v;
+ }
+
+ @Override
+ public CharSequence popValue(Appendable out) throws IOException {
+ return pop(out);
+ }
+
+ @Override
+ public Variable pop(Appendable out) throws IOException {
+ Variable v = Variable.getStackVariable(VarType.REFERENCE, ++counter);
+ out.append("var ").append(v).append(" = stack.pop();\n");
+ flushed = counter;
+ return v;
+ }
+
+ @Override
+ public void pop(Appendable out, int count) throws IOException {
+ while (count-- > 0) {
+ out.append("stack.pop();");
+ }
+ }
+
+ @Override
+ public CharSequence getT(Appendable out, int indexFromTop, int type, boolean clear) throws IOException {
+ Variable v = Variable.getStackVariable(VarType.REFERENCE, ++counter);
+ out.append("var ").append(v).append(" = stack[stack.length - " + (indexFromTop + 1) + "];\n");
+ flushed = counter;
+ return v;
+ }
+
+ @Override
+ public Variable get(Appendable out, int indexFromTop) throws IOException {
+ Variable v = Variable.getStackVariable(VarType.REFERENCE, ++counter);
+ out.append("var ").append(v).append(" = stack[stack.length - " + (indexFromTop + 1) + "];\n");
+ flushed = counter;
+ return v;
+ }
+
+ @Override
+ boolean alwaysUseGt() {
+ return true;
+ }
+
+ @Override
+ void caughtException(Appendable out, String e) throws IOException {
+ out.append("stack = [").append(e).append("];");
+ }
+}
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java
index 0fc02d316..788d7a6c3 100644
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java
@@ -20,7 +20,7 @@
import java.io.IOException;
import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray;
-final class StackMapper {
+final class StackMapper extends AbstractStackMapper {
private final TypeArray stackTypeIndexPairs;
private final StringArray stackValues;
private boolean dirty;
@@ -45,34 +45,17 @@ public void syncWithFrameStack(final TypeArray frameStack) {
}
}
- public Variable pushI() {
- return pushT(VarType.INTEGER);
- }
-
- public Variable pushL() {
- return pushT(VarType.LONG);
- }
-
- public Variable pushF() {
- return pushT(VarType.FLOAT);
- }
-
- public Variable pushD() {
- return pushT(VarType.DOUBLE);
- }
-
- public Variable pushA() {
- return pushT(VarType.REFERENCE);
- }
-
+ @Override
public Variable pushT(final int type) {
return getVariable(pushTypeImpl(type));
}
+ @Override
void assign(Appendable out, int varType, CharSequence s) throws IOException {
pushTypeAndValue(varType, s);
}
+ @Override
void replace(Appendable out, int varType, String format, CharSequence... arr)
throws IOException {
StringBuilder sb = new StringBuilder();
@@ -84,7 +67,12 @@ void replace(Appendable out, int varType, String format, CharSequence... arr)
final int value = (last << 8) | (varType & 0xff);
stackTypeIndexPairs.set(last, value);
}
+
+ @Override
+ void finishStatement(Appendable out) throws IOException {
+ }
+ @Override
void flush(Appendable out) throws IOException {
int count = stackTypeIndexPairs.getSize();
for (int i = 0; i < count; i++) {
@@ -98,49 +86,34 @@ void flush(Appendable out) throws IOException {
dirty = false;
}
+ @Override
public boolean isDirty() {
return dirty;
}
- public CharSequence popI() {
- return popT(VarType.INTEGER);
- }
-
- public CharSequence popL() {
- return popT(VarType.LONG);
- }
-
- public CharSequence popF() {
- return popT(VarType.FLOAT);
- }
-
- public CharSequence popD() {
- return popT(VarType.DOUBLE);
- }
-
- public CharSequence popA() {
- return popT(VarType.REFERENCE);
- }
-
- public CharSequence popT(final int type) {
- final CharSequence variable = getT(0, type);
+ @Override
+ public CharSequence popT(Appendable out, final int type) throws IOException {
+ final CharSequence variable = getT(out, 0, type);
popImpl(1);
return variable;
}
- public CharSequence popValue() {
- final CharSequence variable = getT(0, -1);
+ @Override
+ public CharSequence popValue(Appendable out) throws IOException {
+ final CharSequence variable = getT(out, 0, -1);
popImpl(1);
return variable;
}
+ @Override
public Variable pop(Appendable out) throws IOException {
flush(out);
- final Variable variable = get(0);
+ final Variable variable = get(out, 0);
popImpl(1);
return variable;
}
- public void pop(final int count) {
+ @Override
+ public void pop(Appendable out, final int count) {
final int stackSize = stackTypeIndexPairs.getSize();
if (count > stackSize) {
throw new IllegalStateException("Stack underflow");
@@ -148,30 +121,8 @@ public void pop(final int count) {
popImpl(count);
}
- public CharSequence getI(final int indexFromTop) {
- return getT(indexFromTop, VarType.INTEGER);
- }
-
- public CharSequence getL(final int indexFromTop) {
- return getT(indexFromTop, VarType.LONG);
- }
-
- public CharSequence getF(final int indexFromTop) {
- return getT(indexFromTop, VarType.FLOAT);
- }
-
- public CharSequence getD(final int indexFromTop) {
- return getT(indexFromTop, VarType.DOUBLE);
- }
-
- public CharSequence getA(final int indexFromTop) {
- return getT(indexFromTop, VarType.REFERENCE);
- }
-
- public CharSequence getT(final int indexFromTop, final int type) {
- return getT(indexFromTop, type, true);
- }
- public CharSequence getT(final int indexFromTop, final int type, boolean clear) {
+ @Override
+ public CharSequence getT(Appendable out, final int indexFromTop, final int type, boolean clear) {
final int stackSize = stackTypeIndexPairs.getSize();
if (indexFromTop >= stackSize) {
throw new IllegalStateException("Stack underflow");
@@ -189,7 +140,8 @@ public CharSequence getT(final int indexFromTop, final int type, boolean clear)
return getVariable(stackValue);
}
- public Variable get(final int indexFromTop) {
+ @Override
+ public Variable get(Appendable out, final int indexFromTop) {
final int stackSize = stackTypeIndexPairs.getSize();
if (indexFromTop >= stackSize) {
throw new IllegalStateException("Stack underflow");
@@ -232,10 +184,18 @@ private void popImpl(final int count) {
stackTypeIndexPairs.setSize(stackSize - count);
}
- public Variable getVariable(final int typeAndIndex) {
- final int type = typeAndIndex & 0xff;
- final int index = typeAndIndex >> 8;
+ @Override
+ boolean alwaysUseGt() {
+ return false;
+ }
+
+ @Override
+ int initCode(Appendable out) throws IOException {
+ return 0;
+ }
- return Variable.getStackVariable(type, index);
+ @Override
+ void caughtException(Appendable out, String e) throws IOException {
+ out.append("var stA0 = ").append(e).append(";");
}
}
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringConcatHandler.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringConcatHandler.java
index 8338748a3..f023eef71 100644
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringConcatHandler.java
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringConcatHandler.java
@@ -38,13 +38,13 @@ protected boolean handle(Ctx ctx) throws IOException {
fixedArgsCount = cnt.length();
final CharSequence[] vars = new CharSequence[fixedArgsCount];
for (int j = fixedArgsCount - 1; j >= 0; --j) {
- vars[j] = ctx.stackMapper.popValue();
+ vars[j] = ctx.stackMapper.popValue(ctx.out);
}
ctx.stackMapper.flush(ctx.out);
- final Variable stringVar = ctx.stackMapper.pushA();
+ final CharSequence stringVar = ctx.stackMapper.pushA();
ctx.out.append("\nvar ").append(stringVar).append(" = ");
StringBuilder sep = new StringBuilder();
diff --git a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java
index 371c34782..b371cc480 100644
--- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java
+++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java
@@ -224,7 +224,12 @@ private void generateBody(Appendable out, StringArray names) throws IOException
if (name == null) {
break;
}
- InputStream is = resources.get(name + ".class");
+ InputStream is;
+ try {
+ is = resources.get(name + ".class");
+ } catch (IOException noSuchResource) {
+ is = null;
+ }
if (is == null) {
lazyReference(out, name);
skipClass.add(name);
@@ -235,7 +240,7 @@ private void generateBody(Appendable out, StringArray names) throws IOException
processed.add(name);
initCode.add(ic == null ? "" : ic);
} catch (RuntimeException ex) {
- throw new IOException("Error while compiling " + name + "\n", ex);
+ throw new IOException("Error while compiling " + name + "\n" + ex.getClass().getName() + ": " + ex.getMessage(), ex);
}
}
diff --git a/rt/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java b/rt/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java
index b04becd56..43ee54d0a 100644
--- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java
+++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java
@@ -46,7 +46,8 @@ static byte[] readClass(String name) throws IOException {
if (u == null) {
throw new IOException("Can't find " + name);
}
- try (InputStream is = u.openStream()) {
+ InputStream is = u.openStream();
+ try {
byte[] arr;
arr = new byte[is.available()];
int offset = 0;
@@ -58,6 +59,8 @@ static byte[] readClass(String name) throws IOException {
offset += len;
}
return arr;
+ } finally {
+ is.close();
}
}
diff --git a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java
index 176ad0178..420daf1d9 100644
--- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java
+++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java
@@ -281,7 +281,7 @@ public static Object reflectiveMethodCall(boolean direct, String mn) throws Exce
public static int reflectiveSum(int a, int b) throws Exception {
Method m = StaticMethod.class.getMethod("sum", int.class, int.class);
- return (int) m.invoke(null, a, b);
+ return ((Number) m.invoke(null, a, b)).intValue();
}
private abstract class Application {
diff --git a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Exceptions.java b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Exceptions.java
index 0408f8844..462685bfd 100644
--- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Exceptions.java
+++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Exceptions.java
@@ -71,7 +71,9 @@ public static String newInstance(String n) {
return ("CNFE:" + ex.getMessage()).toString();
}
return c.newInstance().getClass().getName();
- } catch (InstantiationException | IllegalAccessException ex) {
+ } catch (InstantiationException ex) {
+ return ex.getMessage();
+ } catch (IllegalAccessException ex) {
return ex.getMessage();
}
}
diff --git a/rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java b/rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java
index e9ab684fd..f98306477 100644
--- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java
+++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java
@@ -26,6 +26,7 @@
import java.io.IOException;
import java.io.InputStream;
import static org.testng.Assert.*;
+import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -37,7 +38,8 @@
public class SizeOfAMethodTest {
private static String code;
- @Test public void sumXYShouldBeSmall() {
+ @Test
+ public void sumXYShouldBeSmall() {
String s = code;
int beg = s.indexOf("c.sum__III");
int end = s.indexOf(".access", beg);
@@ -46,7 +48,8 @@ public class SizeOfAMethodTest {
assertTrue(beg < end, "Found end of sum method in " + code);
String method = s.substring(beg, end);
-
+
+ assumeNewStackMapper(method);
assertEquals(method.indexOf("st"), -1, "There should be no stack operations:\n" + method);
}
@@ -61,10 +64,13 @@ public class SizeOfAMethodTest {
String method = s.substring(beg, end);
+ assumeNewStackMapper(method);
+
assertEquals(method.indexOf("stA1"), -1, "No need for stA1 register:\n" + method);
}
- @Test public void deepConstructor() {
+ @Test
+ public void deepConstructor() {
String s = code;
int beg = s.indexOf("c.intHolder__I");
int end = s.indexOf(".access", beg);
@@ -73,11 +79,14 @@ public class SizeOfAMethodTest {
assertTrue(beg < end, "Found end of intHolder method in " + code);
String method = s.substring(beg, end);
+
+ assumeNewStackMapper(method);
assertEquals(method.indexOf("stA3"), -1, "No need for stA3 register on second constructor:\n" + method);
}
- @Test public void emptyConstructorRequiresNoStack() {
+ @Test
+ public void emptyConstructorRequiresNoStack() {
String s = code;
int beg = s.indexOf("CLS.cons__V");
int end = s.indexOf(".access", beg);
@@ -87,12 +96,15 @@ public class SizeOfAMethodTest {
String method = s.substring(beg, end);
method = method.replace("constructor", "CNSTR");
+
+ assumeNewStackMapper(method);
assertEquals(method.indexOf("st"), -1, "There should be no stack operations:\n" + method);
assertEquals(method.indexOf("for"), -1, "There should be no for blocks:\n" + method);
}
- @Test public void dontGeneratePrimitiveFinalConstants() {
+ @Test
+ public void dontGeneratePrimitiveFinalConstants() {
assertEquals(code.indexOf("MISSING_CONSTANT"), -1, "MISSING_CONSTANT field should not be generated");
}
@@ -117,5 +129,12 @@ public InputStream get(String resource) throws IOException {
public static void releaseTheCode() {
code = null;
}
+
+ private static void assumeNewStackMapper(String code) {
+ int stackArray = code.indexOf("var stack = [];");
+ if (stackArray >= 0) {
+ throw new SkipException("Skipping the text as code contains stack = []");
+ }
+ }
}
diff --git a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StackMapperTest.java b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StackMapperTest.java
index d96ae392b..2b33fa47f 100644
--- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StackMapperTest.java
+++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StackMapperTest.java
@@ -34,28 +34,28 @@ public StackMapperTest() {
throws Exception {
StringBuilder sb = new StringBuilder();
- StackMapper smapper = new StackMapper();
+ AbstractStackMapper smapper = new StackMapper();
smapper.assign(sb, VarType.INTEGER, "0");
smapper.assign(sb, VarType.REFERENCE, "arr");
smapper.assign(sb, VarType.INTEGER, "33");
smapper.replace(sb, VarType.INTEGER, "@2[@1]",
- smapper.popI(), smapper.getA(0)
+ smapper.popI(sb), smapper.getA(sb, 0)
);
smapper.replace(sb, VarType.INTEGER, "(@1) + (@2)",
- smapper.getI(1), smapper.popI()
+ smapper.getI(sb, 1), smapper.popI(sb)
);
smapper.assign(sb, VarType.REFERENCE, "arr");
smapper.assign(sb, VarType.INTEGER, "22");
smapper.replace(sb, VarType.INTEGER, "@2[@1]",
- smapper.popI(), smapper.getA(0)
+ smapper.popI(sb), smapper.getA(sb, 0)
);
smapper.replace(sb, VarType.INTEGER, "(@1) + (@2)",
- smapper.getI(1), smapper.popI()
+ smapper.getI(sb, 1), smapper.popI(sb)
);
smapper.flush(sb);
diff --git a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java
index fbbc96d52..4b66d3e32 100644
--- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java
+++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java
@@ -104,12 +104,10 @@ public static int countAB(String txt) {
}
public static int stringSwitch(String txt) {
- switch (txt) {
- case "jedna": return 1;
- case "dve": return 2;
- case "tri": return 3;
- case "ctyri": return 4;
- }
+ if ("jedna".equals(txt)) return 1;
+ if ("dve".equals(txt)) return 2;
+ if ("tri".equals(txt)) return 3;
+ if ("ctyri".equals(txt)) return 4;
return -1;
}
diff --git a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java
index d3da77edc..f46e3fec9 100644
--- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java
+++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java
@@ -85,13 +85,24 @@ public class StringTest {
);
}
- @Test(timeOut=10000) public void toStringConcatenation() throws Exception {
+ @Test
+ public void toStringConcatenation1() throws Exception {
+ assertExec(
+ "Five executions should generate 5Hello World!",
+ StringSample.class, "toStringTest__Ljava_lang_String_2I",
+ "Hello World!1", 1
+ );
+ }
+
+ @Test
+ public void toStringConcatenation5() throws Exception {
assertExec(
"Five executions should generate 5Hello World!",
StringSample.class, "toStringTest__Ljava_lang_String_2I",
"Hello World!5", 5
);
}
+
@Test public void toStringConcatenationJava() throws Exception {
assertEquals("Hello World!5", StringSample.toStringTest(5));
}