-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
A Vision for WebAssembly Support in Swift #2358
Conversation
This means that adoption of Wasm in developer tools does not imply unavoidable performance overhead. In fact, with | ||
security guarantees that virtualization brings there's no longer a need to spawn a separate process for each |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love this sentence :)
Co-authored-by: Yuta Saito <[email protected]>
Co-authored-by: Ben Barham <[email protected]>
Co-authored-by: Alex Hoppen <[email protected]>
Co-authored-by: Alex Hoppen <[email protected]>
Co-authored-by: Hamish Knight <[email protected]>
Co-authored-by: Alastair Houghton <[email protected]>
I see this primarily as a topic for the new Platform Steering Group, but we'll look it over on the LSG as well. |
Could this also talk a little about the story re. debugging? How do we debug Swift code built on WASM? Does it matter whether we're debugging in the browser or using a separate WASM interpreter like wasmtime? Do we support attaching LLDB somehow? How are we going to deal with metadata? |
There's no debugging story, unfortunately. Some browsers had some support for source maps at some point, some rely on DWARF, some have no support for debugging other then stepping through disassembly. I'm not aware of Wasm runtimes that have special support for debugging, other than @kateinoigakukun's wasminspect. There's apparently a WebAssembly Debugging Subgroup, but they have no meeting minutes posted since 2020. |
I think, since this is a vision document, it should probably expand on what debugging should look like, or what our goal is here in that regard, and maybe a summary of what is presently possible would be useful along with some ideas about how we might make progress towards the end goal (which, presumably, is some kind of support for source-level debugging of Swift programs running on WASM)? |
[`__attribute__((export_name("name")))`](https://clang.llvm.org/docs/AttributeReference.html#export-name), which | ||
is the counterpart of `@_extern(wasm)` working in the opposite direction. This explicitly makes a Swift declaration | ||
available outside of the current module, added to its exports section under a given name. Again, the lack of | ||
this attribute in Swift requires use of C headers as a workaround. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added brief notes about debugging, multi-threading, 64-bit, and shared library directions. Feel free to ignore or amend this if it's too implementation details :)
this attribute in Swift requires use of C headers as a workaround. | |
this attribute in Swift requires use of C headers as a workaround. | |
## Platform-specific Considerations | |
### Debugging | |
Debugging Wasm modules is challenging because Wasm does not expose ways to introspect and control the execution of | |
the Wasm instance, so a debugger cannot be built on top of Wasm itself. Therefore, special support from the Wasm | |
execution engine is necessary for debugging. | |
The current state of debugging tools in the Wasm ecosystem is not as mature as other platforms but there are two | |
main directions: | |
1. LLDB debugger with Wasm runtime supporting GDB Remote Serial Protocol [1] | |
2. Wasm runtime with a built-in debugger [2] | |
The first approach provides an almost equivalent experience to existing debugging workflows on other platforms. It | |
can utilize LLDB's Swift support, remote metadata inspection and serialized Swift module information. However, since | |
Wasm is a Harvard architecture and has no way to allocate executable memory space at runtime, implementing expression | |
evaluation with JIT in user space is challenging. In other words, gdb stub in Wasm engines need tricky implementations | |
or need to extend the GDB Remote Serial Protocol. | |
The second approach embeds the debugger within the Wasm engine. In scenarios where the Wasm engine is embedded as a guest | |
language in another host language engine (e.g. within a Web Browser), this approach allows seamless debugging experiences | |
with the host language by integrating with the host debugger. For example, in cases where JavaScript and Wasm call frames | |
are interleaved, the debugger works well in both contexts without switching tools. Debugging tools like Chrome DevTools | |
can use DWARF information embedded in Wasm file to provide debugging support. However, supporting Swift-specific | |
metadata information and JIT-based expression evaluation will require integrating LLDB's Swift plugin with these debuggers | |
in some way. | |
Given that both approaches can utilize DWARF information, the Swift toolchain should generate as much DWARF information as possible | |
for statically known things. Also, making Swift type information DWARF-friendly is desirable because the current debug | |
information generated by the Swift compiler assumes that debuggers can understand certain Swift primitives (e.g. `Swift.Int` | |
is currently represented as a `DW_TAG_structure_type` node without any member but ideally such types should be represented | |
as `DW_TAG_base_type` nodes with `DW_AT_encoding` attribute or provide a debug summary string by LLDB Summary Strings) | |
[1]: https://github.com/llvm/llvm-project/pull/77949 | |
[2]: https://github.com/ChromeDevTools/devtools-frontend/blob/main/extensions/cxx_debugging | |
### Multi-threading and Concurrency | |
WebAssembly has [atomic operations in the instruction set](https://github.com/WebAssembly/threads) (only sequential | |
consistency is supported), but it does not have a built-in way to create threads. Instead, it relies on the host | |
environment to provide multi-threading support. This means that multi-threading in Wasm is dependent on the Wasm runtime | |
that executes the module. There are two proposals to standardize ways to create threads in Wasm: (1) [wasi-threads](https://github.com/WebAssembly/wasi-threads), | |
which is already supported by some toolchains, runtimes, and libraries but has been superseded by the new one. (2) The | |
new proposal [shared-everything-threads](https://github.com/WebAssembly/shared-everything-threads) is still in the | |
early stages of spec development but is expected to be the future of multi-threading in Wasm. | |
Swift currently supports two threading models in Wasm: single-threaded (`wasm32-unknown-wasi`) and multi-threaded | |
using wasi-threads (`wasm32-unknown-wasip1-threads`). Despite the latter supporting multi-threading, Swift Concurrency defaults | |
to a cooperative single-threaded executor due to the lack of wasi-threads support in libdispatch. Preparing for the | |
shared-everything-threads proposal is crucial to ensure that Swift Concurrency can adapt to future multi-threading | |
standards in Wasm. | |
### 64-bit address space | |
WebAssembly currently uses a 32-bit address space, but the specification is going to support [64-bit address space](https://github.com/WebAssembly/memory64/). | |
Swift already has support on 64-bit for other platforms, however, WebAssembly is the first platform where relative reference | |
from data to code is not allowed. Alternative solutions like image-base relative addressing or small "code model" for fitting | |
64-bit pointer in 32-bit are unavailable, at least for now. This means that we need cooperation from the WebAssembly toolchain | |
side or different memory layout in Swift metadata to support 64-bit in WebAssembly. | |
### Shared libraries | |
There are two approaches to using shared libraries in WebAssembly ecosystem: | |
1. [Emscripten-style dynamic linking](https://emscripten.org/docs/compiling/Dynamic-Linking.html) | |
2. [Component Model-based "ahead-of-time" linking](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Linking.md) | |
Emscripten-style dynamic linking is a traditional way to use shared libraries in WebAssembly, where the host environment provides | |
non-standard dynamic loading capabilities. | |
Component Model-based AOT linking is a new way that transforms shared library WebAssembly Core modules compiled with | |
Emscripten's dynamic linking ABI into a single WebAssembly Component at build time. The latter approach cannot fully replace the former, | |
as it is not able to handle dynamic loading of shared libraries at runtime, but it is more portable way to distribute programs linked | |
with shared libraries because it does not require the host environment to provide any special capabilities except for Component Model | |
support. | |
From the Swift toolchain perspective, they both use the Emscripten's dynamic linking ABI, so the support for shared libraries in | |
Swift is mostly about making sure that Swift programs can be compiled in position-independent code mode and linked with shared | |
libraries by following the dynamic linking ABI. |
Closing this, since after migration to |
For now this contains an introduction section which doesn't assume any prior knowledge of the Wasm ecosystem. It provides overview of properties of Wasm useful when applied to Swift developer tools specifically. A list of high-level goals is provided, with a short subsection for specific language features that can be proposed in the near term.