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

SwiftのWASM対応 in practice

Avatar for Yuta Saito Yuta Saito
September 13, 2019

SwiftのWASM対応 in practice

Avatar for Yuta Saito

Yuta Saito

September 13, 2019
Tweet

More Decks by Yuta Saito

Other Decks in Programming

Transcript

  1. 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
  2. ίϯύΠϥΛ४උ $ 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 [email protected]:swiftwasm/swiftwasm-compile-service.git$ && cd swiftwasm-compile-service $ ./downloadPrebuilts.sh $ ./unpackPrebuilts.sh $ cd ../ $ git clone [email protected]: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
  3. ϥϯλΠϜ΋४උ $ git clone --recurse-submodules [email protected]:CraneStation/wasmtime.git $ cd wasmtime $

    cargo build --release $ ./wasmtime/target/release/wasmtime --version 0.2.0 8
  4. ϏϧυεΫϦϓτ $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
  5. VTableΛࢀর͢ΔΑ͏ͳίʔυ΋ಈ͘ class Animal { func bark() {} } class Cat:

    Animal { override func bark() {} } @_optimize(none) func barkAnimal(_ animal: Animal) { animal.bark() } barkAnimal(Cat()) 12
  6. ͱΓ͋͑ͣಈ͔ͯ͠ΈΔ $ ./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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. ϥϯλΠϜදݱ (Swift෩) typealias NonThrowableFunc = () -> Void typealias ThrowableFunc

    = (inout Error) -> Void let f: NonThrowableFunc = {} let g: ThrowableFunc = f var error: Error try g(&error) 17
  15. 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
  16. 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
  17. ࣮૷ 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
  18. 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
  19. ܕڧ੍ͷ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
  20. $ 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
  21. $ 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
  22. $ 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
  23. Ωϟϓνϟ͕ແ͍ͷʹthickʁ let f: () -> Void = {} let g:

    () throws -> Void = f throwsͳؔ਺͸ඞͣίϯςΩετΛ࣋ͭΑ͏ʹ࣮૷͞Ε͍ͯ Δɻ υΩϡϝϯτΛړ͕ͬͨཧ༝͸Θ͔Βͳ͔ͬͨ 37
  24. $ 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
  25. convert_function $T -> U to $T' -> U'ͷม׵Λߦ͏ جຊతʹABI compatibleͳΠϯλʔϑΣʔεͷม׵͔͠ߦΘͳ

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

    compatible͕ͩWASMͰ͸not ABI compatible ͳͷͰάϧʔίʔυΛૠೖ͢Δɻ 40
  27. ੜ੒͞ΕΔ(͸ͣͷ) 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
  28. ੜ੒͞ΕΔ(͸ͣͷ) 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
  29. ࣮૷ 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
  30. ࣮૷ 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