diff --git a/transpiler/java/com/google/j2cl/transpiler/ast/ArrayTypeDescriptor.java b/transpiler/java/com/google/j2cl/transpiler/ast/ArrayTypeDescriptor.java index 73b42487de..1952cece1f 100644 --- a/transpiler/java/com/google/j2cl/transpiler/ast/ArrayTypeDescriptor.java +++ b/transpiler/java/com/google/j2cl/transpiler/ast/ArrayTypeDescriptor.java @@ -75,7 +75,22 @@ public boolean isUntypedArray() { * Returns true for arrays where raw wasm array representation is enough. These arrays are located * in {@see javaemul.internal.WasmArrays}. */ - public abstract boolean isNativeWasmArray(); + public abstract boolean isMarkedAsNativeWasmArray(); + + @Override + public boolean isNativeWasmArray() { + if (isMarkedAsNativeWasmArray()) { + return true; + } + + if (getComponentTypeDescriptor().toRawTypeDescriptor() instanceof DeclaredTypeDescriptor) { + DeclaredTypeDescriptor componentTypeDescriptor = + (DeclaredTypeDescriptor) getComponentTypeDescriptor().toRawTypeDescriptor(); + return componentTypeDescriptor.getTypeDeclaration().getWasmInfo() != null; + } + + return false; + } @Override public abstract boolean isNullable(); @@ -228,7 +243,7 @@ public static Builder newBuilder() { return new AutoValue_ArrayTypeDescriptor.Builder() // Default values. .setNullable(true) - .setNativeWasmArray(false); + .setMarkedAsNativeWasmArray(false); } /** Builder for an ArrayTypeDescriptor. */ @@ -242,7 +257,7 @@ public static Builder from(ArrayTypeDescriptor arrayTypeDescriptor) { public abstract Builder setNullable(boolean isNullable); - public abstract Builder setNativeWasmArray(boolean wasmNative); + public abstract Builder setMarkedAsNativeWasmArray(boolean wasmNative); abstract ArrayTypeDescriptor autoBuild(); diff --git a/transpiler/java/com/google/j2cl/transpiler/ast/TypeDescriptor.java b/transpiler/java/com/google/j2cl/transpiler/ast/TypeDescriptor.java index 8819ff38db..7b71bd1ff7 100644 --- a/transpiler/java/com/google/j2cl/transpiler/ast/TypeDescriptor.java +++ b/transpiler/java/com/google/j2cl/transpiler/ast/TypeDescriptor.java @@ -114,6 +114,11 @@ public boolean isAnnotatedWithFunctionalInterface() { return false; } + /** Returns whether the described type is a wasm native array. */ + public boolean isNativeWasmArray() { + return false; + } + /** * Returns the mangled name of a type. * diff --git a/transpiler/java/com/google/j2cl/transpiler/backend/wasm/WasmGenerationEnvironment.java b/transpiler/java/com/google/j2cl/transpiler/backend/wasm/WasmGenerationEnvironment.java index 3a8342f716..9fcb05a7d5 100644 --- a/transpiler/java/com/google/j2cl/transpiler/backend/wasm/WasmGenerationEnvironment.java +++ b/transpiler/java/com/google/j2cl/transpiler/backend/wasm/WasmGenerationEnvironment.java @@ -146,7 +146,10 @@ String getWasmTypeName(TypeDescriptor typeDescriptor) { if (typeDescriptor.isArray()) { ArrayTypeDescriptor arrayTypeDescriptor = (ArrayTypeDescriptor) typeDescriptor; if (arrayTypeDescriptor.isNativeWasmArray()) { - return getWasmTypeName(arrayTypeDescriptor.getComponentTypeDescriptor()) + ".array"; + String wasmTypeName = getWasmTypeName(arrayTypeDescriptor.getComponentTypeDescriptor()); + // Make sure the resulting type name always has $ prefix. + String prefix = wasmTypeName.startsWith("$") ? "" : "$"; + return format("%s%s.array", prefix, wasmTypeName); } return getWasmTypeName(TypeDescriptors.getWasmArrayType(arrayTypeDescriptor)); } @@ -172,9 +175,6 @@ private static String getTypeSignature(TypeDescriptor typeDescriptor) { } public String getWasmEmptyArrayGlobalName(ArrayTypeDescriptor arrayTypeDescriptor) { - checkArgument( - arrayTypeDescriptor.isPrimitiveArray() - || TypeDescriptors.isJavaLangObject(arrayTypeDescriptor.getComponentTypeDescriptor())); return "$__emptyArray_" + getWasmTypeName(arrayTypeDescriptor); } /** Returns the name of the global that stores the itable for a Java type. */ diff --git a/transpiler/java/com/google/j2cl/transpiler/backend/wasm/WasmOutputsGenerator.java b/transpiler/java/com/google/j2cl/transpiler/backend/wasm/WasmOutputsGenerator.java index 4eba3257d3..cdac907a68 100644 --- a/transpiler/java/com/google/j2cl/transpiler/backend/wasm/WasmOutputsGenerator.java +++ b/transpiler/java/com/google/j2cl/transpiler/backend/wasm/WasmOutputsGenerator.java @@ -824,11 +824,23 @@ private void emitWasmStruct( private List collectUsedNativeArrayTypes(Library library) { Set usedArrayTypes = new LinkedHashSet<>(); + // Collect native arrays from fields and variables; this covers all scenarios. library.accept( + // TODO(b/303659726): Generalize a type visitor that could be used here and other places + // like in ImportGatherer. Or consider emitting the one dimensional array type for all + // native types. new AbstractVisitor() { @Override public void exitField(Field field) { - TypeDescriptor typeDescriptor = field.getDescriptor().getTypeDescriptor(); + collectIfArrayType(field.getDescriptor().getTypeDescriptor()); + } + + @Override + public void exitVariable(Variable variable) { + collectIfArrayType(variable.getTypeDescriptor()); + } + + private void collectIfArrayType(TypeDescriptor typeDescriptor) { if (!typeDescriptor.isArray()) { return; } diff --git a/transpiler/java/com/google/j2cl/transpiler/passes/ImplementArraysAsClasses.java b/transpiler/java/com/google/j2cl/transpiler/passes/ImplementArraysAsClasses.java index cf2d64ee18..34eebe6624 100644 --- a/transpiler/java/com/google/j2cl/transpiler/passes/ImplementArraysAsClasses.java +++ b/transpiler/java/com/google/j2cl/transpiler/passes/ImplementArraysAsClasses.java @@ -302,7 +302,7 @@ private static Variable markVariableTypeDescriptorAsNative(Variable original) { } private static ArrayTypeDescriptor markArrayTypeDescriptorAsNative(ArrayTypeDescriptor original) { - return ArrayTypeDescriptor.Builder.from(original).setNativeWasmArray(true).build(); + return ArrayTypeDescriptor.Builder.from(original).setMarkedAsNativeWasmArray(true).build(); } private static TypeDescriptor maybeMarkTypeDescriptorAsNative(TypeDescriptor original) { diff --git a/transpiler/javatests/com/google/j2cl/integration/java/wasm/super-wasm/Main.java b/transpiler/javatests/com/google/j2cl/integration/java/wasm/super-wasm/Main.java index 61c4151c2e..056fe6bcbc 100644 --- a/transpiler/javatests/com/google/j2cl/integration/java/wasm/super-wasm/Main.java +++ b/transpiler/javatests/com/google/j2cl/integration/java/wasm/super-wasm/Main.java @@ -27,6 +27,7 @@ *

This test will be removed when all Wasm features are implemented and all integration tests are * enabled for Wasm. */ +@SuppressWarnings("unusable-by-js") public class Main { public static void main(String... args) throws Exception { @@ -34,6 +35,7 @@ public static void main(String... args) throws Exception { testClassLiterals(); testArrayInstanceOf(); testArrayGetClass(); + testNativeArrays(); } private static void testWasmAnnotation() { @@ -139,4 +141,27 @@ private static void testArrayGetClass() { assertEquals(Object[].class, objectArray.getClass()); assertEquals(Object.class, objectArray.getClass().getComponentType()); } + + @Wasm("i31") + interface I31Ref {} + + @Wasm("ref.i31") + private static native I31Ref toI31Ref(int value); + + @Wasm("i31.get_s") + private static native int i31GetS(I31Ref value); + + private static void testNativeArrays() { + I31Ref[] i31Refs = new I31Ref[10]; + + I31Ref two = toI31Ref(2); + i31Refs[1] = two; + assertTrue(i31GetS(i31Refs[1]) == 2); + for (int i = 0; i < i31Refs.length; i++) { + i31Refs[i] = toI31Ref(i); + } + for (int i = 0; i < i31Refs.length; i++) { + assertTrue(i31GetS(i31Refs[i]) == i); + } + } }