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

SwiftのWASM対応 in practice

7a4968fbcd56e81f95a4f3c186141b52?s=47 Yuta Saito
September 13, 2019

SwiftのWASM対応 in practice

7a4968fbcd56e81f95a4f3c186141b52?s=128

Yuta Saito

September 13, 2019
Tweet

Transcript

  1. SwiftͷWASMରԠ in practice Θ͍Θ͍swiftc #14 @kateinoigakukun 1

  2. લճ·Ͱͷ͋Β͢͡ ࠷ۙͷSwiftͷWASMରԠ - Speaker Deck 2

  3. @zhuowei͞Μ͕ਐΊͯΔ https://github.com/apple/swift/pull/24684 3

  4. RelativePointer࢖͑ͳ͍໰୊͸ղফࡁΈ static inline Offset measureRelativeOffset(A *referent, B *base) { #ifdef

    __wasm__ // WebAssembly: hack: disable relative pointers auto offset = (Offset)(uintptr_t)referent; return offset; #endif ... } • offsetͷྖҬʹAbsolutePointerΛຒΊͯରԠͯ͠Δɻ • ໊લͱ࣮ଶ͕ဃ཭͍ͯ͠ΔͷͰ͜ͷ··Ϛʔδ͞ΕΔ͜ͱ͸ ͳͦ͞͏ https://github.com/apple/swift/pull/24684/files#diff-c9c1e1282dc7ca8ab7fb46ceaa35a4fcR170-R176 4
  5. ࢒ΓͷίϯύΠϥଆͷ࡞ۀ • swiftccͷରԠ • 2019೥6݄൒͹͔Βߋ৽͞Εͯͳ͍ 5

  6. ։ൃ४උ • swiftwasm/swiftwasm-compile-service • https://swiftwasm.org ͷίϯύΠϧαʔϏε෦෼ • ࣮ࡍʹϦϯΫ͢ΔͨΊͷΦϒδΣΫτϑΝΠϧ͕ೖͬͯΔ ͷͰͦͷ··ར༻ •

    swiftwasm/swift • վ଄swift 6
  7. ίϯύΠϥΛ४උ $ mkdir swiftwasm-source $ cd swiftwasm-source $ sudo apt

    update $ sudo apt install git cmake ninja-build clang python uuid-dev libicu-dev icu-devtools \ libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev \ libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev \ systemtap-sdt-dev tzdata rsync $ wget -O wasisdk.deb "https://github.com/swiftwasm/wasi-sdk/releases/download/20190421.6/wasi-sdk_3.19gefb17cb478f9.m_amd64.deb" $ sudo dpkg -i wasisdk.deb $ wget -O icu.tar.xz "https://github.com/swiftwasm/icu4c-wasi/releases/download/20190421.3/icu4c-wasi.tar.xz" $ tar xf icu.tar.xz $ git clone git@github.com:swiftwasm/swiftwasm-compile-service.git$ && cd swiftwasm-compile-service $ ./downloadPrebuilts.sh $ ./unpackPrebuilts.sh $ cd ../ $ git clone git@github.com:swiftwasm/swift.git $ cd swift $ ./utils/update-checkout $ utils/build-script --debug --wasm \ --llvm-targets-to-build "X86;WebAssembly" \ --wasm-wasi-sdk "/opt/wasi-sdk" \ --wasm-icu-uc "todo" \ --wasm-icu-uc-include "$(pwd)/icu_out/include" \ --wasm-icu-i18n "todo" \ --wasm-icu-i18n-include "todo" \ --wasm-icu-data "todo" \ --build-swift-static-stdlib 7
  8. ϥϯλΠϜ΋४උ $ git clone --recurse-submodules git@github.com:CraneStation/wasmtime.git $ cd wasmtime $

    cargo build --release $ ./wasmtime/target/release/wasmtime --version 0.2.0 8
  9. ಈ͔ͯ͠ΈΔ $ cat ./hello.swift print("Hello world") 9

  10. ϏϧυεΫϦϓτ $SWIFTWASM_SOURCE/build/Ninja-DebugAssert/swift-linux-x86_64/bin/swiftc \ -target wasm32-unknown-unknown-wasm \ -sdk $WASM_SYSROOT \ -o

    $object_file -c $input $COMPILE_SERVICE/compiler/wasi-sdk/opt/wasi-sdk/bin/wasm-ld \ --error-limit=0 -o $output \ $WASM_SYSROOT/lib/wasm32-wasi/crt1.o \ $COMPILE_SERVICE/extra_objs/swift_start.o \ $COMPILE_SERVICE/compiler/opt/swiftwasm-sdk/lib/swift_static/wasm/wasm32/swiftrt.o \ $object_file \ -L $COMPILE_SERVICE/compiler/opt/swiftwasm-sdk/lib/swift_static/wasm \ -L $WASM_SYSROOT/lib/wasm32-wasi \ -L $COMPILE_SERVICE/compiler/icu_out/lib \ -lswiftCore \ -lc -lc++ -lc++abi -lswiftImageInspectionShared \ -licuuc -licudata \ $COMPILE_SERVICE/compiler/wasi-sdk/opt/wasi-sdk/lib/clang/8.0.0/lib/wasi/libclang_rt.builtins-wasm32.a \ $COMPILE_SERVICE/extra_objs/fakepthread.o \ $COMPILE_SERVICE/extra_objs/fakelocaltime.o \ $COMPILE_SERVICE/extra_objs/swift_end.o \ --no-gc-sections \ --no-threads 10
  11. $ SWIFTWASM_SOURCE=/home/katei/swiftwasm-source $ ./compile-swift-for-wasm.sh hello.swift hello.wasm $ wasmtime hello.wasm Hello

    world 11
  12. VTableΛࢀর͢ΔΑ͏ͳίʔυ΋ಈ͘ class Animal { func bark() {} } class Cat:

    Animal { override func bark() {} } @_optimize(none) func barkAnimal(_ animal: Animal) { animal.bark() } barkAnimal(Cat()) 12
  13. ໨ඪ swifterror෇͖ͷؔ਺ݺͼग़͠ͷαϙʔτ $ cat throws_subtyping.swift let f: () -> Void

    = {} let g: () throws -> Void = f try g() 13
  14. ͱΓ͋͑ͣಈ͔ͯ͠ΈΔ $ ./compile-swift-for-wasm.sh throws_subtyping.{swift,wasm} $ wasmtime throws_subtyping.wasm error: failed to

    process main module `throws_subtyping.wasm` caused by: Instantiation error: Trap occurred while invoking start function: wasm trap at 0x7f775103d251 14
  15. Calleeଆ LLVM IR define internal swiftcc void @"$s16throws_subtypingyycfU_"() #0 {

    entry: ret void } 15
  16. Callerଆ LLVM IR define i32 @main(i32, i8**) #0 { entry:

    %swifterror = alloca %swift.error*, align 4 store %swift.error* null, %swift.error** %swifterror, align 4 %2 = bitcast i8** %1 to i8* store i8* bitcast (void ()* @"$s16throws_subtypingyycfU_" to i8*), i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 store %swift.refcounted* null, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %3 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 %4 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %4) #1 store i8* %3, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 store %swift.refcounted* %4, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %6 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 %7 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %8 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %7) #1 %9 = bitcast i8* %6 to void (%swift.refcounted*, %swift.error**)* call swiftcc void %9(%swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror) ... } 16
  17. Callerଆ LLVM IR define i32 @main(i32, i8**) #0 { entry:

    %swifterror = alloca %swift.error*, align 4 store %swift.error* null, %swift.error** %swifterror, align 4 %2 = bitcast i8** %1 to i8* store i8* bitcast (void ()* @"$s16throws_subtypingyycfU_" to i8*), i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 store %swift.refcounted* null, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %3 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 %4 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %4) #1 store i8* %3, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 store %swift.refcounted* %4, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %6 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 %7 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %8 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %7) #1 %9 = bitcast i8* %6 to void (%swift.refcounted*, %swift.error**)* call swiftcc void %9(%swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror) ... } 16
  18. Callerଆ LLVM IR define i32 @main(i32, i8**) #0 { entry:

    %swifterror = alloca %swift.error*, align 4 store %swift.error* null, %swift.error** %swifterror, align 4 %2 = bitcast i8** %1 to i8* store i8* bitcast (void ()* @"$s16throws_subtypingyycfU_" to i8*), i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 store %swift.refcounted* null, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %3 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 %4 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %4) #1 store i8* %3, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 store %swift.refcounted* %4, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %6 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 %7 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %8 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %7) #1 %9 = bitcast i8* %6 to void (%swift.refcounted*, %swift.error**)* call swiftcc void %9(%swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror) ... } 16
  19. Callerଆ LLVM IR define i32 @main(i32, i8**) #0 { entry:

    %swifterror = alloca %swift.error*, align 4 store %swift.error* null, %swift.error** %swifterror, align 4 %2 = bitcast i8** %1 to i8* store i8* bitcast (void ()* @"$s16throws_subtypingyycfU_" to i8*), i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 store %swift.refcounted* null, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %3 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 %4 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %4) #1 store i8* %3, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 store %swift.refcounted* %4, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %6 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 %7 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %8 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %7) #1 %9 = bitcast i8* %6 to void (%swift.refcounted*, %swift.error**)* call swiftcc void %9(%swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror) ... } 16
  20. Callerଆ LLVM IR define i32 @main(i32, i8**) #0 { entry:

    %swifterror = alloca %swift.error*, align 4 store %swift.error* null, %swift.error** %swifterror, align 4 %2 = bitcast i8** %1 to i8* store i8* bitcast (void ()* @"$s16throws_subtypingyycfU_" to i8*), i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 store %swift.refcounted* null, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %3 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 %4 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %4) #1 store i8* %3, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 store %swift.refcounted* %4, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %6 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 %7 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %8 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %7) #1 %9 = bitcast i8* %6 to void (%swift.refcounted*, %swift.error**)* call swiftcc void %9(%swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror) ... } 16
  21. Callerଆ LLVM IR define i32 @main(i32, i8**) #0 { entry:

    %swifterror = alloca %swift.error*, align 4 store %swift.error* null, %swift.error** %swifterror, align 4 %2 = bitcast i8** %1 to i8* store i8* bitcast (void ()* @"$s16throws_subtypingyycfU_" to i8*), i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 store %swift.refcounted* null, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %3 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 %4 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %4) #1 store i8* %3, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 store %swift.refcounted* %4, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %6 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 %7 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %8 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %7) #1 %9 = bitcast i8* %6 to void (%swift.refcounted*, %swift.error**)* call swiftcc void %9(%swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror) ... } 16
  22. Callerଆ LLVM IR define i32 @main(i32, i8**) #0 { entry:

    %swifterror = alloca %swift.error*, align 4 store %swift.error* null, %swift.error** %swifterror, align 4 %2 = bitcast i8** %1 to i8* store i8* bitcast (void ()* @"$s16throws_subtypingyycfU_" to i8*), i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 store %swift.refcounted* null, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %3 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 0), align 4 %4 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1fyycvp", i32 0, i32 1), align 4 %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %4) #1 store i8* %3, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 store %swift.refcounted* %4, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %6 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 0), align 4 %7 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s16throws_subtyping1gyyKcvp", i32 0, i32 1), align 4 %8 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %7) #1 %9 = bitcast i8* %6 to void (%swift.refcounted*, %swift.error**)* call swiftcc void %9(%swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror) ... } 16
  23. ϥϯλΠϜදݱ (Swift෩) typealias NonThrowableFunc = () -> Void typealias ThrowableFunc

    = (inout Error) -> Void let f: NonThrowableFunc = {} let g: ThrowableFunc = f var error: Error try g(&error) 17
  24. LLVM IR define internal swiftcc void @"$s16throws_subtyping4mainyyFyycfU_"() #0 { entry:

    ret void } %1 = bitcast void ()* @"$s16throws_subtyping4mainyyFyycfU_" to void (%swift.refcounted*, %swift.error**)* call swiftcc void %1( %swift.refcounted* swiftself %2, %swift.error** noalias nocapture dereferenceable(4) %swifterror ) 18
  25. • swifterrorͱswiftself͸ελοΫͰ͸ͳ͘ϨδελΛ௨͡ ͯ౉͞ΕΔɻ • ͜ΕʹΑͬͯswifterror΍swiftself͕ແ͍ؔ਺͸୯ʹϨδ ελʹೖ͍ͬͯΔ஋Λແࢹ͢Δ͚ͩͰɺΦʔόʔϔουແ͠ ʹthrowsͳؔ਺ͱ࣮ͯ͠ߦͰ͖Δɻ • ͔͠͠ɺWASMʹ͸Ϩδελ͕ແ͍ͷͰελοΫʹੵ·͟Δ Λಘͳ͍ɻ͞ΒʹɺWASM͸ελοΫʹੵ·ΕͨҾ਺ͷ਺Λ

    ϥϯλΠϜʹνΣοΫ͢ΔͷͰΫϥογϡͯ͠͠·͏ɻ 19
  26. ͭ·Γ LLVM IRͷ࣌఺ͰҾ਺ͷ਺͕callerͱcalleeͰҰக͍ͯ͠Δඞཁ͕ ͋Δ 20

  27. swiftccରԠʹඞཁͳ࡞ۀ • callerɺcalleeʹৗʹswifterrorͱswiftselfΛ͚ͭΔ • Joe GroffͷఏҊͨ͠ํ๏ ·ͨ͸ • ܕڧ੍ͷSIL InstructionΛάϧʔίʔυʹม׵ͯ͠Ҿ਺ͷ਺Λ

    ߹ΘͤΔ • ࣮૷͍ͯ͠Δ్தͰؾ͍ͮͨํ๏ 21
  28. callerɺcalleeʹৗʹswifterrorͱswiftselfΛ͚ͭΔ define internal swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself, %swift.error** noalias

    nocapture swifterror dereferenceable(4) ) call swiftcc void %9( %swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror ) 22
  29. Pros • ੜ੒͞ΕΔίʔυྔ͸ຆͲมΘΒͳ͍ Cons • มߋՕॴ͕ෆ໌ྎ • callerͱcalleeͷ྆ํͷੜ੒෦෼Λมߋ͢Δඞཁ͕͋Δ 23

  30. ࣮૷ void SignatureExpansion::expandParameters() { ... auto needsContext = [=]() ->

    bool { + if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) return true; switch (FnType->getRepresentation()) { case SILFunctionType::Representation::Block: llvm_unreachable("adding block parameter in Swift CC expansion?"); // Always leave space for a context argument if we have an error result. case SILFunctionType::Representation::CFunctionPointer: case SILFunctionType::Representation::Method: case SILFunctionType::Representation::WitnessMethod: case SILFunctionType::Representation::ObjCMethod: case SILFunctionType::Representation::Thin: case SILFunctionType::Representation::Closure: return FnType->hasErrorResult(); case SILFunctionType::Representation::Thick: return true; } llvm_unreachable("bad representation kind"); }; if (needsContext()) { if (claimSelf()) IGM.addSwiftSelfAttributes(Attrs, ParamIRTypes.size()); ParamIRTypes.push_back(IGM.RefCountedPtrTy); } // ଓ͘-> ... } lib/IRGen/GenCall.cpp 24
  31. void SignatureExpansion::expandParameters() { ... if (FnType->hasErrorResult()) { if (claimError()) IGM.addSwiftErrorAttributes(Attrs,

    ParamIRTypes.size()); llvm::Type *errorType = IGM.getStorageType( getSILFuncConventions().getSILType(FnType->getErrorResult())); ParamIRTypes.push_back(errorType->getPointerTo()); + } else if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { + if (claimError()) + IGM.addSwiftErrorAttributes(Attrs, ParamIRTypes.size()); + SILType exnType = SILType::getExceptionType(IGM.Context); + assert(exnType.isObject()); + auto errorResult = SILResultInfo(exnType.getASTType(), + ResultConvention::Owned); + llvm::Type *errorType = IGM.getStorageType( + getSILFuncConventions().getSILType(errorResult)); + ParamIRTypes.push_back(errorType->getPointerTo()); + } ... } lib/IRGen/GenCall.cpp 25
  32. hasErrorResult͕false͔ͭswifterrorҾ਺͕౉ͬͯ͘Δɺͱ͍ ͏ࠓ·Ͱߟྀ͞Ε͍ͯͳ͍έʔε͕ൃੜ͢ΔͷͰassertʹҾ͔ͬ ͔Γ·͘ΔɻͦΕͧΕద੾ʹճආ͢Δɻ(͜Ε͕େม) • lib/IRGen/GenCall.cpp • calleeଆ • lib/IRGen/IRGenSIL.cpp •

    callerଆ 26
  33. ࡞ۀϒϥϯν https://github.com/swiftwasm/swift/compare/ swiftwasm...kateinoigakukun:katei/swifterror assertʹҾ͔͔ͬΔέʔε͕͍͔ͭ͘࢒͍ͬͯͯɺ·ͩstdlibΛ ίϯύΠϧͰ͖ͯͳ͍ 27

  34. ܕڧ੍ͷSIL InstructionΛάϧʔίʔυʹม׵ͯ͠Ҿ਺ͷ਺Λ ߹ΘͤΔ ͜Ε͸ߏ૝ஈ֊ 28

  35. ܕڧ੍ͷSIL InstructionΛάϧʔίʔυʹม׵ͯ͠Ҿ਺ͷ਺Λ ߹ΘͤΔ define internal swiftcc void @"$s16throws_subtypingyycfU_"() define internal

    swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself ) { entry: call swiftcc void @"$s16throws_subtypingyycfU_"() } define internal swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself, %swift.error** noalias nocapture swifterror dereferenceable(4) ) { entry: call swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself %0, ) } call swiftcc void %9( %swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror ) 29
  36. Pros • طଘͷܕڧ੍ͷ࢓૊Έʹ৐ͤΔ͚ͩͰࡁΉ Cons • άϧʔίʔυ͕૿͑Δ 30

  37. ܕڧ੍ͱ͸ 31

  38. ཧ࿦͔Βೖ໳͢Δswift/lib/Sema - Θ͍Θ͍swiftc #1 by @ukitaka 32

  39. $ cat sources/throws_subtyping.swift let f: () -> Void = {}

    let g: () throws -> Void = f 33
  40. $ swiftc -emit-sil sources/throws_subtyping.swift // main sil @main : $@convention(c)

    (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): alloc_global @$s16throws_subtyping1fyycvp // id: %2 %3 = global_addr @$s16throws_subtyping1fyycvp : $*@callee_guaranteed () -> () // users: %9, %6 // function_ref closure #1 in %4 = function_ref @$s16throws_subtypingyycfU_ : $@convention(thin) () -> () // user: %5 %5 = thin_to_thick_function %4 : $@convention(thin) () -> () to $@callee_guaranteed () -> () // user: %6 store %5 to %3 : $*@callee_guaranteed () -> () // id: %6 alloc_global @$s16throws_subtyping1gyyKcvp // id: %7 %8 = global_addr @$s16throws_subtyping1gyyKcvp : $*@callee_guaranteed () -> @error Error // users: %13, %12 %9 = load %3 : $*@callee_guaranteed () -> () // users: %11, %10 strong_retain %9 : $@callee_guaranteed () -> () // id: %10 %11 = convert_function %9 : $@callee_guaranteed () -> () to $@callee_guaranteed () -> @error Error // user: %12 store %11 to %8 : $*@callee_guaranteed () -> @error Error // id: %12 %13 = load %8 : $*@callee_guaranteed () -> @error Error // users: %22, %17, %15, %14 strong_retain %13 : $@callee_guaranteed () -> @error Error // id: %14 try_apply %13() : $@callee_guaranteed () -> @error Error, normal bb1, error bb2 // id: %15 34
  41. $ swiftc -emit-sil sources/throws_subtyping.swift // main sil @main : $@convention(c)

    (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): alloc_global @$s16throws_subtyping1fyycvp // id: %2 %3 = global_addr @$s16throws_subtyping1fyycvp : $*@callee_guaranteed () -> () // users: %9, %6 // function_ref closure #1 in %4 = function_ref @$s16throws_subtypingyycfU_ : $@convention(thin) () -> () // user: %5 %5 = thin_to_thick_function %4 : $@convention(thin) () -> () to $@callee_guaranteed () -> () // user: %6 store %5 to %3 : $*@callee_guaranteed () -> () // id: %6 alloc_global @$s16throws_subtyping1gyyKcvp // id: %7 %8 = global_addr @$s16throws_subtyping1gyyKcvp : $*@callee_guaranteed () -> @error Error // users: %13, %12 %9 = load %3 : $*@callee_guaranteed () -> () // users: %11, %10 strong_retain %9 : $@callee_guaranteed () -> () // id: %10 %11 = convert_function %9 : $@callee_guaranteed () -> () to $@callee_guaranteed () -> @error Error // user: %12 store %11 to %8 : $*@callee_guaranteed () -> @error Error // id: %12 %13 = load %8 : $*@callee_guaranteed () -> @error Error // users: %22, %17, %15, %14 strong_retain %13 : $@callee_guaranteed () -> @error Error // id: %14 try_apply %13() : $@callee_guaranteed () -> @error Error, normal bb1, error bb2 // id: %15 34
  42. $ swiftc -emit-sil sources/throws_subtyping.swift // main sil @main : $@convention(c)

    (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): alloc_global @$s16throws_subtyping1fyycvp // id: %2 %3 = global_addr @$s16throws_subtyping1fyycvp : $*@callee_guaranteed () -> () // users: %9, %6 // function_ref closure #1 in %4 = function_ref @$s16throws_subtypingyycfU_ : $@convention(thin) () -> () // user: %5 %5 = thin_to_thick_function %4 : $@convention(thin) () -> () to $@callee_guaranteed () -> () // user: %6 store %5 to %3 : $*@callee_guaranteed () -> () // id: %6 alloc_global @$s16throws_subtyping1gyyKcvp // id: %7 %8 = global_addr @$s16throws_subtyping1gyyKcvp : $*@callee_guaranteed () -> @error Error // users: %13, %12 %9 = load %3 : $*@callee_guaranteed () -> () // users: %11, %10 strong_retain %9 : $@callee_guaranteed () -> () // id: %10 %11 = convert_function %9 : $@callee_guaranteed () -> () to $@callee_guaranteed () -> @error Error // user: %12 store %11 to %8 : $*@callee_guaranteed () -> @error Error // id: %12 %13 = load %8 : $*@callee_guaranteed () -> @error Error // users: %22, %17, %15, %14 strong_retain %13 : $@callee_guaranteed () -> @error Error // id: %14 try_apply %13() : $@callee_guaranteed () -> @error Error, normal bb1, error bb2 // id: %15 34
  43. thin_to_thick_function thinͳؔ਺Λthickͳؔ਺ͱͯ͠ѻ͑ΔΑ͏ʹ໌ࣔతʹ ؔ਺ϙΠϯλΛؔ਺ϙΠϯλͱۭͷίϯςΩετͷϖΞʹม׵ ͢Δɻ • thin • ίϯςΩετΛ࣋ͨͳ͍ؔ਺ • thick

    • ΩϟϓνϟͷίϯςΩετΛ࣋ͭؔ਺ 35
  44. x86_64্Ͱ͸thinͳؔ਺ͱthickͳؔ਺͸ABI compatibleͳͷ Ͱؔ਺ϙΠϯλʹରͯ͠͸Կ΋ૢ࡞͠ͳ͍ɻ WASM্Ͱ͸not ABI compatibleͳͷͰάϧʔίʔυΛૠೖ͢ Δɻ 36

  45. Ωϟϓνϟ͕ແ͍ͷʹthickʁ let f: () -> Void = {} let g:

    () throws -> Void = f throwsͳؔ਺͸ඞͣίϯςΩετΛ࣋ͭΑ͏ʹ࣮૷͞Ε͍ͯ Δɻ υΩϡϝϯτΛړ͕ͬͨཧ༝͸Θ͔Βͳ͔ͬͨ 37
  46. $ swiftc -emit-sil sources/throws_subtyping.swift // main sil @main : $@convention(c)

    (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): alloc_global @$s16throws_subtyping1fyycvp // id: %2 %3 = global_addr @$s16throws_subtyping1fyycvp : $*@callee_guaranteed () -> () // users: %9, %6 // function_ref closure #1 in %4 = function_ref @$s16throws_subtypingyycfU_ : $@convention(thin) () -> () // user: %5 %5 = thin_to_thick_function %4 : $@convention(thin) () -> () to $@callee_guaranteed () -> () // user: %6 store %5 to %3 : $*@callee_guaranteed () -> () // id: %6 alloc_global @$s16throws_subtyping1gyyKcvp // id: %7 %8 = global_addr @$s16throws_subtyping1gyyKcvp : $*@callee_guaranteed () -> @error Error // users: %13, %12 %9 = load %3 : $*@callee_guaranteed () -> () // users: %11, %10 strong_retain %9 : $@callee_guaranteed () -> () // id: %10 %11 = convert_function %9 : $@callee_guaranteed () -> () to $@callee_guaranteed () -> @error Error // user: %12 store %11 to %8 : $*@callee_guaranteed () -> @error Error // id: %12 %13 = load %8 : $*@callee_guaranteed () -> @error Error // users: %22, %17, %15, %14 strong_retain %13 : $@callee_guaranteed () -> @error Error // id: %14 try_apply %13() : $@callee_guaranteed () -> @error Error, normal bb1, error bb2 // id: %15 38
  47. convert_function $T -> U to $T' -> U'ͷม׵Λߦ͏ جຊతʹABI compatibleͳΠϯλʔϑΣʔεͷม׵͔͠ߦΘͳ

    ͍ɻ ABI compatible͕ނɺIRGenͰ͸ಛผͳ͜ͱ͸ͤͣʹ$T -> Uͱ ͯ͠ग़ྗ͢Δ 39
  48. convert_function ͜͜ʹ$T -> U to $T' throws -> U'ͷม׵΋ؚ·ΕΔɻ x86_64Ͱ͸ABI

    compatible͕ͩWASMͰ͸not ABI compatible ͳͷͰάϧʔίʔυΛૠೖ͢Δɻ 40
  49. ੜ੒͞ΕΔ(͸ͣͷ) LLVM IR (࠶ܝ) define internal swiftcc void @"$s16throws_subtypingyycfU_"() define

    internal swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself ) { entry: call swiftcc void @"$s16throws_subtypingyycfU_"() } define internal swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself, %swift.error** noalias nocapture swifterror dereferenceable(4) ) { entry: call swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself %0, ) } call swiftcc void %9( %swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror ) 41
  50. ੜ੒͞ΕΔ(͸ͣͷ) LLVM IR (࠶ܝ) define internal swiftcc void @"$s16throws_subtypingyycfU_"() define

    internal swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself ) { entry: call swiftcc void @"$s16throws_subtypingyycfU_"() } define internal swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself, %swift.error** noalias nocapture swifterror dereferenceable(4) ) { entry: call swiftcc void @"$s16throws_subtypingyycfU_"( %swift.refcounted* swiftself %0, ) } call swiftcc void %9( %swift.refcounted* swiftself %7, %swift.error** noalias nocapture dereferenceable(4) %swifterror ) 41
  51. ࣮૷ void IRGenSILFunction::visitThinToThickFunctionInst( swift::ThinToThickFunctionInst *i) { // TODO: WASMλʔήοτͳΒάϧʔίʔυੜ੒ͯ͠ݺͼग़͢ //

    Take the incoming function pointer and add a null context pointer to it. Explosion from = getLoweredExplosion(i->getOperand()); Explosion to; to.add(from.claimNext()); if (i->getType().castTo<SILFunctionType>()->isNoEscape()) to.add(llvm::ConstantPointerNull::get(IGM.OpaquePtrTy)); else to.add(IGM.RefCountedNull); setLoweredExplosion(i, to); } lib/IRGen/IRGenSIL.cpp#L4727-L4738 42
  52. ࣮૷ void IRGenSILFunction::visitConvertFunctionInst(swift::ConvertFunctionInst *i) { // TODO: WASMλʔήοτͳΒάϧʔίʔυੜ੒ͯ͠ݺͼग़͢ // This

    instruction is specified to be a no-op. Explosion temp = getLoweredExplosion(i->getOperand()); setLoweredExplosion(i, temp); } lib/IRGen/IRGenSIL.cpp#L4442-L4446 43
  53. ଞͷྑ͍ΞΠσΟΞืूͯ͠·͢ 44

  54. ཧ૝ͷґଘؔ܎ Swift͕ΞʔΩςΫνϟͷ஌ࣝΛ࣋ͨͳͯ͘ྑ͍ܗ͕ཧ૝ 45

  55. ݱ࣮ͷґଘؔ܎ LLVM IR͸ΞʔΩςΫνϟඇґଘ͕ͩLLVM IRʹม׵͢Δաఔ͕ ΞʔΩςΫνϟʹґଘͯ͠Δ 46