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
base: main
Are you sure you want to change the base?
Changes from all commits
368591a
f0813d9
4ceaf01
f3bd451
c51de07
1a427da
9e07dd2
bd1b5c6
699af86
8e48421
edb2c31
387b8fd
ae72732
e177c67
9f4fddf
51e5d1b
f1195a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# A Vision for WebAssembly Support in Swift | ||
|
||
## Introduction | ||
|
||
WebAssembly (abbreviated [Wasm](https://webassembly.github.io/spec/core/intro/introduction.html#wasm)) is a virtual | ||
machine instruction set focused on portability, security, and high performance. It is vendor-neutral, designed and | ||
developed by [W3C](https://w3.org). An implementation of a WebAssembly virtual machine is usually called a | ||
*WebAssembly runtime*. | ||
|
||
One prominent spec-compliant implementation of a Wasm runtime in Swift is [WasmKit](https://github.com/swiftwasm/WasmKit). It is available as a Swift package, supports multiple | ||
host platforms, and has a simple API for interaction with guest Wasm modules. | ||
|
||
An application compiled to a Wasm module can run on any platform that has a Wasm runtime available. Despite its origins | ||
in the browser, it is a general-purpose technology that has use cases in client-side and | ||
server-side applications and services. WebAssembly support in Swift makes the language more appealing in those settings, | ||
and also brings it to the browser where it previously wasn't available at all. It facilitates a broader adoption of | ||
Swift in more environments and contexts. | ||
|
||
We can't anticipate every possible application Swift developers are going to create with Wasm, but we can provide a few | ||
examples of its possible adoption in the Swift toolchain itself. To quote | ||
[a GSoC 2024 idea](https://www.swift.org/gsoc2024/#building-swift-macros-with-webassembly): | ||
|
||
> WebAssembly could provide a way to build Swift macros into binaries that can be distributed and run anywhere, | ||
> eliminating the need to rebuild them continually. | ||
|
||
This can be applicable not only to Swift macros, but also for the evaluation of SwiftPM manifests and plugins. | ||
|
||
The WebAssembly instruction set has useful properties from a security perspective, as it has | ||
no interrupts or peripheral access instructions. Access to the underlying system is always done by calling | ||
explicitly imported functions, implementations for which are provided by an imported WebAssembly module or a WebAssembly | ||
runtime itself. The runtime has full control over interactions of the virtual machine with the outside world. | ||
|
||
WebAssembly code and data live in completely separate address spaces, with all executable code in a given module loaded | ||
and validated by the runtime upfront. Combined with the lack of "jump to address" and a limited set of control flow | ||
instructions that require explicit labels in the same function body, this makes a certain class of attacks impossible to | ||
execute in a correctly implemented spec-compliant WebAssembly runtime. | ||
|
||
In the context of Swift developer tools, arbitrary code execution during build time can be virtualized with Wasm. | ||
While Swift macros, SwiftPM manifests, and plugins are sandboxed on Darwin platforms, with Wasm we can provide stronger | ||
security guarantees on other platforms that have a compatible Wasm runtime available. | ||
|
||
The WebAssembly instruction set is designed with performance in mind. A WebAssembly module can be JIT-compiled or | ||
compiled on a client machine to an optimized native binary ahead of time. With recently accepted proposals to the Wasm | ||
specification it now supports features such as SIMD, atomics, multi-threading, and more. A WebAssembly runtime can | ||
generate a restricted subset of native binary code that implements these features with little performance overhead. | ||
|
||
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 | ||
Comment on lines
+47
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I love this sentence :) |
||
Swift compiler and SwiftPM plugin/manifest invocation. Virtualized Wasm binaries can run in the host process of a | ||
Wasm runtime, removing the overhead of new process setup and IPC infrastructure. | ||
|
||
### WebAssembly System Interface and the Component Model | ||
|
||
The WebAssembly virtual machine has no in-built support for I/O; instead, a Wasm module's access to I/O is dependent entirely upon the runtime that executes it. | ||
|
||
A standardized set of APIs implemented by a Wasm runtime for interaction with the host operating system is called | ||
[WebAssembly System Interface (WASI)](https://wasi.dev). A layer on top of WASI that Swift apps compiled to Wasm can already | ||
use thanks to C interop is [WASI libc](https://github.com/WebAssembly/wasi-libc). In fact, the current implementation of | ||
Swift stdlib and runtime for `wasm32-unknown-wasi` triple is based on this C library. It is important for WASI support in | ||
Swift to be as complete as possible to ensure portability of Swift code in the broader Wasm ecosystem. | ||
|
||
In the last few years, the W3C WebAssembly Working Group considered multiple proposals for improving the WebAssembly | ||
[type system](https://github.com/webassembly/interface-types) and | ||
[module linking](https://github.com/webassembly/module-linking). These were later subsumed into a combined | ||
[Component Model](https://component-model.bytecodealliance.org) proposal thanks to the ongoing work on | ||
[WASI Preview 2](https://github.com/WebAssembly/WASI/blob/main/preview2/README.md), which served as playground for | ||
the new design. | ||
|
||
The Component Model defines these core concepts: | ||
|
||
- A *component* is a composable container for one or more WebAssembly modules that have a predefined interface; | ||
- *WebAssembly Interface Types (WIT) language* allows defining contracts between components; | ||
- *Canonical ABI* is an ABI for types defined by WIT and used by component interfaces in the Component Model. | ||
|
||
Preliminary support for WIT has been implemented in | ||
[the `wit-tool` subcommand](https://github.com/swiftwasm/WasmKit/blob/0.0.3/Sources/WITTool/WITTool.swift) of the WasmKit | ||
CLI. Users of this tool can generate `.wit` files from Swift declarations, and vice versa: Swift bindings from `.wit` | ||
files. | ||
|
||
## Goals | ||
|
||
As of March 2024 all patches necessary for basic Wasm and WASI support have been merged to the Swift toolchain and | ||
core libraries. Based on this, we propose a high-level roadmap for WebAssembly support and adoption in the Swift | ||
ecosystem: | ||
|
||
1. Ensure that Swift toolchain and core libraries have a regularly running test suite for supported Wasm and WASI | ||
triples. | ||
|
||
2. Allow Swift developers to easily install and build with a Swift SDK for WASI. This requires an implementation | ||
of corresponding build scripts and CI jobs to generate and publish such SDK. Some parts of the Swift toolchain and core | ||
libraries need a Swift SDK for running tests for WASI, so this will benefit the previous point in stabilizing support | ||
for this platform. | ||
|
||
3. Make it easier to evaluate and adopt Wasm with increased API coverage for this platform in the Swift core libraries. As a | ||
virtualized embeddable platform, not all system APIs are always available or easy to port to WASI. For example, | ||
multi-threading, file system access, and localization need special support in Wasm runtimes and a certain amount of | ||
consideration from a developer adopting these APIs. | ||
|
||
4. Improve support for cross-compilation in Swift and SwiftPM. We can simplify versioning, installation, and overall | ||
management of Swift SDKs for cross-compilation in general, which is beneficial not only for WebAssembly, but for all | ||
platforms. | ||
|
||
5. Continue work on Wasm Component Model support in Swift as the Component Model proposal is stabilized. Ensure | ||
that future versions of WASI are available to Swift developers targeting Wasm. A more ambitious long-term goal to | ||
consider is making interoperability with Wasm components as smooth as C and C++ interop already is for Swift. With | ||
a formal specification for Canonical ABI progressing, this goal will become more achievable with time. | ||
|
||
### Proposed Language Features | ||
|
||
In our work on Wasm support in Swift we experimented with a few function attributes that could be considered | ||
as pitches and eventually Swift Evolution proposals, if the community is interested in their wider adoption. | ||
These attributes allow easier interoperation between Swift code and other Wasm modules linked with it by a Wasm | ||
runtime. | ||
|
||
* [`@_extern(wasm)` attribute](https://github.com/apple/swift/pull/69107) that corresponds to Clang's | ||
[`__attribute__((import_name("declaration_name")))`](https://clang.llvm.org/docs/AttributeReference.html#export-name) | ||
and [`__attribute__((import_module("module_name")))`](https://clang.llvm.org/docs/AttributeReference.html#import-module). | ||
This indicates that function's implementation is not provided together with its declaration in Swift and is | ||
available externally, imported by a Wasm runtime during the linking phase. The declaration is added to current Wasm | ||
module's imports section. Without `@_extern(wasm)` developers need to rely on C interop to create a declaration in a C | ||
header using the Clang version of attributes. | ||
|
||
* [`@_expose(wasm)` attribute](https://github.com/apple/swift/pull/68524) that corresponds to Clang's | ||
[`__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 commentThe reason will be displayed to describe this comment to others. Learn more. I wondered if there was going to be a summary or conclusion at the end. It might be nice to have some form of wrap-up, I think. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how that would look without tautologically rehashing what's been said in other sections. I'm open to concrete suggestions though. |
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 think it would be nice to say (or organize sections)
(I'm not sure if we really need Wasm-specific language evolutions)
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.
@_extern(wasm, module:, name:)
might need to be formalized as an SE proposal.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.
And
@_expose(wasm)
too 😉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.
The second point is the main thing I felt was missing here. The third point could probably be part of a section after goals, ie.
Language Support
or something similar. I'm not sure the current state belongs in the vision, it should certainly be part of any associated forum post though.The second seems partially answered by portability/security, but then the sections after that seem more about describing WebAssembly (and its different parts) itself. Maybe those should go under a
WebAssembly Components
(not quite sure if that's the right wording, especially since WebAssembly Component Model is a thing) section. So we'd have eg.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.
Thank you @bnbarham, I've addressed your feedback and added the "Goals" section, limited to 5 high-level goals for now, followed by a short "Proposed Language Features" subsection.