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

SwiftのWASM対応 in practice

Yuta Saito
September 13, 2019

SwiftのWASM対応 in practice

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