diff --git a/teavm-core/src/main/java/org/teavm/model/ValueType.java b/teavm-core/src/main/java/org/teavm/model/ValueType.java
index 9cc6adacc..5e1dc9982 100644
--- a/teavm-core/src/main/java/org/teavm/model/ValueType.java
+++ b/teavm-core/src/main/java/org/teavm/model/ValueType.java
@@ -265,6 +265,10 @@ public abstract class ValueType {
public abstract boolean isObject(String cls);
+ public boolean isObject(Class> cls) {
+ return isObject(cls.getName());
+ }
+
private static ValueType parseImpl(String string) {
switch (string.charAt(0)) {
case 'Z':
diff --git a/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JS.java b/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JS.java
index 8e3bd8901..690385ba9 100644
--- a/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JS.java
+++ b/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JS.java
@@ -17,6 +17,7 @@ package org.teavm.jso.plugin;
import java.lang.reflect.Array;
import java.util.Iterator;
+import java.util.function.Function;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.javascript.spi.InjectedBy;
@@ -28,30 +29,54 @@ import org.teavm.jso.core.JSBoolean;
import org.teavm.jso.core.JSNumber;
import org.teavm.jso.core.JSString;
-/**
- *
Container of static methods to manipulate over {@link JSObject}s.
- *
- * @author Alexey Andreev
- */
final class JS {
private JS() {
}
- /**
- * Gets global JavaScript object, that is similar to the window
object in the browser.
- * @return global object.
- */
- @JSBody(params = {}, script = "return window;")
- public static native JSObject getGlobal();
+ @InjectedBy(JSNativeGenerator.class)
+ public static native JSObject wrap(byte value);
@InjectedBy(JSNativeGenerator.class)
- public static native JSObject wrap(String str);
+ public static native JSObject wrap(short value);
@InjectedBy(JSNativeGenerator.class)
- public static native JSObject wrap(char c);
+ public static native JSObject wrap(int value);
@InjectedBy(JSNativeGenerator.class)
- public static native JSObject marshall(Object obj);
+ public static native JSObject wrap(char value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native JSObject wrap(float value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native JSObject wrap(double value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native JSObject wrap(boolean value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native JSObject wrap(String value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native byte unwrapByte(JSObject value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native short unwrapShort(JSObject value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native int unwrapInt(JSObject value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native float unwrapFloat(JSObject value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native double unwrapDouble(JSObject value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native boolean unwrapBoolean(JSObject value);
+
+ @InjectedBy(JSNativeGenerator.class)
+ public static native String unwrapString(JSObject value);
public static JSArray wrap(T[] array) {
JSArray result = JSArray.create(array.length);
@@ -61,20 +86,20 @@ final class JS {
return result;
}
- public static JSArray> wrap(T[][] array) {
- JSArray> result = JSArray.create(array.length);
+ public static Function> arrayWrapper() {
+ return JS::wrap;
+ }
+
+ public static JSArray map(S[] array, Function f) {
+ JSArray result = JSArray.create(array.length);
for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
+ result.set(i, f.apply(array[i]));
}
return result;
}
- public static JSArray>> wrap(T[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> arrayMapper(Function f) {
+ return array -> map(array, f);
}
public static JSArray wrap(boolean[] array) {
@@ -85,20 +110,8 @@ final class JS {
return result;
}
- public static JSArray> wrap(boolean[][] array) {
- JSArray> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
- }
-
- public static JSArray>> wrap(boolean[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> booleanArrayWrapper() {
+ return JS::wrap;
}
public static JSArray wrap(byte[] array) {
@@ -109,20 +122,8 @@ final class JS {
return result;
}
- public static JSArray> wrap(byte[][] array) {
- JSArray> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
- }
-
- public static JSArray>> wrap(byte[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> byteArrayWrapper() {
+ return JS::wrap;
}
public static JSArray wrap(short[] array) {
@@ -133,20 +134,8 @@ final class JS {
return result;
}
- public static JSArray> wrap(short[][] array) {
- JSArray> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
- }
-
- public static JSArray>> wrap(short[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> shortArrayWrapper() {
+ return JS::wrap;
}
public static JSArray wrap(char[] array) {
@@ -157,20 +146,8 @@ final class JS {
return result;
}
- public static JSArray> wrap(char[][] array) {
- JSArray> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
- }
-
- public static JSArray>> wrap(char[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> charArrayWrapper() {
+ return JS::wrap;
}
public static JSArray wrap(int[] array) {
@@ -181,20 +158,8 @@ final class JS {
return result;
}
- public static JSArray> wrap(int[][] array) {
- JSArray> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
- }
-
- public static JSArray>> wrap(int[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> intArrayWrapper() {
+ return JS::wrap;
}
public static JSArray wrap(String[] array) {
@@ -205,20 +170,8 @@ final class JS {
return result;
}
- public static JSArray> wrap(String[][] array) {
- JSArray> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
- }
-
- public static JSArray>> wrap(String[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> stringArrayWrapper() {
+ return JS::wrap;
}
public static JSArray wrap(float[] array) {
@@ -229,20 +182,8 @@ final class JS {
return result;
}
- public static JSArray> wrap(float[][] array) {
- JSArray> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
- }
-
- public static JSArray>> wrap(float[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> floatArrayWrapper() {
+ return JS::wrap;
}
public static JSArray wrap(double[] array) {
@@ -253,30 +194,11 @@ final class JS {
return result;
}
- public static JSArray> wrap(double[][] array) {
- JSArray> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
+ public static Function> doubleArrayWrapper() {
+ return JS::wrap;
}
- public static JSArray>> wrap(double[][][] array) {
- JSArray>> result = JSArray.create(array.length);
- for (int i = 0; i < array.length; ++i) {
- result.set(i, wrap(array[i]));
- }
- return result;
- }
-
- @InjectedBy(JSNativeGenerator.class)
- @PluggableDependency(JSNativeGenerator.class)
- public static native String unwrapString(JSObject obj);
-
- @InjectedBy(JSNativeGenerator.class)
- public static native char unwrapCharacter(JSObject obj);
-
- public static T[] unwrapArray(Class type, JSArray array) {
+ public static T[] unwrapArray(Class type, JSArrayReader array) {
@SuppressWarnings("unchecked")
T[] result = (T[]) Array.newInstance(type, array.getLength());
for (int i = 0; i < result.length; ++i) {
@@ -285,27 +207,118 @@ final class JS {
return result;
}
- public static T[][] unwrapArray2(Class type, JSArray> array) {
+ public static Function, T[]> arrayUnwrapper(Class type) {
+ return array -> unwrapArray(type, array);
+ }
+
+ public static T[] unmapArray(Class type, JSArrayReader array, Function f) {
@SuppressWarnings("unchecked")
- T[][] result = (T[][]) Array.newInstance(Array.newInstance(type, 0).getClass(), array.getLength());
+ T[] result = (T[]) Array.newInstance(type, array.getLength());
for (int i = 0; i < result.length; ++i) {
- result[i] = unwrapArray(type, array.get(i));
+ result[i] = f.apply(array.get(i));
}
return result;
}
- public static T[][][] unwrapArray3(Class type, JSArray>> array) {
- Class> baseType = Array.newInstance(type, 0).getClass();
- @SuppressWarnings("unchecked")
- T[][][] result = (T[][][]) Array.newInstance(Array.newInstance(baseType, 0).getClass(), array.getLength());
+ public static Function, T[]> arrayUnmapper(Class type, Function f) {
+ return array -> unmapArray(type, array, f);
+ }
+
+ public static boolean[] unwrapBooleanArray(JSArrayReader array) {
+ boolean[] result = new boolean[array.getLength()];
for (int i = 0; i < result.length; ++i) {
- result[i] = unwrapArray2(type, array.get(i));
+ result[i] = array.get(i).booleanValue();
}
return result;
}
- @JSBody(params = "obj", script = "return typeof(obj) === 'undefined';")
- public static native boolean isUndefined(JSObject obj);
+ public static Function, boolean[]> booleanArrayUnwrapper() {
+ return JS::unwrapBooleanArray;
+ }
+
+ public static byte[] unwrapByteArray(JSArrayReader array) {
+ byte[] result = new byte[array.getLength()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = array.get(i).byteValue();
+ }
+ return result;
+ }
+
+ public static Function, byte[]> byteArrayUnwrapper() {
+ return JS::unwrapByteArray;
+ }
+
+ public static short[] unwrapShortArray(JSArrayReader array) {
+ short[] result = new short[array.getLength()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = array.get(i).shortValue();
+ }
+ return result;
+ }
+
+ public static Function, short[]> shortArrayUnwrapper() {
+ return JS::unwrapShortArray;
+ }
+
+ public static int[] unwrapIntArray(JSArrayReader array) {
+ int[] result = new int[array.getLength()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = array.get(i).intValue();
+ }
+ return result;
+ }
+
+ public static Function, int[]> intArrayUnwrapper() {
+ return JS::unwrapIntArray;
+ }
+
+ public static char[] unwrapCharArray(JSArrayReader array) {
+ char[] result = new char[array.getLength()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = array.get(i).charValue();
+ }
+ return result;
+ }
+
+ public static Function, char[]> charArrayUnwrapper() {
+ return JS::unwrapCharArray;
+ }
+
+ public static float[] unwrapFloatArray(JSArrayReader array) {
+ float[] result = new float[array.getLength()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = array.get(i).floatValue();
+ }
+ return result;
+ }
+
+ public static Function, float[]> floatArrayUnwrapper() {
+ return JS::unwrapFloatArray;
+ }
+
+ public static double[] unwrapDoubleArray(JSArrayReader array) {
+ double[] result = new double[array.getLength()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = array.get(i).doubleValue();
+ }
+ return result;
+ }
+
+ public static Function, double[]> doubleArrayUnwrapper() {
+ return JS::unwrapDoubleArray;
+ }
+
+ public static String[] unwrapStringArray(JSArrayReader array) {
+ String[] result = new String[array.getLength()];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = array.get(i).stringValue();
+ }
+ return result;
+ }
+
+ public static Function, String[]> stringArrayUnwrapper() {
+ return JS::unwrapStringArray;
+ }
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@@ -333,7 +346,6 @@ final class JS {
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
JSObject d, JSObject e);
-
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
diff --git a/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JSNativeGenerator.java b/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JSNativeGenerator.java
index 85c4b123f..9406bfb08 100644
--- a/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JSNativeGenerator.java
+++ b/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JSNativeGenerator.java
@@ -17,7 +17,9 @@ package org.teavm.jso.plugin;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
-import org.teavm.dependency.*;
+import org.teavm.dependency.DependencyAgent;
+import org.teavm.dependency.DependencyPlugin;
+import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.Renderer;
import org.teavm.javascript.ast.ConstantExpr;
import org.teavm.javascript.ast.Expr;
@@ -72,19 +74,6 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
SourceWriter writer = context.getWriter();
switch (methodRef.getName()) {
- case "getGlobal":
- writer.append("window");
- break;
- case "isUndefined":
- writer.append("(");
- context.writeExpr(context.getArgument(0));
- writer.ws().append("===").ws().append("undefined)");
- break;
- case "getTypeName":
- writer.append("(typeof ");
- context.writeExpr(context.getArgument(0));
- writer.append(")");
- break;
case "get":
context.writeExpr(context.getArgument(0));
renderProperty(context.getArgument(1), context);
@@ -122,9 +111,6 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
}
writer.append("))");
break;
- case "marshall":
- context.writeExpr(context.getArgument(0));
- break;
case "wrap":
if (methodRef.getDescriptor().parameterType(0).isObject("java.lang.String")) {
if (context.getArgument(0) instanceof ConstantExpr) {
diff --git a/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java b/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java
index 7505162f8..e4a822f27 100644
--- a/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java
+++ b/teavm-jso-impl/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java
@@ -22,6 +22,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.javascript.spi.Sync;
@@ -33,6 +34,7 @@ import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.core.JSArray;
+import org.teavm.jso.core.JSArrayReader;
import org.teavm.model.AccessLevel;
import org.teavm.model.AnnotationHolder;
import org.teavm.model.AnnotationReader;
@@ -667,28 +669,136 @@ class JavascriptNativeProcessor {
++degree;
itemType = ((ValueType.Array) itemType).getItemType();
}
- if (degree > 3) {
- diagnostics.error(location, "Unsupported type: {{t0}}", type);
- return var;
+
+ CastInstruction castInsn = new CastInstruction();
+ castInsn.setValue(var);
+ castInsn.setTargetType(ValueType.parse(JSArrayReader.class));
+ var = program.createVariable();
+ castInsn.setReceiver(var);
+ castInsn.setLocation(location.getSourceLocation());
+ replacement.add(castInsn);
+
+ var = degree == 1
+ ? unwrapSingleDimensionArray(location, var, itemType)
+ : unwrapMultiDimensionArray(location, var, itemType, degree);
+
+ return var;
+ }
+
+ private Variable unwrapSingleDimensionArray(CallLocation location, Variable var, ValueType type) {
+ Variable result = program.createVariable();
+
+ InvokeInstruction insn = new InvokeInstruction();
+ insn.setMethod(singleDimensionArrayUnwrapper(type));
+ insn.setType(InvocationType.SPECIAL);
+
+ if (insn.getMethod().parameterCount() == 2) {
+ Variable cls = program.createVariable();
+ ClassConstantInstruction clsInsn = new ClassConstantInstruction();
+ clsInsn.setConstant(type);
+ clsInsn.setLocation(location.getSourceLocation());
+ clsInsn.setReceiver(cls);
+ replacement.add(clsInsn);
+ insn.getArguments().add(cls);
}
- if (itemType instanceof ValueType.Object) {
- String className = ((ValueType.Object) itemType).getClassName();
- if (className.equals("java.lang.String")) {
- String methodName = "unwrapStringArray";
- if (degree > 1) {
- methodName += degree;
- }
- ValueType argType = degree == 1
- ? ValueType.parse(JSStringArray.class)
- : ValueType.parse(JSArray.class);
- return unwrap(var, methodName, argType, type, location.getSourceLocation());
- } else if (isNative(className)) {
- return unwrapObjectArray(location, var, degree, itemType, type);
- }
+ insn.getArguments().add(var);
+ insn.setReceiver(result);
+ return result;
+ }
+
+ private Variable unwrapMultiDimensionArray(CallLocation location, Variable var, ValueType type, int degree) {
+ Variable function = program.createVariable();
+
+ InvokeInstruction insn = new InvokeInstruction();
+ insn.setMethod(multipleDimensionArrayUnwrapper(type));
+ insn.setType(InvocationType.SPECIAL);
+
+ if (insn.getMethod().parameterCount() == 1) {
+ Variable cls = program.createVariable();
+ ClassConstantInstruction clsInsn = new ClassConstantInstruction();
+ clsInsn.setConstant(type);
+ clsInsn.setLocation(location.getSourceLocation());
+ clsInsn.setReceiver(cls);
+ replacement.add(clsInsn);
+ insn.getArguments().add(cls);
}
- diagnostics.error(location, "Unsupported type: {{t0}}", type);
- return var;
+
+ insn.setReceiver(function);
+
+ while (--degree > 1) {
+ type = ValueType.arrayOf(type);
+ Variable cls = program.createVariable();
+
+ ClassConstantInstruction clsInsn = new ClassConstantInstruction();
+ clsInsn.setConstant(type);
+ clsInsn.setLocation(location.getSourceLocation());
+ clsInsn.setReceiver(cls);
+ replacement.add(clsInsn);
+
+ insn = new InvokeInstruction();
+ insn.setMethod(new MethodReference(JS.class, "arrayUnmapper", Class.class, Function.class,
+ Function.class));
+ insn.setType(InvocationType.SPECIAL);
+ insn.getArguments().add(cls);
+ insn.getArguments().add(function);
+ function = program.createVariable();
+ insn.setReceiver(function);
+ }
+
+ return null;
+ }
+
+ private MethodReference singleDimensionArrayUnwrapper(ValueType itemType) {
+ if (itemType instanceof ValueType.Primitive) {
+ switch (((ValueType.Primitive) itemType).getKind()) {
+ case BOOLEAN:
+ return new MethodReference(JS.class, "unwrapBooleanArray", JSArrayReader.class, boolean[].class);
+ case BYTE:
+ return new MethodReference(JS.class, "unwrapByteArray", JSArrayReader.class, byte[].class);
+ case SHORT:
+ return new MethodReference(JS.class, "unwrapShortArray", JSArrayReader.class, short[].class);
+ case CHARACTER:
+ return new MethodReference(JS.class, "unwrapCharArray", JSArrayReader.class, char[].class);
+ case INTEGER:
+ return new MethodReference(JS.class, "unwrapIntArray", JSArrayReader.class, int[].class);
+ case FLOAT:
+ return new MethodReference(JS.class, "unwrapFloatArray", JSArrayReader.class, float[].class);
+ case DOUBLE:
+ return new MethodReference(JS.class, "unwrapDoubleArray", JSArrayReader.class, double[].class);
+ default:
+ break;
+ }
+ } else if (itemType.isObject(String.class)) {
+ return new MethodReference(JS.class, "unwrapStringArray", JSArrayReader.class, String[].class);
+ }
+ return new MethodReference(JS.class, "unwrapArray", Class.class, JSArrayReader.class, byte[].class);
+ }
+
+ private MethodReference multipleDimensionArrayUnwrapper(ValueType itemType) {
+ if (itemType instanceof ValueType.Primitive) {
+ switch (((ValueType.Primitive) itemType).getKind()) {
+ case BOOLEAN:
+ return new MethodReference(JS.class, "booleanArrayUnwrapper", Function.class, Function.class);
+ case BYTE:
+ return new MethodReference(JS.class, "byteArrayUnwrapper", Function.class, Function.class);
+ case SHORT:
+ return new MethodReference(JS.class, "shortArrayUnwrapper", Function.class, Function.class);
+ case CHARACTER:
+ return new MethodReference(JS.class, "charArrayUnwrapper", Function.class, Function.class);
+ case INTEGER:
+ return new MethodReference(JS.class, "intArrayUnwrapper", Function.class, Function.class);
+ case FLOAT:
+ return new MethodReference(JS.class, "floatArrayUnwrapper", Function.class, Function.class);
+ case DOUBLE:
+ return new MethodReference(JS.class, "doubleArrayUnwrapper", Function.class, Function.class);
+ default:
+ break;
+ }
+ } else if (itemType.isObject(String.class)) {
+ return new MethodReference(JS.class, "stringArrayUnwrapper", Function.class, Function.class);
+ }
+ return new MethodReference(JS.class, "arrayUnwrapper", Class.class, Function.class, Function.class);
}
private Variable unwrap(Variable var, String methodName, ValueType argType, ValueType resultType,
@@ -714,57 +824,6 @@ class JavascriptNativeProcessor {
return result;
}
- private Variable unwrapObjectArray(CallLocation location, Variable var, int degree, ValueType itemType,
- ValueType expectedType) {
- String methodName = "unwrapArray";
- if (degree > 1) {
- methodName += degree;
- }
- ValueType resultType = ValueType.parse(JSObject.class);
- for (int i = 0; i < degree; ++i) {
- resultType = ValueType.arrayOf(resultType);
- }
-
- Variable classVar = program.createVariable();
- ClassConstantInstruction classInsn = new ClassConstantInstruction();
- classInsn.setConstant(itemType);
- classInsn.setReceiver(classVar);
- classInsn.setLocation(location.getSourceLocation());
- replacement.add(classInsn);
-
- Variable castValue = program.createVariable();
- CastInstruction castInsn = new CastInstruction();
- castInsn.setValue(var);
- castInsn.setReceiver(castValue);
- castInsn.setLocation(location.getSourceLocation());
- castInsn.setTargetType(ValueType.parse(JSArray.class));
- replacement.add(castInsn);
- var = castValue;
-
- Variable result = program.createVariable();
- InvokeInstruction insn = new InvokeInstruction();
- insn.setMethod(new MethodReference(JS.class.getName(), methodName, ValueType.parse(Class.class),
- ValueType.parse(JSArray.class), resultType));
- insn.getArguments().add(classVar);
- insn.getArguments().add(var);
- insn.setReceiver(result);
- insn.setType(InvocationType.SPECIAL);
- insn.setLocation(location.getSourceLocation());
- replacement.add(insn);
- var = result;
-
- Variable castResult = program.createVariable();
- castInsn = new CastInstruction();
- castInsn.setValue(var);
- castInsn.setReceiver(castResult);
- castInsn.setLocation(location.getSourceLocation());
- castInsn.setTargetType(expectedType);
- replacement.add(castInsn);
- var = castResult;
-
- return var;
- }
-
private Variable wrapArgument(CallLocation location, Variable var, ValueType type) {
if (type instanceof ValueType.Object) {
String className = ((ValueType.Object) type).getClassName();
@@ -807,22 +866,89 @@ class JavascriptNativeProcessor {
}
}
Variable result = program.createVariable();
- InvokeInstruction insn = new InvokeInstruction();
- insn.setMethod(new MethodReference(JS.class.getName(), "wrap", getWrappedType(type), getWrapperType(type)));
- insn.getArguments().add(var);
- insn.setReceiver(result);
- insn.setType(InvocationType.SPECIAL);
- insn.setLocation(location);
- replacement.add(insn);
+
+ ValueType itemType = type;
+ int degree = 0;
+ while (itemType instanceof ValueType.Array) {
+ itemType = ((ValueType.Array) itemType).getItemType();
+ ++degree;
+ }
+
+ if (degree <= 1) {
+ InvokeInstruction insn = new InvokeInstruction();
+ insn.setMethod(new MethodReference(JS.class.getName(), "wrap", getWrappedType(type),
+ getWrapperType(type)));
+ insn.getArguments().add(var);
+ insn.setReceiver(result);
+ insn.setType(InvocationType.SPECIAL);
+ insn.setLocation(location);
+ replacement.add(insn);
+ } else {
+ Variable function = program.createVariable();
+
+ InvokeInstruction insn = new InvokeInstruction();
+ insn.setMethod(getWrapperFunction(itemType));
+ insn.setReceiver(function);
+ insn.setType(InvocationType.SPECIAL);
+ insn.setLocation(location);
+ replacement.add(insn);
+
+ while (--degree > 1) {
+ insn = new InvokeInstruction();
+ insn.setMethod(new MethodReference(JS.class, "arrayMapper", Function.class, Function.class));
+ insn.getArguments().add(function);
+ function = program.createVariable();
+ insn.setReceiver(function);
+ insn.setType(InvocationType.SPECIAL);
+ insn.setLocation(location);
+ replacement.add(insn);
+ }
+
+ insn = new InvokeInstruction();
+ insn.setMethod(new MethodReference(JS.class.getName(), "map", getWrappedType(type),
+ ValueType.parse(Function.class), getWrapperType(type)));
+ insn.getArguments().add(var);
+ insn.getArguments().add(function);
+ insn.setReceiver(result);
+ insn.setType(InvocationType.SPECIAL);
+ insn.setLocation(location);
+ replacement.add(insn);
+ }
return result;
}
+ private MethodReference getWrapperFunction(ValueType type) {
+ if (type instanceof ValueType.Primitive) {
+ switch (((ValueType.Primitive) type).getKind()) {
+ case BOOLEAN:
+ return new MethodReference(JS.class, "booleanArrayWrapper", Function.class);
+ case BYTE:
+ return new MethodReference(JS.class, "byteArrayWrapper", Function.class);
+ case SHORT:
+ return new MethodReference(JS.class, "shortArrayWrapper", Function.class);
+ case CHARACTER:
+ return new MethodReference(JS.class, "charArrayWrapper", Function.class);
+ case INTEGER:
+ return new MethodReference(JS.class, "intArrayWrapper", Function.class);
+ case FLOAT:
+ return new MethodReference(JS.class, "floatArrayWrapper", Function.class);
+ case DOUBLE:
+ return new MethodReference(JS.class, "doubleArrayWrapper", Function.class);
+ default:
+ break;
+ }
+ } else if (type.isObject(String.class)) {
+ return new MethodReference(JS.class, "stringArrayWrapper", Function.class);
+ }
+ return new MethodReference(JS.class, "arrayWrapper", Function.class);
+ }
+
private ValueType getWrappedType(ValueType type) {
if (type instanceof ValueType.Array) {
ValueType itemType = ((ValueType.Array) type).getItemType();
return ValueType.arrayOf(getWrappedType(itemType));
} else if (type instanceof ValueType.Object) {
- if (type.isObject("java.lang.String")) {
+ if (type.isObject(String.class)) {
return type;
} else {
return ValueType.parse(JSObject.class);
@@ -834,28 +960,7 @@ class JavascriptNativeProcessor {
private ValueType getWrapperType(ValueType type) {
if (type instanceof ValueType.Array) {
- ValueType itemType = ((ValueType.Array) type).getItemType();
- if (itemType instanceof ValueType.Primitive) {
- switch (((ValueType.Primitive) itemType).getKind()) {
- case BOOLEAN:
- return ValueType.parse(JSBooleanArray.class);
- case BYTE:
- case SHORT:
- case INTEGER:
- case CHARACTER:
- return ValueType.parse(JSIntArray.class);
- case FLOAT:
- case DOUBLE:
- return ValueType.parse(JSDoubleArray.class);
- case LONG:
- default:
- return ValueType.parse(JSArray.class);
- }
- } else if (itemType.isObject("java.lang.String")) {
- return ValueType.parse(JSStringArray.class);
- } else {
- return ValueType.parse(JSArray.class);
- }
+ return ValueType.parse(JSArray.class);
} else {
return ValueType.parse(JSObject.class);
}
diff --git a/teavm-jso/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin b/teavm-jso-impl/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin
similarity index 100%
rename from teavm-jso/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin
rename to teavm-jso-impl/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin
diff --git a/teavm-jso/src/main/java/org/teavm/jso/core/JSSortFunction.java b/teavm-jso/src/main/java/org/teavm/jso/core/JSSortFunction.java
index 816d3fd55..09cefca0f 100644
--- a/teavm-jso/src/main/java/org/teavm/jso/core/JSSortFunction.java
+++ b/teavm-jso/src/main/java/org/teavm/jso/core/JSSortFunction.java
@@ -24,6 +24,7 @@ import org.teavm.jso.JSObject;
* @param
*/
@JSFunctor
+@FunctionalInterface
public interface JSSortFunction {
int compare(T a, T b);
}