wasm gc: basic support for functors in JSO

This commit is contained in:
Alexey Andreev 2024-10-01 14:43:53 +02:00
parent 383fee67c5
commit 4b76396332
4 changed files with 37 additions and 6 deletions

View File

@ -22,6 +22,7 @@ TeaVM.wasm = function() {
}
let javaObjectSymbol = Symbol("javaObject");
let functionsSymbol = Symbol("functions");
let functionOriginSymbol = Symbol("functionOrigin");
let javaWrappers = new WeakMap();
function defaults(imports) {
let stderr = "";
@ -135,7 +136,7 @@ TeaVM.wasm = function() {
this[functionsSymbol] = null;
};`
);
return fn(javaObjectSymbol, functionsSymbol);
return fn(javaObjectSymbol, functionsSymbol, functionOriginSymbol);
},
defineMethod(cls, name, fn) {
cls.prototype[name] = function(...args) {
@ -181,9 +182,20 @@ TeaVM.wasm = function() {
result = function() {
return instance[propertyName].apply(instance, arguments);
}
result[functionOriginSymbol] = instance;
functions[propertyName] = result;
}
return result;
},
functionAsObject(fn, property) {
let origin = fn[functionOriginSymbol];
if (typeof origin !== 'undefined') {
let functions = origin[functionsSymbol];
if (functions !== void 0 && functions[property] === fn) {
return origin;
}
}
return { [property]: fn };
}
};
for (let name of ["wrapByte", "wrapShort", "wrapChar", "wrapInt", "wrapFloat", "wrapDouble", "unwrapByte",

View File

@ -743,6 +743,7 @@ public final class JS {
@GeneratedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeInjector.class)
@Import(name = "functionAsObject", module = "teavmJso")
public static native JSObject functionAsObject(JSObject instance, JSObject property);
@InjectedBy(JSNativeInjector.class)

View File

@ -87,7 +87,7 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
processor.setClassFilter(classFilter);
}
processor.processClass(cls);
if (typeHelper.isJavaScriptClass(cls.getName())) {
if (isJavaScriptClass(cls)) {
processor.processMemberMethods(cls);
}
@ -122,17 +122,17 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
exposeMethods(cls, exposedClass, context.getDiagnostics(), functorMethod);
exportStaticMethods(cls, context.getDiagnostics());
if (typeHelper.isJavaScriptImplementation(cls.getName()) || !exposedClass.methods.isEmpty()) {
if (isJavaScriptImplementation(cls) || !exposedClass.methods.isEmpty()) {
cls.getAnnotations().add(new AnnotationHolder(JSClassToExpose.class.getName()));
}
if (wasmGC && (!exposedClass.methods.isEmpty() || typeHelper.isJavaScriptClass(cls.getName()))) {
if (wasmGC && (!exposedClass.methods.isEmpty() || isJavaScriptClass(cls))) {
var createWrapperMethod = new MethodHolder(JSMethods.MARSHALL_TO_JS);
createWrapperMethod.setLevel(AccessLevel.PUBLIC);
createWrapperMethod.getModifiers().add(ElementModifier.NATIVE);
cls.addMethod(createWrapperMethod);
if (typeHelper.isJavaScriptImplementation(cls.getName())) {
if (isJavaScriptImplementation(cls)) {
cls.getInterfaces().add(JSMethods.JS_MARSHALLABLE);
}
}
@ -387,6 +387,21 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
return false;
}
private boolean isJavaScriptImplementation(ClassReader cls) {
if (typeHelper.isJavaScriptImplementation(cls.getName())) {
return true;
}
if (cls.getAnnotations().get(JSClass.class.getName()) != null) {
return false;
}
if (cls.getParent() != null) {
if (typeHelper.isJavaScriptClass(cls.getParent())) {
return true;
}
}
return cls.getInterfaces().stream().anyMatch(typeHelper::isJavaScriptClass);
}
private boolean addInterfaces(ExposedClass exposedCls, ClassReader cls) {
boolean added = false;
for (String ifaceName : cls.getInterfaces()) {

View File

@ -26,12 +26,13 @@ import org.teavm.jso.JSProperty;
import org.teavm.junit.EachTestCompiledSeparately;
import org.teavm.junit.OnlyPlatform;
import org.teavm.junit.SkipJVM;
import org.teavm.junit.SkipPlatform;
import org.teavm.junit.TeaVMTestRunner;
import org.teavm.junit.TestPlatform;
@RunWith(TeaVMTestRunner.class)
@SkipJVM
@OnlyPlatform(TestPlatform.JAVASCRIPT)
@OnlyPlatform({TestPlatform.JAVASCRIPT, TestPlatform.WEBASSEMBLY_GC})
@EachTestCompiledSeparately
public class FunctorTest {
@Test
@ -45,6 +46,7 @@ public class FunctorTest {
}
@Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void functorIdentityPreserved() {
JSBiFunction javaFunction = (a, b) -> a + b;
JSObject firstRef = getFunction(javaFunction);
@ -89,6 +91,7 @@ public class FunctorTest {
}
@Test
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
public void castToFunctor() {
JSBiFunction f = getBiFunctionAsObject().cast();
assertEquals(23042, f.foo(23, 42));