Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Porting Swift to WebAssembly

Porting Swift to WebAssembly

Event: WebAssembly Live! Extended https://www.webassembly.live/

WebAssembly is now a compilation target of Swift. SwiftWasm project compiles Swift into Wasm using LLVM. It was an interesting challenge because Swift uses some architecture-dependent techniques. This talk covers the story of bringing Swift to WebAssembly: Porting the Swift compiler, interacting with JavaScript, interoperation of async API using JavaScript event loop.

7a4968fbcd56e81f95a4f3c186141b52?s=128

Yuta Saito

March 30, 2021
Tweet

Transcript

  1. Porting Swift to WebAssembly WebAssembly Live! Extended @kateinoigakukun 1

  2. Who am I Yuta Saito (a.k.a @kateinoigakukun) • Co-maintainer of

    SwiftWasm • Working at Merpay, Inc. • Love Swift ! 2
  3. Motivation: Why Swift? • Safe • Flexible • Not only

    for iOS application • Multi-paradigm • Compiled Language • Seamless C-interoperability 3
  4. Motivation: Why porting to WebAssembly? • Portable • Access to

    Web developer community 4
  5. The all story started with an issue 5

  6. The story of SwiftWasm • Apr, 2019: Initial efforts made

    by @patcheng, @maxdesiatov and @zhuowei • Setting up basic build system for cross-compiling for Wasm • Build stdlib using WASI and wasi-libc for POSIX APIs. 6
  7. The story of SwiftWasm • Sep, 2019: Started hunting Wasm

    specific bugs around compiler • Relative Pointer • Swift Calling Convention • etc... 7
  8. Relative Pointer • Offset is 32-bit, saving lots of space

    on 64-bit platforms. • Calculated by PC-relative relocation designed for jumping. 8
  9. Issue with Relative Pointer No PC-relative relocation like R_X86_64_PC32 at

    that time WASM_RELOC(R_WASM_TABLE_NUMBER_LEB, 20) WASM_RELOC(R_WASM_MEMORY_ADDR_TLS_SLEB, 21) WASM_RELOC(R_WASM_FUNCTION_OFFSET_I64, 22) +WASM_RELOC(R_WASM_MEMORY_ADDR_LOCREL_I32, 23) // S + A - P https://reviews.llvm.org/D96659 9
  10. Swift Calling Convention declare swiftcc void @foo(i32, i32) @data =

    global i8* bitcast (void (i32, i32)* @foo to i8*) define swiftcc void @bar() { %1 = load i8*, i8** @data %2 = bitcast i8* %1 to void (i32, i32, i32, i32)* ; Crash on WebAssembly! ; >> call_indirect to a signature that does not match call swiftcc void %2(i32 1, i32 2, i32 swiftself 0, swifterror 0) %3 = bitcast i8* %1 to void (i32, i32, i32)* ; Crash on WebAssembly! ; >> call_indirect to a signature that does not match call swiftcc void %3(i32 1, i32 2, i32 swiftself 0) ret void } 10
  11. Swift Calling Convention ; lowered as: ; declare swiftcc void

    @foo(i32, i32, swiftself i32, swifterror i32); declare swiftcc void @foo(i32, i32) @data = global i8* bitcast (void (i32, i32)* @foo to i8*) define void @main() { %1 = load i8*, i8** @data %2 = bitcast i8* %1 to void (i32, i32, i32, i32)* call swiftcc void %2(i32 1, i32 2, i32 swiftself 0, swifterror 0) %3 = bitcast i8* %1 to void (i32, i32, i32)* ; lowered as: ; call swiftcc void %2(i32 1, i32 2, i32 swiftself 0, i32 swifterror 0) call swiftcc void %3(i32 1, i32 2, i32 swiftself 0) ret void } https://reviews.llvm.org/D76049 11
  12. The story of SwiftWasm • Jan, 2020: Develop WebAssembly debugger

    https://github.com/kateinoigakukun/wasminspect 12
  13. The story of SwiftWasm • Mar, 2020: Passing all standard

    library test suites 13
  14. The story of SwiftWasm • Mar, 2020: Continuous Integration and

    Delivery 14
  15. The story of SwiftWasm • Apr, 2020: Published JavaScriptKit: JavaScript

    interoperation • Jul, 2020: Published Tokamak: SwiftUI compatible UI framework for Wasm 15
  16. Tokamak: SwiftUI compatible UI framework for Wasm import TokamakDOM struct

    Counter: View { @State var count: Int = 0 var body: some View { VStack { Text("\(count)") HStack { Button("Reset") { count = 0 } Button("Increment") { count += 1 } } } } } Try it out!: https://pad.swiftwasm.org/ 16
  17. The story of SwiftWasm • Nov, 2020: Swift cross-module DCE

    to reduce binary size • Jan, 2021: Experimental concurrency support with JS event loop 17
  18. import JavaScriptKit let fetch = JSObject.global.fetch.function!.async func printZen() async throws

    { let result = try await fetch("https://api.github.com/zen").bject! let text = try await result.asyncing.text!() print(text) } JavaScriptEventLoop.runAsync { try! await printZen() } 18
  19. import JavaScriptKit let fetch = JSObject.global.fetch.function!.async func printZen() async throws

    { let result = try await fetch("https://api.github.com/zen").object! let text = try await result.asyncing.text!() print(text) } JavaScriptEventLoop.runAsync { try! await printZen() } 19
  20. import JavaScriptKit let fetch = JSObject.global.fetch.function!.async func printZen() async throws

    { let result = try await fetch("https://api.github.com/zen").object! let text = try await result.asyncing.text!() print(text) } JavaScriptEventLoop.runAsync { try! await printZen() } 20
  21. import JavaScriptKit let fetch = JSObject.global.fetch.function!.async func printZen() async throws

    { let result = try await fetch("https://api.github.com/zen").object! let text = try await result.asyncing.text!() print(text) } JavaScriptEventLoop.runAsync { try! await printZen() } 21
  22. import JavaScriptKit let fetch = JSObject.global.fetch.function!.async func printZen() async throws

    { let result = try await fetch("https://api.github.com/zen").object! let text = try await result.asyncing.text!() print(text) } JavaScriptEventLoop.runAsync { try! await printZen() } 22
  23. import JavaScriptKit let fetch = JSObject.global.fetch.function!.async func printZen() async throws

    { let result = try await fetch("https://api.github.com/zen").object! let text = try await result.asyncing.text!() print(text) } JavaScriptEventLoop.runAsync { try! await printZen() } 23
  24. Future Works • WASI-less "bare metal" target • Performance and

    Binary size improvement 24
  25. Contributions are welcome! • Website: https://swiftwasm.org • GitHub: https://github.com/swiftwasm 25

  26. Thanks! • All SwiftWasm contributors and sponsors • The Swift

    community 26