wasmerio / wasmer-java

☕ WebAssembly runtime for Java

Home Page:https://medium.com/wasmer/announcing-the-first-java-library-to-run-webassembly-wasmer-jni-89e319d2ac7c

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Exception when passing a callback as parameter

kamphaus opened this issue · comments

Describe the bug

Trying to call a WASM method passing a callback parameter fails with a RuntimeException.

Steps to reproduce

The following Rust code builds the WASM code passed to Instance:

#[no_mangle]
pub extern fn greet(print: extern fn(u8)) {
    print(42)
}

The following Java code fails when trying to call the greet method:

Instance instance = new Instance(wasm);
Consumer<Object> print = (Object o) -> System.out.println("Printed: " + ((Integer) o));
instance.exports.getFunction("greet").apply(print);
instance.close();

Actual behavior

When run, this fails with the following exception:

Exception in thread "main" java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: java.lang.RuntimeException: Failed to convert the argument 0nth of `greet` into a WebAssembly value.
	at org.wasmer.Instance.nativeCallExportedFunction(Native Method)
	at org.wasmer.Exports.lambda$null$0(Exports.java:85)
	at org.example.wasmhost.WasmHostApplication.main(WasmHostApplication.java:45)
	... 8 more

Additional context

My Java version is:

$ java -version
openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.18.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.18.04, mixed mode, sharing)

Hello,

That's expected. Wasm understand i32, i64, f32 and f64. A callback (which is a function pointer) isn't accepted :-).

I see that it's possible with the embedded WASM in javascript (using the wasm-bindgen rust library):
https://rustwasm.github.io/wasm-bindgen/reference/receiving-js-closures-in-rust.html

Also wasmer seems to support callbacks since wasmerio/wasmer#670 was closed in 2019.

wasm-bindgen is really tied to Rust and Javascript. It instruments Rust to generate specific code for Javascript. It's not the case here. wasm-bindgen is not language agnostic.

In wasmerio/wasmer#670, it's not related to passing callbacks from host to Wasm. It was related to calling Wasm functions by their index. And the index was encoded in a u32. But we were talking about Wasm functions, not host functions.

wasmer-java needs more love to support imported functions, memories etc. I'll soon get more time to work on it and to improve it largely, but supporting host functions as Wasm exported function's argument is not part of the plan, and it's very unlikely to be possible in a short-term future.

Note, you can store your function pointer in a Table and pass the table index to the function.
Note 2: wasmer-java doesn't support Table yet for the moment (but wasmer does support it!)

Thanks, that would be great if calling back to Java code from Wasm was possible.
I also tried out GraalVM's polyglot wasm support, but no luck with that either.

Can you describe me what you're trying to achieve please? Maybe it's possible in another way.

I'm trying to develop a plugin system for a Spring Boot Java API.
It should be possible to load/unload plugins without restarting the JVM and have well defined interfaces.
I thought it might be simpler to manage a wasm context per plugin rather than OSGi or webhooks, especially if we might use GraalVM native-image in the future.

Wasm is a good fit for your usecase indeed!

You can callback Java from Wasm with imported (host) function. It's not possible yet with wasmer-java but I'll add it soon :-).