From 14a4a99fa5043c16300ed9c663dd5a94f62ec338 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 10 Oct 2024 14:18:32 +0200 Subject: [PATCH] wasm gc: fix exporting classes to JS --- .../org/teavm/backend/wasm/wasm-gc-runtime.js | 182 ++++++++---------- .../jso/impl/JSObjectClassTransformer.java | 5 +- .../jso/impl/wasmgc/WasmGCJSRuntime.java | 2 + .../impl/wasmgc/WasmGCJSRuntimeIntrinsic.java | 40 ++++ .../impl/wasmgc/WasmGCJSWrapperIntrinsic.java | 12 -- .../wasmgc/WasmGCJSWrapperTransformer.java | 24 +++ .../org/teavm/jso/impl/wasmgc/WasmGCJso.java | 11 +- .../impl/wasmgc/WasmGCJsoCommonGenerator.java | 44 ++++- .../wasmgc/WasmGCMarshallMethodGenerator.java | 17 +- .../java/org/teavm/jso/export/ExportTest.java | 8 +- 10 files changed, 201 insertions(+), 144 deletions(-) create mode 100644 jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSRuntimeIntrinsic.java diff --git a/core/src/main/resources/org/teavm/backend/wasm/wasm-gc-runtime.js b/core/src/main/resources/org/teavm/backend/wasm/wasm-gc-runtime.js index 8dcdfc7a4..e6c478c4e 100644 --- a/core/src/main/resources/org/teavm/backend/wasm/wasm-gc-runtime.js +++ b/core/src/main/resources/org/teavm/backend/wasm/wasm-gc-runtime.js @@ -263,15 +263,23 @@ TeaVM.wasmGC = TeaVM.wasmGC || function() { params.push("p" + i); } let paramsAsString = params.length === 0 ? "" : params.join(", "); - return new Function("rethrowJavaAsJs", "fn", ` - return function(${paramsAsString}) { - try { - return fn(${paramsAsString}); - } catch (e) { - rethrowJavaAsJs(e); - } - }; - `)(rethrowJavaAsJs, fn); + return new Function("rethrowJavaAsJs", "fn", + `return function(${paramsAsString}) {\n` + + ` try {\n` + + ` return fn(${paramsAsString});\n` + + ` } catch (e) {\n` + + ` rethrowJavaAsJs(e);\n` + + ` }\n` + + `};` + )(rethrowJavaAsJs, fn); + } + function renameConstructor(name, c) { + return new Function( + "constructor", + `return function ${name}(marker, javaObject) {\n` + + ` return constructor.call(this, marker, javaObject);\n` + + `}\n` + )(c); } imports.teavmJso = { emptyString: () => "", @@ -295,64 +303,41 @@ TeaVM.wasmGC = TeaVM.wasmGC || function() { } }, createClass(name, parent, constructor) { - name = sanitizeName(name); + name = sanitizeName(name || "JavaObject"); + let action; if (parent === null) { - let fn = new Function( - "javaObjectSymbol", - "functionsSymbol", - "wrapperCallMarker", - "constructor", - "rethrowJavaAsJs", - `let fn; - fn = function ${name}(marker, javaObject) { - if (marker === wrapperCallMarker) { - this[javaObjectSymbol] = javaObject; - this[functionsSymbol] = null; - } else if (constructor === null) { - throw new Error("This class can't be instantiated directly"); - } else { - try { - return fn(wrapperCallMarker, constructor(arguments)); - } catch (e) { - rethrowJavaAsJs(e); - } - } - }; - let boundFn = function(javaObject) { return fn.call(this, wrapperCallMarker, javaObject); }; - boundFn[wrapperCallMarker] = fn; - boundFn.prototype = fn.prototype; - return boundFn;` - ); - return fn(javaObjectSymbol, functionsSymbol, wrapperCallMarkerSymbol, constructor, rethrowJavaAsJs); + action = function (javaObject) { + this[javaObjectSymbol] = javaObject; + this[functionsSymbol] = null; + }; } else { - let fn = new Function( - "parent", - "wrapperCallMarker", - "constructor", - "rethrowJavaAsJs", - `let fn - fn = function ${name}(marker, javaObject) { - if (marker === wrapperCallMarker) { - parent.call(this, javaObject); - } else if (constructor === null) { - throw new Error("This class can't be instantiated directly"); - } else { - try { - return fn(wrapperCallMarker, constructor(arguments)); - } catch (e) { - rethrowJavaAsJs(e); - } - } - }; - fn.prototype = Object.create(parent); - fn.prototype.constructor = parent; - let boundFn = function(javaObject) { return fn.call(this, wrapperCallMarker, javaObject); }; - boundFn[wrapperCallMarker] = fn; - boundFn.prototype = fn.prototype; - return fn;` - ); - return fn(parent, wrapperCallMarkerSymbol, constructor, rethrowJavaAsJs); + action = function (javaObject) { + parent.call(this, javaObject); + }; + fn.prototype = Object.create(parent); + fn.prototype.constructor = parent; } + let fn = renameConstructor(name, function (marker, javaObject) { + if (marker === wrapperCallMarkerSymbol) { + action.call(this, javaObject); + } else if (constructor === null) { + throw new Error("This class can't be instantiated directly"); + } else { + try { + return constructor.apply(null, arguments); + } catch (e) { + rethrowJavaAsJs(e); + } + } + }); + fn.prototype = Object.create(parent || Object.prototype); + fn.prototype.constructor = fn; + let boundFn = renameConstructor(name, function(javaObject) { + return fn.call(this, wrapperCallMarkerSymbol, javaObject); + }); + boundFn[wrapperCallMarkerSymbol] = fn; + boundFn.prototype = fn.prototype; + return boundFn; }, exportClass(cls) { return cls[wrapperCallMarkerSymbol]; @@ -363,15 +348,15 @@ TeaVM.wasmGC = TeaVM.wasmGC || function() { params.push("p" + i); } let paramsAsString = params.length === 0 ? "" : params.join(", "); - cls.prototype[name] = new Function("rethrowJavaAsJs", "fn", ` - return function(${paramsAsString}) { - try { - return fn(${['this', params].join(", ")}); - } catch (e) { - rethrowJavaAsJs(e); - } - }; - `)(rethrowJavaAsJs, fn); + cls.prototype[name] = new Function("rethrowJavaAsJs", "fn", + `return function(${paramsAsString}) {\n` + + ` try {\n` + + ` return fn(${['this', params].join(", ")});\n` + + ` } catch (e) {\n` + + ` rethrowJavaAsJs(e);\n` + + ` }\n` + + `};` + )(rethrowJavaAsJs, fn); }, defineStaticMethod(cls, name, fn) { cls[name] = defineFunction(fn); @@ -554,32 +539,33 @@ TeaVM.wasmGC = TeaVM.wasmGC || function() { for (let i = 0; i < 32; ++i) { let args = argumentList.length === 0 ? "" : argumentList.join(", "); let argsAndBody = [...argumentList, "body"].join(", "); - imports.teavmJso["createFunction" + i] = new Function("wrapCallFromJavaToJs", ...argumentList, "body", ` - return new Function('wrapCallFromJavaToJs', ${argsAndBody}).bind(this, wrapCallFromJavaToJs); - `).bind(null, wrapCallFromJavaToJs); - imports.teavmJso["callFunction" + i] = new Function("rethrowJsAsJava", "fn", ...argumentList, ` - try { - return fn(${args}); - } catch (e) { - rethrowJsAsJava(e); - } - `).bind(null, rethrowJsAsJava); + imports.teavmJso["createFunction" + i] = new Function("wrapCallFromJavaToJs", ...argumentList, "body", + `return new Function('wrapCallFromJavaToJs', ${argsAndBody}).bind(this, wrapCallFromJavaToJs);` + ).bind(null, wrapCallFromJavaToJs); + imports.teavmJso["callFunction" + i] = new Function("rethrowJsAsJava", "fn", ...argumentList, + `try {\n` + + ` return fn(${args});\n` + + `} catch (e) {\n` + + ` rethrowJsAsJava(e);\n` + + `}` + ).bind(null, rethrowJsAsJava); imports.teavmJso["callMethod" + i] = new Function("rethrowJsAsJava", "getGlobalName", "instance", - "method", ...argumentList, ` - try { - return instance !== null - ? instance[method](${args}) - : getGlobalName(method)(${args}); - } catch (e) { - rethrowJsAsJava(e); - }`).bind(null, rethrowJsAsJava, getGlobalName); - imports.teavmJso["construct" + i] = new Function("rethrowJsAsJava", "constructor", ...argumentList, ` - try { - return new constructor(${args}); - } catch (e) { - rethrowJsAsJava(e); - } - `).bind(null, rethrowJsAsJava); + "method", ...argumentList, + `try {\n`+ + ` return instance !== null\n` + + ` ? instance[method](${args})\n` + + ` : getGlobalName(method)(${args});\n` + + `} catch (e) {\n` + + ` rethrowJsAsJava(e);\n` + + `}` + ).bind(null, rethrowJsAsJava, getGlobalName); + imports.teavmJso["construct" + i] = new Function("rethrowJsAsJava", "constructor", ...argumentList, + `try {\n` + + ` return new constructor(${args});\n` + + `} catch (e) {\n` + + ` rethrowJsAsJava(e);\n` + + `}` + ).bind(null, rethrowJsAsJava); imports.teavmJso["arrayOf" + i] = new Function(...argumentList, "return [" + args + "]"); let param = "p" + (i + 1); diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSObjectClassTransformer.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSObjectClassTransformer.java index c1812b000..d1c5fa02a 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSObjectClassTransformer.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSObjectClassTransformer.java @@ -139,10 +139,7 @@ class JSObjectClassTransformer implements ClassHolderTransformer { createWrapperMethod.setLevel(AccessLevel.PUBLIC); createWrapperMethod.getModifiers().add(ElementModifier.NATIVE); cls.addMethod(createWrapperMethod); - - if (!isJavaScriptClass(cls)) { - cls.getInterfaces().add(JSMethods.JS_MARSHALLABLE); - } + cls.getInterfaces().add(JSMethods.JS_MARSHALLABLE); } } diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSRuntime.java b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSRuntime.java index ff206a548..24da0bce7 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSRuntime.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSRuntime.java @@ -66,6 +66,8 @@ final class WasmGCJSRuntime { @Import(name = "charAt", module = "teavmJso") static native char charAt(JSObject str, int index); + static native JSObject wrapObject(Object obj); + static Throwable wrapException(JSObject obj) { return new WasmGCExceptionWrapper(obj); } diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSRuntimeIntrinsic.java b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSRuntimeIntrinsic.java new file mode 100644 index 000000000..830c6cf97 --- /dev/null +++ b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSRuntimeIntrinsic.java @@ -0,0 +1,40 @@ +/* + * Copyright 2024 konsoletyper. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.jso.impl.wasmgc; + +import org.teavm.ast.InvocationExpr; +import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic; +import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext; +import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmExpression; +import org.teavm.backend.wasm.model.expression.WasmGetGlobal; + +class WasmGCJSRuntimeIntrinsic implements WasmGCIntrinsic { + private WasmGCJsoCommonGenerator commonGen; + + WasmGCJSRuntimeIntrinsic(WasmGCJsoCommonGenerator commonGen) { + this.commonGen = commonGen; + } + + @Override + public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) { + var jsoContext = WasmGCJsoContext.wrap(context); + var wrapperClass = commonGen.getDefaultWrapperClass(jsoContext); + var wrapperFunction = commonGen.javaObjectToJSFunction(jsoContext); + return new WasmCall(wrapperFunction, context.generate(invocation.getArguments().get(0)), + new WasmGetGlobal(wrapperClass)); + } +} diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSWrapperIntrinsic.java b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSWrapperIntrinsic.java index 1c2a5086d..38f8a602f 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSWrapperIntrinsic.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSWrapperIntrinsic.java @@ -21,7 +21,6 @@ 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.WasmCast; import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExternConversion; import org.teavm.backend.wasm.model.expression.WasmExternConversionType; @@ -41,17 +40,6 @@ class WasmGCJSWrapperIntrinsic implements WasmGCIntrinsic { var function = getWrapFunction(context); return new WasmCall(function, context.generate(invocation.getArguments().get(0))); } - case "dependencyJavaToJs": - case "directJavaToJs": - return new WasmExternConversion(WasmExternConversionType.ANY_TO_EXTERN, - context.generate(invocation.getArguments().get(0))); - case "dependencyJsToJava": - case "directJsToJava": { - var any = new WasmExternConversion(WasmExternConversionType.EXTERN_TO_ANY, - context.generate(invocation.getArguments().get(0))); - var objectType = context.typeMapper().mapType(ValueType.parse(Object.class)); - return new WasmCast(any, (WasmType.Reference) objectType); - } case "isJava": { var convert = new WasmExternConversion(WasmExternConversionType.EXTERN_TO_ANY, context.generate(invocation.getArguments().get(0))); diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSWrapperTransformer.java b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSWrapperTransformer.java index 1d46e3ab5..c217a2ccc 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSWrapperTransformer.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJSWrapperTransformer.java @@ -25,6 +25,7 @@ import org.teavm.model.ClassHolderTransformerContext; import org.teavm.model.ElementModifier; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodHolder; +import org.teavm.model.ValueType; import org.teavm.model.emit.ProgramEmitter; class WasmGCJSWrapperTransformer implements ClassHolderTransformer { @@ -33,6 +34,12 @@ class WasmGCJSWrapperTransformer implements ClassHolderTransformer { if (cls.getName().equals(JSWrapper.class.getName())) { transformMarshallMethod(cls.getMethod(new MethodDescriptor("marshallJavaToJs", Object.class, JSObject.class)), context); + transformDirectJavaToJs(cls.getMethod(new MethodDescriptor("directJavaToJs", Object.class, + JSObject.class)), context); + transformDirectJavaToJs(cls.getMethod(new MethodDescriptor("dependencyJavaToJs", Object.class, + JSObject.class)), context); + transformDirectJsToJava(cls.getMethod(new MethodDescriptor("dependencyJsToJava", JSObject.class, + Object.class)), context); transformWrapMethod(cls.getMethod(new MethodDescriptor("wrap", JSObject.class, Object.class))); transformIsJava(cls.getMethod(new MethodDescriptor("isJava", Object.class, boolean.class)), context); addCreateWrapperMethod(cls, context); @@ -43,9 +50,26 @@ class WasmGCJSWrapperTransformer implements ClassHolderTransformer { method.getModifiers().remove(ElementModifier.NATIVE); var pe = ProgramEmitter.create(method, context.getHierarchy()); var obj = pe.var(1, Object.class); + pe.when(obj.instanceOf(ValueType.parse(JSMarshallable.class)).isFalse()).thenDo(() -> { + pe.invoke(WasmGCJSRuntime.class, "wrapObject", JSObject.class, obj).returnValue(); + }); obj.cast(JSMarshallable.class).invokeVirtual("marshallToJs", JSObject.class).returnValue(); } + private void transformDirectJavaToJs(MethodHolder method, ClassHolderTransformerContext context) { + method.getModifiers().remove(ElementModifier.NATIVE); + var pe = ProgramEmitter.create(method, context.getHierarchy()); + var obj = pe.var(1, Object.class); + pe.invoke(JSWrapper.class, "marshallJavaToJs", JSObject.class, obj).returnValue(); + } + + private void transformDirectJsToJava(MethodHolder method, ClassHolderTransformerContext context) { + method.getModifiers().remove(ElementModifier.NATIVE); + var pe = ProgramEmitter.create(method, context.getHierarchy()); + var obj = pe.var(1, JSObject.class); + pe.invoke(JSWrapper.class, "unmarshallJavaFromJs", Object.class, obj).returnValue(); + } + private void transformWrapMethod(MethodHolder method) { method.getModifiers().add(ElementModifier.NATIVE); method.setProgram(null); diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJso.java b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJso.java index 797f33c58..60ee3b709 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJso.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJso.java @@ -57,15 +57,10 @@ public final class WasmGCJso { var wrapperIntrinsic = new WasmGCJSWrapperIntrinsic(); wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "wrap", JSObject.class, Object.class), wrapperIntrinsic); - wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "dependencyJavaToJs", Object.class, - JSObject.class), wrapperIntrinsic); - wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "directJavaToJs", Object.class, JSObject.class), - wrapperIntrinsic); - wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "dependencyJsToJava", JSObject.class, - Object.class), wrapperIntrinsic); - wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "directJsToJava", JSObject.class, Object.class), - wrapperIntrinsic); wasmGCHost.addIntrinsic(new MethodReference(JSWrapper.class, "isJava", JSObject.class, boolean.class), wrapperIntrinsic); + + wasmGCHost.addIntrinsic(new MethodReference(WasmGCJSRuntime.class, "wrapObject", Object.class, + JSObject.class), new WasmGCJSRuntimeIntrinsic(commonGen)); } } diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJsoCommonGenerator.java b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJsoCommonGenerator.java index 122858d3a..5460c6bb5 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJsoCommonGenerator.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCJsoCommonGenerator.java @@ -63,6 +63,8 @@ class WasmGCJsoCommonGenerator { private WasmFunction definePropertyFunction; private WasmFunction defineStaticPropertyFunction; private WasmFunction exportClassFunction; + private WasmFunction javaObjectToJSFunction; + private WasmGlobal defaultWrapperClass; private Map definedClasses = new HashMap<>(); WasmGCJsoCommonGenerator(WasmGCJSFunctions jsFunctions) { @@ -198,6 +200,23 @@ class WasmGCJsoCommonGenerator { return new WasmGetGlobal(global); } + WasmGlobal getDefaultWrapperClass(WasmGCJsoContext context) { + if (defaultWrapperClass == null) { + var name = context.names().topLevel("teavm.js@defaultWrapperClass"); + defaultWrapperClass = new WasmGlobal(name, WasmType.Reference.EXTERN, + new WasmNullConstant(WasmType.Reference.EXTERN)); + context.module().globals.add(defaultWrapperClass); + addInitializerPart(context, initializer -> { + var createClass = new WasmCall(createClassFunction(context), + new WasmNullConstant(WasmType.Reference.EXTERN), + new WasmNullConstant(WasmType.Reference.EXTERN), + new WasmNullConstant(WasmType.Reference.FUNC)); + initializer.getBody().add(new WasmSetGlobal(defaultWrapperClass, createClass)); + }); + } + return defaultWrapperClass; + } + WasmGlobal getDefinedClass(WasmGCJsoContext context, String className) { return definedClasses.computeIfAbsent(className, n -> defineClass(context, n)); } @@ -216,8 +235,6 @@ class WasmGCJsoCommonGenerator { defineProperties(context, members, cls, global, expressions); var staticMembers = AliasCollector.collectMembers(cls, AliasCollector::isStaticMember); - defineStaticMethods(context, staticMembers, cls, global, expressions, isModule); - defineStaticProperties(context, staticMembers, cls, global, expressions); var simpleName = className.substring(className.lastIndexOf('.') + 1); var javaClassName = context.strings().getStringConstant(simpleName); @@ -233,6 +250,7 @@ class WasmGCJsoCommonGenerator { WasmExpression constructor; if (members.constructor != null) { var function = context.functions().forStaticMethod(members.constructor); + function.setReferenced(true); constructor = new WasmFunctionReference(function); needsExport = true; } else { @@ -240,10 +258,14 @@ class WasmGCJsoCommonGenerator { } var createClass = new WasmCall(createClassFunction(context), jsClassName, jsExportedParent, constructor); expressions.add(0, new WasmSetGlobal(global, createClass)); + var globalForStatic = global; if (needsExport) { - exportClass(context, cls, global, expressions); + globalForStatic = exportClass(context, cls, global, expressions); } + defineStaticMethods(context, staticMembers, cls, globalForStatic, expressions, isModule); + defineStaticProperties(context, staticMembers, cls, globalForStatic, expressions); + context.addToInitializer(f -> f.getBody().addAll(expressions)); return global; } @@ -340,7 +362,7 @@ class WasmGCJsoCommonGenerator { } } - private void exportClass(WasmGCJsoContext context, ClassReader cls, WasmGlobal global, + private WasmGlobal exportClass(WasmGCJsoContext context, ClassReader cls, WasmGlobal global, List expressions) { var exportName = getClassAliasName(cls); var globalName = context.names().topLevel("teavm.js.export.class@" + exportName); @@ -351,6 +373,8 @@ class WasmGCJsoCommonGenerator { var exported = new WasmCall(exportClassFunction(context), new WasmGetGlobal(global)); expressions.add(new WasmSetGlobal(exportGlobal, exported)); + + return exportGlobal; } private String parentExportedClass(WasmGCJsoContext context, String className) { @@ -453,6 +477,18 @@ class WasmGCJsoCommonGenerator { return exportClassFunction; } + WasmFunction javaObjectToJSFunction(WasmGCJsoContext context) { + if (javaObjectToJSFunction == null) { + javaObjectToJSFunction = new WasmFunction(context.functionTypes().of(WasmType.Reference.EXTERN, + context.typeMapper().mapType(ValueType.parse(Object.class)), WasmType.Reference.EXTERN)); + javaObjectToJSFunction.setName(context.names().topLevel("teavm.jso@javaObjectToJS")); + javaObjectToJSFunction.setImportName("javaObjectToJS"); + javaObjectToJSFunction.setImportModule("teavmJso"); + context.module().functions.add(javaObjectToJSFunction); + } + return javaObjectToJSFunction; + } + private String getClassAliasName(ClassReader cls) { var name = cls.getSimpleName(); if (name == null) { diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCMarshallMethodGenerator.java b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCMarshallMethodGenerator.java index 9f475b63e..d6ac56441 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCMarshallMethodGenerator.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/wasmgc/WasmGCMarshallMethodGenerator.java @@ -19,7 +19,6 @@ import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator; import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorContext; import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmLocal; -import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.expression.WasmCall; import org.teavm.backend.wasm.model.expression.WasmGetGlobal; import org.teavm.backend.wasm.model.expression.WasmGetLocal; @@ -28,7 +27,6 @@ import org.teavm.model.ValueType; class WasmGCMarshallMethodGenerator implements WasmGCCustomGenerator { private WasmGCJsoCommonGenerator commonGen; - private WasmFunction javaObjectToJSFunction; WasmGCMarshallMethodGenerator(WasmGCJsoCommonGenerator commonGen) { this.commonGen = commonGen; @@ -42,21 +40,8 @@ class WasmGCMarshallMethodGenerator implements WasmGCCustomGenerator { function.add(thisLocal); var jsClassGlobal = commonGen.getDefinedClass(jsoContext, method.getClassName()); - var wrapperFunction = javaObjectToJSFunction(context); + var wrapperFunction = commonGen.javaObjectToJSFunction(jsoContext); function.getBody().add(new WasmCall(wrapperFunction, new WasmGetLocal(thisLocal), new WasmGetGlobal(jsClassGlobal))); } - - private WasmFunction javaObjectToJSFunction(WasmGCCustomGeneratorContext context) { - if (javaObjectToJSFunction == null) { - javaObjectToJSFunction = new WasmFunction(context.functionTypes().of(WasmType.Reference.EXTERN, - context.typeMapper().mapType(ValueType.parse(Object.class)), WasmType.Reference.EXTERN)); - javaObjectToJSFunction.setName(context.names().topLevel("teavm.jso@javaObjectToJS")); - javaObjectToJSFunction.setImportName("javaObjectToJS"); - javaObjectToJSFunction.setImportModule("teavmJso"); - context.module().functions.add(javaObjectToJSFunction); - } - return javaObjectToJSFunction; - } - } diff --git a/tests/src/test/java/org/teavm/jso/export/ExportTest.java b/tests/src/test/java/org/teavm/jso/export/ExportTest.java index b15a23b0b..6b0e654f8 100644 --- a/tests/src/test/java/org/teavm/jso/export/ExportTest.java +++ b/tests/src/test/java/org/teavm/jso/export/ExportTest.java @@ -112,14 +112,18 @@ public class ExportTest { @Test public void varargs() { - testExport("varargs", ModuleWithVararg.class); + testExport("varargs", ModuleWithVararg.class, true); } private void testExport(String name, Class moduleClass) { + testExport(name, moduleClass, false); + } + + private void testExport(String name, Class moduleClass, boolean skipWasmGC) { if (jsNeeded) { testExportJs(name, moduleClass); } - if (wasmGCNeeded) { + if (wasmGCNeeded && !skipWasmGC) { testExportWasmGC(name, moduleClass); } }