Design clarification
Now swiftwasm project succeeds to pass quite a few test suite, so we are planning to send some patches to upstream as Max said.
Before sending them, I want to confirm and clarify the direction of supporting WebAssembly.
Implementation design of stdlib
There are some topics to discuss for the implementation of stdlib for WebAssembly.
ICU
I know there is some discussion about implementing a subset of stdlib without ICU. But I want to use ICU to support WebAssembly incrementally. I’ve sent some patches to ICU project to build it for WebAssembly.
- ICU-20978 Reduce unnecessary building for tools when cross-building by kateinoigakukun · Pull Request #990 · unicode-org/icu · GitHub
- ICU-20977 Minimal support for WebAssembly in double-conversion-utils.h by kateinoigakukun · Pull Request #989 · unicode-org/icu · GitHub
After these patches applied, it'll get to be able to built for WebAssembly and integrated with Swift stdlib. Actually, I prepared a patched prebuilt ICU library and it works well on WebAssembly with Swift.
wasi-libc
Swift stdlib depends on libc but libc can’t be built for WebAssembly because pure WebAssembly doesn't have a system call interface.
wasi-libc is a bytecode alliance project which enables us to build a libc compatible library depending on WASI. As same as I want to use ICU to achieve incremental support, I want to depend on WASI to use wasi-libc also.
We need to provide some polyfills for some missing features like pthread, but swiftwasm project has already implemented them and it works well.
Basically we are focusing to run Swift executable files correctly on WebAssembly runtime, so we want to depend on ICU and WASI to support WebAssembly progressively. I also consider supporting WASI independent target in the future, but for that kind of target, we have to implement a subset of stdlib.
In addition, we want to package wasi-libc and ICU libraries in Swift toolchain of WASM. If a general SDK like wasi-sdk becomes popular in the future, we may use it. But at present, it’s difficult to install wasi-sdk, and unlike the general sysroot, the path to be installed is not fixed. For this reason, we think it is appropriate to distribute them as part of the Swift toolchain at this time.
Implementation design of runtime
As zhuowei said in WIP: [Swift+Wasm] initial support for compiling Swift to WebAssembly by zhuowei · Pull Request #24684 · apple/swift · GitHub, some of Swift runtime features can’t work on WebAssembly.
Relative Pointer
Relative Pointer does not work on WASM. See the PR #24684 description for details.
The swiftwasm project has temporarily applied a hacky patch as a solution to this issue. However, the use cases of Relative Pointer have been almost completely identified, and related features also work well.
When merging to the upstream, we plan to implement some kind of abstract pointer type instead of using the RelativePointer type directly. I think that this design should be discussed with the core team more.
swifterror, swiftself
swifterror and swiftself don’t work on WASM also. See the PR #24684 description for details.
I have tried to solve this in several ways.
A conversion from non-throws to throws function and a conversion from thin function to thick function is the root cause of this issue.
First, I tried to emit the thunk function at the SIL level. ABI compatibility between function types is checked in the process of converting a typed AST to SIL. For example, conversion from () -> Int
type to () -> Optional<Int>
type requires thunk, but conversion from ()-> Void
type to () throws -> Void
type doesn’t require thunk.
This patch https://github.com/swiftwasm/swift/pull/6 enables many cases of function calls to work on WASM. However, there was one problem with this solution.
Thunk functions were created at the SIL level, but in some cases, the functions were rewritten as thin_to_thick_function
instructions by optimization. e.g. CapturePropagation rewrites partial_apply
to a thin_to_thick_function
function. As described above, thin_to_thick_function
instruction outputs function call without thunk and it's an invalid instruction as WASM.
So I implemented IRGen as thin_to_thick_function emits valid LLVM IR for WASM. This change transforms thin_to_thick_function
into function call using LLVM IR level thunk like partial_apply
. Here is the patch PR. [WASM] Implement thin-to-thick semantic for WebAssembly by kateinoigakukun · Pull Request #186 · swiftwasm/swift · GitHub
These changes make output executable files no longer cause WASM runtime errors in function calls.
Trivial issues
WebAssembly doesn't support multi-thread yet, so we run the test suite in a single thread. This makes it difficult to run some test suite that expects to be crashed. Should we ignore these kinds of suite temporarily using ifdef? or is there a better way?