wasm gc: support primitive array conversion to JavaScript in JSO

This commit is contained in:
Alexey Andreev 2024-09-28 19:52:14 +02:00
parent bbf45760b8
commit 5ad4496c34
7 changed files with 34 additions and 13 deletions

View File

@ -18,7 +18,7 @@ var TeaVM = TeaVM || {};
TeaVM.wasm = function() { TeaVM.wasm = function() {
let exports; let exports;
let getGlobalName = function(name) { let getGlobalName = function(name) {
return eval("return " + {name}); return eval(name);
} }
function defaults(imports) { function defaults(imports) {
let stderr = ""; let stderr = "";

View File

@ -746,7 +746,6 @@ public final class JS {
@InjectedBy(JSNativeInjector.class) @InjectedBy(JSNativeInjector.class)
@NoSideEffects @NoSideEffects
@Import(name = "global", module = "teavmJso")
public static native JSObject global(String name); public static native JSObject global(String name);
@InjectedBy(JSNativeInjector.class) @InjectedBy(JSNativeInjector.class)

View File

@ -29,7 +29,7 @@ class WasmGCJSFunctions {
if (function == null) { if (function == null) {
var extern = WasmType.SpecialReferenceKind.EXTERN.asNonNullType(); var extern = WasmType.SpecialReferenceKind.EXTERN.asNonNullType();
var constructorParamTypes = new WasmType[index + 1]; var constructorParamTypes = new WasmType[index + 1];
Arrays.fill(constructorParamTypes, extern); Arrays.fill(constructorParamTypes, WasmType.Reference.EXTERN);
var functionType = context.functionTypes().of(extern, constructorParamTypes); var functionType = context.functionTypes().of(extern, constructorParamTypes);
function = new WasmFunction(functionType); function = new WasmFunction(functionType);
function.setName(context.names().topLevel("teavm.js:createFunction" + index)); function.setName(context.names().topLevel("teavm.js:createFunction" + index));
@ -44,11 +44,9 @@ class WasmGCJSFunctions {
WasmFunction getFunctionCaller(WasmGCIntrinsicContext context, int index) { WasmFunction getFunctionCaller(WasmGCIntrinsicContext context, int index) {
var function = callers[index]; var function = callers[index];
if (function == null) { if (function == null) {
var extern = WasmType.SpecialReferenceKind.EXTERN.asNonNullType();
var paramTypes = new WasmType[index + 1]; var paramTypes = new WasmType[index + 1];
Arrays.fill(paramTypes, extern); Arrays.fill(paramTypes, WasmType.Reference.EXTERN);
paramTypes[0] = WasmType.Reference.EXTERN; var functionType = context.functionTypes().of(WasmType.Reference.EXTERN, paramTypes);
var functionType = context.functionTypes().of(extern, paramTypes);
function = new WasmFunction(functionType); function = new WasmFunction(functionType);
function.setName(context.names().topLevel("teavm.js:callFunction" + index)); function.setName(context.names().topLevel("teavm.js:callFunction" + index));
function.setImportModule("teavmJso"); function.setImportModule("teavmJso");

View File

@ -20,10 +20,17 @@ import static org.teavm.jso.impl.wasmgc.WasmGCJSConstants.STRING_TO_JS;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic; import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext; import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmCall; import org.teavm.backend.wasm.model.expression.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.jso.JSObject;
import org.teavm.jso.impl.JS;
import org.teavm.model.MethodReference;
class WasmGCJSIntrinsic implements WasmGCIntrinsic { class WasmGCJSIntrinsic implements WasmGCIntrinsic {
private WasmFunction globalFunction;
@Override @Override
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) { public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
switch (invocation.getMethod().getName()) { switch (invocation.getMethod().getName()) {
@ -35,8 +42,26 @@ class WasmGCJSIntrinsic implements WasmGCIntrinsic {
var function = context.functions().forStaticMethod(JS_TO_STRING); var function = context.functions().forStaticMethod(JS_TO_STRING);
return new WasmCall(function, context.generate(invocation.getArguments().get(0))); return new WasmCall(function, context.generate(invocation.getArguments().get(0)));
} }
case "global": {
var stringToJs = context.functions().forStaticMethod(STRING_TO_JS);
var name = new WasmCall(stringToJs, context.generate(invocation.getArguments().get(0)));
return new WasmCall(getGlobalFunction(context), name);
}
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} }
private WasmFunction getGlobalFunction(WasmGCIntrinsicContext context) {
if (globalFunction == null) {
globalFunction = new WasmFunction(context.functionTypes().of(WasmType.Reference.EXTERN,
WasmType.Reference.EXTERN));
globalFunction.setName(context.names().suggestForMethod(new MethodReference(JS.class,
"global", String.class, JSObject.class)));
globalFunction.setImportName("global");
globalFunction.setImportModule("teavmJso");
context.module().functions.add(globalFunction);
}
return globalFunction;
}
} }

View File

@ -20,12 +20,14 @@ import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapperFactory;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapperFactoryContext; import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapperFactoryContext;
import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.WasmType;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.core.JSArray;
class WasmGCJSTypeMapper implements WasmGCCustomTypeMapper, WasmGCCustomTypeMapperFactory { class WasmGCJSTypeMapper implements WasmGCCustomTypeMapper, WasmGCCustomTypeMapperFactory {
@Override @Override
public WasmType map(String className) { public WasmType map(String className) {
if (className.equals(JSObject.class.getName())) { if (className.equals(JSObject.class.getName())
return WasmType.SpecialReferenceKind.EXTERN.asNonNullType(); || className.equals(JSArray.class.getName())) {
return WasmType.Reference.EXTERN;
} }
return null; return null;
} }

View File

@ -35,5 +35,6 @@ public final class WasmGCJso {
wasmGCHost.addIntrinsic(new MethodReference(JS.class, "wrap", String.class, JSObject.class), jsIntrinsic); wasmGCHost.addIntrinsic(new MethodReference(JS.class, "wrap", String.class, JSObject.class), jsIntrinsic);
wasmGCHost.addIntrinsic(new MethodReference(JS.class, "unwrapString", JSObject.class, String.class), wasmGCHost.addIntrinsic(new MethodReference(JS.class, "unwrapString", JSObject.class, String.class),
jsIntrinsic); jsIntrinsic);
wasmGCHost.addIntrinsic(new MethodReference(JS.class, "global", String.class, JSObject.class), jsIntrinsic);
} }
} }

View File

@ -58,7 +58,6 @@ public class ConversionTest {
} }
@Test @Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void convertsPrimitiveArraysToJavaScript() { public void convertsPrimitiveArraysToJavaScript() {
assertEquals("true:2:3:64:4:5.5:6.5:foo", combinePrimitiveArrays(new boolean[] { true }, new byte[] { 2 }, assertEquals("true:2:3:64:4:5.5:6.5:foo", combinePrimitiveArrays(new boolean[] { true }, new byte[] { 2 },
new short[] { 3 }, new char[] { '@' }, new int[] { 4 }, new float[] { 5.5F }, new double[] { 6.5 }, new short[] { 3 }, new char[] { '@' }, new int[] { 4 }, new float[] { 5.5F }, new double[] { 6.5 },
@ -84,7 +83,6 @@ public class ConversionTest {
} }
@Test @Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void convertsPrimitiveArrays2ToJavaScript() { public void convertsPrimitiveArrays2ToJavaScript() {
assertEquals("true:2:3:64:4:5.5:6.5:foo", combinePrimitiveArrays2(new boolean[][] {{ true }}, assertEquals("true:2:3:64:4:5.5:6.5:foo", combinePrimitiveArrays2(new boolean[][] {{ true }},
new byte[][] {{ 2 }}, new short[][] {{ 3 }}, new char[][] {{ '@' }}, new int[][] {{ 4 }}, new byte[][] {{ 2 }}, new short[][] {{ 3 }}, new char[][] {{ '@' }}, new int[][] {{ 4 }},
@ -111,7 +109,6 @@ public class ConversionTest {
} }
@Test @Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void convertsPrimitiveArrays4ToJavaScript() { public void convertsPrimitiveArrays4ToJavaScript() {
assertEquals("true:2:3:64:4:5.5:6.5:foo", combinePrimitiveArrays4(new boolean[][][][] {{{{ true }}}}, assertEquals("true:2:3:64:4:5.5:6.5:foo", combinePrimitiveArrays4(new boolean[][][][] {{{{ true }}}},
new byte[][][][] {{{{ 2 }}}}, new short[][][][] {{{{ 3 }}}}, new char[][][][] {{{{ '@' }}}}, new byte[][][][] {{{{ 2 }}}}, new short[][][][] {{{{ 3 }}}}, new char[][][][] {{{{ '@' }}}},
@ -153,7 +150,6 @@ public class ConversionTest {
} }
@Test @Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void copiesArray() { public void copiesArray() {
int[] array = { 23 }; int[] array = { 23 };
assertEquals(24, mutate(array)); assertEquals(24, mutate(array));