Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TeaVM on embeddable runtimes #1003

Open
mipastgt opened this issue Jan 26, 2025 · 8 comments
Open

TeaVM on embeddable runtimes #1003

mipastgt opened this issue Jan 26, 2025 · 8 comments

Comments

@mipastgt
Copy link

mipastgt commented Jan 26, 2025

I am currently experimenting with embeddable Wasm runtimes. In particular

I wonder why I am not able to even get a primitive Java function, compiled via TeaVM to Wasm,
running on any of these runtimes, whereas the same tests work without problems for an
equivalent C function compiled via Emscripten. See attachements.

On these runtimes I get the following error messages, but they don't make much sense to me.
Is there some mistake on my side or is TeaVM just incompatible with these runtimes?
How are the Java and C versions of the generated Wasm different?

The C version was compiled with
emcc --no-entry -s EXPORTED_FUNCTIONS=_fibonacci -o c_fibonacci.wasm c_fibonacci.c

GraalWasm:

Only function types are supported in the type section
org.graalvm.polyglot.PolyglotException: Only function types are supported in the type section
	at app//org.graalvm.polyglot.Context.eval(Context.java:402)
	at app//de.mpmediasoft.wasm.library.LibraryWasmGraalImpl.<clinit>(LibraryWasmGraalImpl.kt:28)
	at app//de.mpmediasoft.wasm.KotlinWasmGraalTest.<init>(KotlinWasmGraalTest.kt:6)
    ...

Chasm:

Failed to instantiate module: ExecutionError(error=MissingImport)
java.lang.IllegalStateException: Failed to instantiate module: ExecutionError(error=MissingImport)
    at io.github.charlietap.chasm.embedding.shapes.ChasmResultKt.expect(ChasmResult.kt:56)
    at de.mpmediasoft.wasm.library.LibraryWasmChasmImpl$Companion.instantiateModule(LibraryWasmChasmImpl.kt:29)
    at de.mpmediasoft.wasm.library.LibraryWasmChasmImpl$Companion.access$instantiateModule(LibraryWasmChasmImpl.kt:12)
    at de.mpmediasoft.wasm.library.LibraryWasmChasmImpl.<clinit>(LibraryWasmChasmImpl.kt:35)

Chicory:

Caused by: com.dylibso.chicory.wasm.MalformedException: section size mismatch, unexpected end of section or function, We don't support non func types. Form 0x5E was given but we expected 0x60
	at com.dylibso.chicory.wasm.Parser.parse(Parser.java:227)
	at com.dylibso.chicory.wasm.Parser.parse(Parser.java:198)
	at de.mpmediasoft.wasm.library.LibraryWasmChicoryImpl$Companion.instantiateModule(LibraryWasmChicoryImpl.kt:19)
	at de.mpmediasoft.wasm.library.LibraryWasmChicoryImpl$Companion.access$instantiateModule(LibraryWasmChicoryImpl.kt:15)
	at de.mpmediasoft.wasm.library.LibraryWasmChicoryImpl.<clinit>(LibraryWasmChicoryImpl.kt:26)

Archiv.zip

@konsoletyper
Copy link
Owner

I have no idea why these runtimes don't run TeaVM-generated binaries properly. Perhaps, it's a good idea to ask authors of these runtimes. However, what can be:

  1. You used new TeaVM Wasm GC BE instead of classical Wasm BE, while none of these runtimes support Wasm GC. Please, look through official site and learn samples dir here for the answers.
  2. These runtimes are standalone, so they can't execute JavaScript. Wasm itself is just a sandbox which only execute some virtual machine, unable to communicate with the real world, so without having ability to import JS functions or having pre-existing runtime like WASI, the whole Wasm is useless. If the lack of JS is the case, then you'll better use WASI BE. Please, refer to web site, samples dir or learn the code.

@konsoletyper
Copy link
Owner

Another option could be to embed this runtimes (if possible) and to provide all necessary imports

@mipastgt
Copy link
Author

  1. At least Chasm does support GC.
Additionally, the runtime supports the following proposals

    Tail Call
    Extended Constant Expressions
    Typed Function References
    Wasm GC
    Multiple Memories
    Exception Handling
  1. The example function does not need any JS or WASI calls. If I'd need that I could problably use
    https://weh.released.at/api/index.html

@konsoletyper
Copy link
Owner

  1. By the stacktrace you provided, Chasm complains on missing import function, although it does not report which function it is. You may disassemble wasm file to find out which imports it requires, and even why.
  2. The example function does not need any JS or WASI calls. It does not matter. It uses Java runtime, which may rely on JS or WASI internally. You can turn on name section generation and disassemble the module to figure out what's using these imports.

@mipastgt
Copy link
Author

Thanks. I'll have a look.

@konsoletyper
Copy link
Owner

And the short clarification for you. Wasm GC BE was designed primarily for using in the browser. Therefore, it always exports Java functions as Wasm functions with all parameters having type externref, and then uses imported JS function to convert them to actual Java values, even if it's a primitive. An optimization could be implemented to avoid this, but this optimization is of a low priority due to the focus. Also, TeaVM tries to generate exceptions that can be properly handled from outside (i.e. from JS), so it also uses couple of methods to properly wrap JS exceptions with Wasm GC structures. This implies certain methods got imported from JS even for some minimal code that does not communicate with outer world.

As a workaround, make sure that your embedded runtime provides implementations for these methods, that should not be too hard. Read this file for the inspiration.

Another possibility is to try classical Wasm BE, but I'm not sure it does not import anything from JS.

@CharlieTap
Copy link

Hey 👋🏼 @mipastgt Asked me to take a look at this so I thought I'd dump my context

As well as needing particular imports to run:

 (import "teavm" "takeStackTrace" (func (;0;) (type 24)))
  (import "teavm" "decorateException" (func (;1;) (type 40)))
  (import "teavmJso" "stringFromCharCode" (func (;2;) (type 25)))
  (import "teavmJso" "createClass" (func (;3;) (type 30)))
  (import "teavmJso" "defineFunction" (func (;4;) (type 32)))
  (import "teavmJso" "defineStaticMethod" (func (;5;) (type 33)))
  (import "teavmJso" "emptyString" (func (;6;) (type 39)))
  (import "teavmJso" "concatStrings" (func (;7;) (type 42)))
  (import "teavmJso" "unwrapInt" (func (;8;) (type 43)))
  (import "teavmJso" "wrapInt" (func (;9;) (type 25)))

The binary produced doesn't seem to export a function you can call, instead it exports a global:

  (export "teavm.getJsException" (func 29))
  (export "teavm.setJsException" (func 30))
  (export "teavm.javaException" (tag 0))
  (export "fibonacci" (global 16))
  (export "teavm.memory" (memory 0))

I don't know of any wasm runtimes which would allow this to work, typically you can only execute functions that exported. Even if the global contained a function reference the runtime should prevent that function running unless its exported

@konsoletyper
Copy link
Owner

I don't know of any wasm runtimes which would allow this to work

At least, browser allows this. Also, I guess v8 and spidermonkey as standalone/embedded runtimes.

Anyway, what's the problem from @mipastgt side to provide these functions in embedded Chasm?

I don't know of any wasm runtimes which would allow this to work, typically you can only execute functions that exported

Are you sure? Browser allows to export them. Here you can find out how TeaVM

Even if the global contained a function reference the runtime should prevent that function running unless its exported

It contains externref. Actually, defineFunction should take Wasm function ref and convert it into embedder's function. TeaVM does it this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants