$30 off During Our Annual Pro Sale. View Details »

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.

Yuta Saito

March 30, 2021
Tweet

More Decks by Yuta Saito

Other Decks in Technology

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