Skip to content

POC: Embedded Swift consumers of dispatch on wasm32-unknown-wasip1 - #7

Draft
scottmarchant wants to merge 4 commits into
feat/scottm/libDispatchWasmV2from
feat/scottm/libDispatchWasmEmbedded
Draft

POC: Embedded Swift consumers of dispatch on wasm32-unknown-wasip1#7
scottmarchant wants to merge 4 commits into
feat/scottm/libDispatchWasmV2from
feat/scottm/libDispatchWasmEmbedded

Conversation

@scottmarchant

Copy link
Copy Markdown
Collaborator

Fork-only proof of concept. This PR is a draft on purpose and is not meant to merge. It shows the Embedded Swift research on top of #3 (the combined WASI port). The full findings live in tests/wasm/EMBEDDED-RESEARCH.md on this branch. The series tracker is #3.

Summary

An Embedded Swift program can import Dispatch and use it today, with the official swift.org swift-6.3.3-RELEASE_wasm-embedded SDK. The smoke test dispatches work, waits on semaphores and groups, arms a timer source, and walks a DispatchData. It passes under both wasmtime v24 LTS and current wasmtime v47 (the output is a plain wasip1 module, so there is no runtime constraint):

PASS: async=8/8 sync=1 group=1 timer=1 source=1 data=4

Binary size is the headline: the same consumer builds to 572 KB embedded vs 7.8 MB with the regular static-stdlib SDK, about 13.6x smaller. The cooperative suite still passes 52 of 52 with these edits.

What this dictates for #3 and #5

  • Prepare shared code for cooperative single-threaded event backends #5 needs no change. The embedded work changes no C code at all, so the slice A seams and signatures are untouched.
  • feat: WASI port V2 — combined branch: #2's runtime + #1's test scenarios + API-contract tests #3's C runtime needs no change. The embedded SDK is the same artifactbundle, triple, and sysroot as the regular wasm SDK; only toolset flags differ. The cooperative event backend is used as is.
  • Two small overlay edits are the entire diff, and they are candidates for slice C (the Swift overlay slice) as an "Embedded Swift compatibility" commit: a plain (not @_implementationOnly) shims import under #if hasFeature(Embedded), and a class bound on DispatchSourceProtocol through a conditional typealias (AnyObject under Embedded, Any elsewhere). The typealias is the one cross-platform-visible addition; an upstream reviewer may prefer a different spelling.
  • Embedded and threads are orthogonal experiments. Embedded rides the cooperative backend on the plain wasip1 triple. A combined embedded+threads build was not attempted.

Discoveries specific to embedded

  • Embedded Swift emits no autolink metadata: the link directives in the module maps are ignored, so consumers must name every archive on the link line. The regular SDK autolinks them.
  • Whole-module mode is mandatory. Under CMake that is CMAKE_Swift_COMPILATION_MODE=wholemodule, and it must be propagated into try_compile or the Swift compiler check fails.
  • The host toolchain ships no wasm compiler-rt builtins; linking through the host swiftc needs the bundle's clang resource dir (-Xclang-linker -resource-dir ...).
  • wasi-libc's CLOCK_MONOTONIC is a pointer macro to an incomplete struct and does not import into Embedded Swift. The overlay is unaffected (it funnels through the C shims); consumer code that uses raw libc clocks will notice.
  • DISPATCH_WASI_EMBEDDED=ON builds libdispatch.a, libBlocksRuntime.a, and libswiftDispatch.a in embedded mode. BUILD_TESTING stays OFF: an embedded ctest lane is future work.

Commits

Four conventional commits: the two overlay edits, the CMake knob, the smoke test, and the research notes.

scottmarchant and others added 4 commits August 19, 2026 13:52
Two gated changes make all nine overlay files compile with
-enable-experimental-feature Embedded, with no API removed and no
signature moved:

- Import _DispatchOverlayShims plainly under #if hasFeature(Embedded).
  Embedded Swift compiles public functions into the client, so an
  @_implementationOnly import is unusable from them (56 errors).
- Constrain DispatchSourceProtocol through a conditional typealias
  that is AnyObject under Embedded and Any elsewhere. Embedded Swift
  only supports class-bound existentials, and the make*Source
  factories return them (14 errors). The only conformer is the
  DispatchSource class, so the bound is factual.

Non-embedded arms are unchanged: the cooperative WASI suite still
passes 52 of 52 with these edits.

Co-authored-by: Krzysztof Rodak <krodak.konta@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cmake ... -DDISPATCH_WASI_EMBEDDED=ON -DENABLE_SWIFT=YES builds
libdispatch.a, libBlocksRuntime.a, and libswiftDispatch.a in Embedded
Swift mode. The knob appends -enable-experimental-feature Embedded,
selects usr/lib/swift as the Swift resource dir (the embedded stdlib
modules live there), forces CMAKE_Swift_COMPILATION_MODE=wholemodule
and propagates it through try_compile (or the compiler check runs
incrementally and reports the compiler as broken), and defines
__EMBEDDED_SWIFT__ on the C side to match the SDK's embedded toolset.

The C library produced with the knob is the cooperative port,
unchanged. The regular configuration is unaffected: the cooperative
suite still passes 52 of 52 after a reconfigure.

Co-authored-by: Krzysztof Rodak <krodak.konta@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add tests/wasm/embedded-dispatch-smoke.swift, an Embedded Swift
consumer of the overlay built in embedded mode. Under wasmtime v24
LTS and current wasmtime v47 it prints:

    PASS: async=8/8 sync=1 group=1 timer=1 source=1 data=4

Coverage: eager async on the cooperative backend, serial sync,
DispatchGroup wait, a dispatch_after timer firing while a semaphore
wait pumps, a timer DispatchSource through the class-bound existential
path, and DispatchData append/iterate through the shims funnel. The
same source builds to 572 KB embedded vs 7.8 MB with the regular
static-stdlib SDK.

Co-authored-by: Krzysztof Rodak <krodak.konta@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add tests/wasm/EMBEDDED-RESEARCH.md: the official swift.org embedded
wasm SDK shares the wasm32-unknown-wasip1 triple and sysroot with the
regular SDK and differs only in toolset flags, so the C library and
the cooperative event backend need zero changes. Record the toolchain
facts that cost time: the host toolchain lacks wasm compiler-rt
builtins (override the clang resource dir), Embedded Swift emits no
autolink metadata (consumers must name every archive), whole-module
mode is mandatory, and wasi-libc clockid macros do not import.

Co-authored-by: Krzysztof Rodak <krodak.konta@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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

Successfully merging this pull request may close these issues.

1 participant