-
-
Notifications
You must be signed in to change notification settings - Fork 268
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
Draft of WASI support #610
Conversation
This is a first pass at implementing support for [WASI](https://wasi.dev/). It adds a new `TeaVMTargetType` of `WASI`, which is mostly the same as `WEBASSEMBLY` except it generates a module suitable for execution by a WASI-compatible runtime such as [Wasmtime](https://github.com/bytecodealliance/wasmtime). Currently supported features: - A simple allocator for supporting the component model [canonical ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md) calls - CLI argument marshaling - Standard in/out/err - Filesystem operations and I/O - System clock See tests/wasi/src/main/java/wasi/Test.java and tests/wasi/test.sh for examples. Not yet implemented: - Networking (i.e. sockets) - Environment variables - System random numbers - Process exit, yield, etc. - [DWARF](https://dwarfstd.org/) debugging support - Better logging of uncaught exceptions Note that the current implementation is probably overly paranoid in that all pointer arguments passed to WASI functions are allocated by the aforementioned allocator rather than on the Java heap. I've done this because I'm not clear on when TeaVM guarantees that object address will not change. Thus I've assumed that they could change at any time whatsoever, which is probably not true. Also note that the filesystem implementation currently throws generic `IOException`s and `ErrnoException`s rather than those specified by the standard (e.g. `FileNotFoundException`). Additional work will be needed to throw the correct exception based on the `errno` value. The main goal of this PR is to start a discussion about WASI support in TeaVM and answer questions such as: - Is WASI support a reasonable goal for the TeaVM project? - If so, is the approach of this PR roughly correct, or are significant changes needed? - What other features are missing to make this useful? Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Let's start with discussion: what is the purpose of running Java in WASI? Why not just running JVM? |
As for introducing separate target for WASI: currently it looks quite dirty. I'd consider updating wasm-runtime.js to emulate WASI in the browser. |
Haven't we already talked about this? My reasons are:
|
This PR also lacks the way of running classlib tests for WASI target. |
As for buffers. TeaVM GC can move objects. However, it does not move any objects to which there are references from stack. This means that for any non-asynchronous call it's ok to use byte array in heap instead of custom allocator. |
@konsoletyper First, thanks for all the work you've put into TeaVM. The WebAssembly support in particular is quite impressive and useful. I've looked at other similar projects, but TeaVM seems to be the most robust and flexible.
Excellent question. @jcaesar mentioned a few reasons related to the precise control and security guarantees you get when embedding untrusted Wasm code in an application. Another use case is lightweight, multi-tenant cloud computing tasks. Companies like Fastly, Shopify, and Fermyon (my current employeer) are using WASI and the component model to host and run customer code in a secure, platform-, architecture-, and language-agnostic way. A traditional JVM is not a great fit for this for a few reasons:
To be clear, are you suggesting I should remove the WASI target and make the WEBASSEMBLY target generate a WASI-compatible module by default, which would rely on wasm-runtime.js to adapt it for use in the browser? If so, that sounds reasonable to me. BTW, a WASI polyfill is already available: https://wasi.dev/polyfill/. Perhaps we could reuse that? I haven't looked at the code yet, though -- it might be too heavyweight for this purpose.
Good point. I focused on testing the WASI-specific parts first, but I agree that we should run all the existing classlib tests. I'll put that on my TODO list.
Thanks, that's helpful. I'll update the code with that in mind. |
This polyfill is for an older version of WASI (wasi_unstable) and uses emscripten behind the scenes, which means it is about 400kb big. I have written a pure javascript polyfill for a subset of the current WASI version (wasi_snapshot_v0): https://github.com/bjorn3/browser_wasi_shim I believe there are also other wasi javascript polyfills. |
This PR is awesome. Great work on this @dicej. Adding some comments that I believe could be relevant:
Can we make this PR runtime agnostic? I believe it will be beneficial to have the runtime as an environment variable rather than statically defined. That way we can test easily with Wasmer, Wizer or any other server-side Wasm VM.
Wasmer already ships the most popular WASI implementation for JS. It might be worth using it here (it's already used officially by the Ruby ecosystem): https://www.npmjs.com/package/@wasmer/wasi (specially because if tests pass when using Wasmer as a runtime in the Github CI, it will be assured that it will work exactly the same way on the browser). Thoughts? |
My previous commit was based on the assumption that objects allocated on the Java heap could be moved by TeaVM at any time. It turns out TeaVM will not move objects which are referenced by stack variables, so we can use those instead of `malloc`ed buffers. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Per review feedback, this removes `TeaVMTargetType.WASI` and makes `TeaVMTargetType.WEBASSEMBLY` generate a WASI module unconditionally. Such modules won't run in a browser without a polyfill, which I plan to add in a later commit. Along the way, I noticed the `Console` intrinsics weren't working properly and fixed them. Finally, this adds a new `WasiRunStrategy` which runs the full TeaVM test suite using either Wasmtime or Wasmer. You can try it by running the following from the test directory: ``` mvn -e install \ -Dteavm.junit.js=false \ -Dteavm.junit.js.runner=none \ -Dteavm.junit.wasm=true \ -Dteavm.junit.wasm.runner=wasi-wasmer ``` Specify `-Dteavm.junit.wasm.runner=wasi-wasmtime` to use Wasmtime. Currently many of the tests are failing, but I haven't had a chance to investigate yet or compare the results to the same tests running in a browser using an unmodified TeaVM. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
How big is WasmerJS's WASI? From what I see, the average TeaVM module doesn't need much more than |
WasmerJS's WASI is around 120Kb gzip-compressed. From looking at the PR, it seems that the WASI requirements are mainly on the filesystem and clock: To implement those properly, you will usually require a in-memory FS (which is where most of the bulk comes from, looking at Wasmer-JS). |
Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Previously, TeaVM used imported functions for timezone resolution, char case conversion, and floating point tests. Since WASI doesn't support any of those things, we implement them in Java as best we can. Floating point tests are easy; timezone resolution will have to wait for WebAssembly/WASI#467 (we hard-code UTC for now); case conversion can be done entirely in Java, although I've only handled ASCII characters in this commit. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Signed-off-by: Joel Dice <joel.dice@fermyon.com>
One of the tests had been running for 90 minutes when I gave up on it. Now we time out any tests that takes longer than 5 minutes. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Signed-off-by: Joel Dice <joel.dice@fermyon.com>
A previous commit provided stub implementations of `getNativeOffset`, `toUpperCase`, and `toLowerCase`. This reverts that change and instead uses the JS versions in the browser. It won't work in a WASI runtime without providing the extra imports to the module, but there's currently no way to get the local timezone in WASI, and I'm not yet ready to take on a proper implementation of `toUpperCase` and `toLowerCase`. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Signed-off-by: Joel Dice <joel.dice@fermyon.com>
This uses https://github.com/bjorn3/browser_wasi_shim to emulate WASI features. Note that I had to change the API for TeaVM `main` since `browser_wasi_shim` requires that CLI arguments are known before the module is loaded. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Status update: I've removed I've also added a new Finally, I've implemented support for environment variables and random numbers, as well as pure Java implementations of Caveat: There are still several functions in the class library which require non-WASI imports from the host, including local timezone resolution, character case conversion, and various math functions. Code which uses any of those features will result in a module that imports functions not provided by WASI and thus won't run on a WASI runtime unless those imports are explicitly satisfied (e.g. by an embedding application). For timezone resolution, we can use WebAssembly/WASI#467 if/when it is implemented. The other functions could in principal be implemented in pure Java with no host support, but I'll leave that as a future improvement. @konsoletyper What do you think? Is there anything you'd like to see changed or added, or is this something you'd consider merging? |
Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Signed-off-by: Joel Dice <joel.dice@fermyon.com>
@konsoletyper I'm guessing you're busy and that this PR isn't a high priority for you right now, which is totally understandable. For the time being, it might be best if I create a friendly fork of the TeaVM repo for further WASI development and publish Maven packages under a different name (e.g. teavm-wasi) and group for anyone to use. We'd like to start using this at Fermyon, and I know there are others who are interested in using it as well. Thoughts? |
@dicej @konsoletyper we are interested in this PR. |
Same here |
Per my above comment, I've created a friendly fork of this project and published an initial release to the Maven Central repository under the I'll be using that fork for WASI and Component Model work going forward. Feel free to open issues and/or PRs there if you're interested in helping out. |
I'd like to caution: Java fits Web APIs and JavaScript almost naturally due to its many similarities, an advantage that makes it a great source language for WebAssembly in actual browsers due to sharing many concepts. Neither WASI nor the Component Model share Java respectively Web/JS concepts, but are afaict attempts to establish a new foundation where the disadvantages of the few blessed first-class languages become every other language's disadvantage over mere opinion. This, and especially that this PR now proposes to unconditionally emit WASI modules even when targeting browsers, has a bunch of implications for anything with an almost natural fit for the Web platform - here effectively turning Java's good fit into concrete disadvantages, none of which is mentioned as a caveat by those now trying to persuade TeaVM into supporting (and then indirectly promoting) the imho fundamentally misguided and, frankly, questionable approach to Web standards they are responsible for themselves. FYI, take care :) |
This is a first pass at implementing support for WASI. It adds a new
TeaVMTargetType
ofWASI
, which is mostly the same asWEBASSEMBLY
except it generates a module suitable for execution by a WASI-compatible runtime such as Wasmtime.Currently supported features:
See tests/wasi/src/main/java/wasi/Test.java and tests/wasi/test.sh for examples.
Not yet implemented:
Note that the current implementation is probably overly paranoid in that allpointer arguments passed to WASI functions are allocated by the aforementioned
allocator rather than on the Java heap. I've done this because I'm not clear on
when TeaVM guarantees that object address will not change. Thus I've assumed
that they could change at any time whatsoever, which is probably not true.
Also note that the filesystem implementation currently throws generic
IOException
s andErrnoException
s rather than those specified by the standard(e.g.
FileNotFoundException
). Additional work will be needed to throw thecorrect exception based on the
errno
value.The main goal of this PR is to start a discussion about WASI support in TeaVM and answer questions such as:
Signed-off-by: Joel Dice joel.dice@fermyon.com