Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

࢒ΓͷίϯύΠϥଆͷ࡞ۀ • swiftccͷରԠ • 2019೥6݄൒͹͔Βߋ৽͞Εͯͳ͍ 5

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

ίϯύΠϥΛ४උ $ 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

Slide 8

Slide 8 text

ϥϯλΠϜ΋४උ $ git clone --recurse-submodules git@github.com:CraneStation/wasmtime.git $ cd wasmtime $ cargo build --release $ ./wasmtime/target/release/wasmtime --version 0.2.0 8

Slide 9

Slide 9 text

ಈ͔ͯ͠ΈΔ $ cat ./hello.swift print("Hello world") 9

Slide 10

Slide 10 text

ϏϧυεΫϦϓτ $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

Slide 11

Slide 11 text

$ SWIFTWASM_SOURCE=/home/katei/swiftwasm-source $ ./compile-swift-for-wasm.sh hello.swift hello.wasm $ wasmtime hello.wasm Hello world 11

Slide 12

Slide 12 text

VTableΛࢀর͢ΔΑ͏ͳίʔυ΋ಈ͘ class Animal { func bark() {} } class Cat: Animal { override func bark() {} } @_optimize(none) func barkAnimal(_ animal: Animal) { animal.bark() } barkAnimal(Cat()) 12

Slide 13

Slide 13 text

໨ඪ swifterror෇͖ͷؔ਺ݺͼग़͠ͷαϙʔτ $ cat throws_subtyping.swift let f: () -> Void = {} let g: () throws -> Void = f try g() 13

Slide 14

Slide 14 text

ͱΓ͋͑ͣಈ͔ͯ͠ΈΔ $ ./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

Slide 15

Slide 15 text

Calleeଆ LLVM IR define internal swiftcc void @"$s16throws_subtypingyycfU_"() #0 { entry: ret void } 15

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

ϥϯλΠϜදݱ (Swift෩) typealias NonThrowableFunc = () -> Void typealias ThrowableFunc = (inout Error) -> Void let f: NonThrowableFunc = {} let g: ThrowableFunc = f var error: Error try g(&error) 17

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

• swifterrorͱswiftself͸ελοΫͰ͸ͳ͘ϨδελΛ௨͡ ͯ౉͞ΕΔɻ • ͜ΕʹΑͬͯswifterror΍swiftself͕ແ͍ؔ਺͸୯ʹϨδ ελʹೖ͍ͬͯΔ஋Λແࢹ͢Δ͚ͩͰɺΦʔόʔϔουແ͠ ʹthrowsͳؔ਺ͱ࣮ͯ͠ߦͰ͖Δɻ • ͔͠͠ɺWASMʹ͸Ϩδελ͕ແ͍ͷͰελοΫʹੵ·͟Δ Λಘͳ͍ɻ͞ΒʹɺWASM͸ελοΫʹੵ·ΕͨҾ਺ͷ਺Λ ϥϯλΠϜʹνΣοΫ͢ΔͷͰΫϥογϡͯ͠͠·͏ɻ 19

Slide 26

Slide 26 text

ͭ·Γ LLVM IRͷ࣌఺ͰҾ਺ͷ਺͕callerͱcalleeͰҰக͍ͯ͠Δඞཁ͕ ͋Δ 20

Slide 27

Slide 27 text

swiftccରԠʹඞཁͳ࡞ۀ • callerɺcalleeʹৗʹswifterrorͱswiftselfΛ͚ͭΔ • Joe GroffͷఏҊͨ͠ํ๏ ·ͨ͸ • ܕڧ੍ͷSIL InstructionΛάϧʔίʔυʹม׵ͯ͠Ҿ਺ͷ਺Λ ߹ΘͤΔ • ࣮૷͍ͯ͠Δ్தͰؾ͍ͮͨํ๏ 21

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Pros • ੜ੒͞ΕΔίʔυྔ͸ຆͲมΘΒͳ͍ Cons • มߋՕॴ͕ෆ໌ྎ • callerͱcalleeͷ྆ํͷੜ੒෦෼Λมߋ͢Δඞཁ͕͋Δ 23

Slide 30

Slide 30 text

࣮૷ 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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

hasErrorResult͕false͔ͭswifterrorҾ਺͕౉ͬͯ͘Δɺͱ͍ ͏ࠓ·Ͱߟྀ͞Ε͍ͯͳ͍έʔε͕ൃੜ͢ΔͷͰassertʹҾ͔ͬ ͔Γ·͘ΔɻͦΕͧΕద੾ʹճආ͢Δɻ(͜Ε͕େม) • lib/IRGen/GenCall.cpp • calleeଆ • lib/IRGen/IRGenSIL.cpp • callerଆ 26

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

ܕڧ੍ͷ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

Slide 36

Slide 36 text

Pros • طଘͷܕڧ੍ͷ࢓૊Έʹ৐ͤΔ͚ͩͰࡁΉ Cons • άϧʔίʔυ͕૿͑Δ 30

Slide 37

Slide 37 text

ܕڧ੍ͱ͸ 31

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

$ swiftc -emit-sil sources/throws_subtyping.swift // main sil @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>): 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

Slide 41

Slide 41 text

$ swiftc -emit-sil sources/throws_subtyping.swift // main sil @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>): 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

Slide 42

Slide 42 text

$ swiftc -emit-sil sources/throws_subtyping.swift // main sil @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>): 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

Slide 43

Slide 43 text

thin_to_thick_function thinͳؔ਺Λthickͳؔ਺ͱͯ͠ѻ͑ΔΑ͏ʹ໌ࣔతʹ ؔ਺ϙΠϯλΛؔ਺ϙΠϯλͱۭͷίϯςΩετͷϖΞʹม׵ ͢Δɻ • thin • ίϯςΩετΛ࣋ͨͳ͍ؔ਺ • thick • ΩϟϓνϟͷίϯςΩετΛ࣋ͭؔ਺ 35

Slide 44

Slide 44 text

x86_64্Ͱ͸thinͳؔ਺ͱthickͳؔ਺͸ABI compatibleͳͷ Ͱؔ਺ϙΠϯλʹରͯ͠͸Կ΋ૢ࡞͠ͳ͍ɻ WASM্Ͱ͸not ABI compatibleͳͷͰάϧʔίʔυΛૠೖ͢ Δɻ 36

Slide 45

Slide 45 text

Ωϟϓνϟ͕ແ͍ͷʹthickʁ let f: () -> Void = {} let g: () throws -> Void = f throwsͳؔ਺͸ඞͣίϯςΩετΛ࣋ͭΑ͏ʹ࣮૷͞Ε͍ͯ Δɻ υΩϡϝϯτΛړ͕ͬͨཧ༝͸Θ͔Βͳ͔ͬͨ 37

Slide 46

Slide 46 text

$ swiftc -emit-sil sources/throws_subtyping.swift // main sil @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>): 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

Slide 47

Slide 47 text

convert_function $T -> U to $T' -> U'ͷม׵Λߦ͏ جຊతʹABI compatibleͳΠϯλʔϑΣʔεͷม׵͔͠ߦΘͳ ͍ɻ ABI compatible͕ނɺIRGenͰ͸ಛผͳ͜ͱ͸ͤͣʹ$T -> Uͱ ͯ͠ग़ྗ͢Δ 39

Slide 48

Slide 48 text

convert_function ͜͜ʹ$T -> U to $T' throws -> U'ͷม׵΋ؚ·ΕΔɻ x86_64Ͱ͸ABI compatible͕ͩWASMͰ͸not ABI compatible ͳͷͰάϧʔίʔυΛૠೖ͢Δɻ 40

Slide 49

Slide 49 text

ੜ੒͞ΕΔ(͸ͣͷ) 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

Slide 50

Slide 50 text

ੜ੒͞ΕΔ(͸ͣͷ) 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

Slide 51

Slide 51 text

࣮૷ 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()->isNoEscape()) to.add(llvm::ConstantPointerNull::get(IGM.OpaquePtrTy)); else to.add(IGM.RefCountedNull); setLoweredExplosion(i, to); } lib/IRGen/IRGenSIL.cpp#L4727-L4738 42

Slide 52

Slide 52 text

࣮૷ 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

Slide 53

Slide 53 text

ଞͷྑ͍ΞΠσΟΞืूͯ͠·͢ 44

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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