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

Swift Actor 實作探索

Swift Actor 實作探索

coscup 2021

3f7d9611fc919c98512b779cde637dfc?s=128

Johnlin

July 16, 2021
Tweet

Transcript

  1. Swift Actor መ࡞୳ࡧ John Lin (@johnlinvc)

  2. ᮫ԙզ • John Lin • Twitter: @johnlinvc • Senior Solution

    Architect, DevOps 
 @ West Pharmaceutical Service (୆ᖯҖ๏෰຿) • Swift Taipei meetup ओ㭎ਓ
  3. Swift Taipei Meetup • https://swift.taipei • 㑌݄ୈҰݸᜌ፨ೋᎯ㭎ɻ • ౼࿦ Swift

    ૬᮫తࢿ㘤ɼ৽஌ɼመ࡞౳౳ɻ • ݱ৔༗ఏڙ᫊৯࿨ञਫ਼ᢛඇञਫ਼ҿྉɻ • ᓣܴိ٣׃⇭ᡅɻ
  4. େߝ • Actor model • Swift actor • Swift actor

    መ຿ൣྫ • Swift ฤᩄྲྀఔ • Swift actor ฤᩄྲྀఔ
  5. Actor model • Actor: ԋһ • model: ໛ܕɼయൣɻ

  6. ֌٢ཁࡏ৽ిӨཫԋ֌٢

  7. Actor model • Ұݸ༻ိ႔ཧฒߦӡࢉతఔࣜ໛ܕ • 1973 ೥༝ Carl Hewitt, Peter

    Bishop & Richard Steiger ఏग़ɻ • ༝ၷେ෦෼૊੒ Actor & message • ෆधཁ೚Կಛผత async featureɼ
 ՄҎࡏၚ౷త blocking ؀ڥதመ࡞ɻ
  8. Actor • ఔࣜӡࢉతᄸݩɻ༗ࣗݾᘐཱతهԱᱪ࿨ӡࢉೳྗɻ • ༗ᘐಛత໊ࢠʢ஍ᅿʣ • ՄҎ၏Լ໘ز݅ࣄɻ • ઀Ꮕ㘤ଉ •

    㗞ੜ৽త actorɻ • ૹ㘤ଉڅଖଞ actorɻ • վᏓࣗݾతهԱᱪʢվᏓߦҝʣ
  9. Message • Actor ೭ؒޓ૬ߏ௨తػ੍ɻ • Actor ՄҎૹmessageڅଖଞత actorɻ • ୠੋ୞ೳᏅࣗݾత

    messageɻ • Obj-C message send ༗ 87% ૾
  10. actor model ӡ࡞

  11. Swift

  12. Swift

  13. Swift • 2011 ೥༝ LLVM ࡞ऀ Chris Lattner ։ᚙత৽ੈ୅ఔࣜޠݴ •

    2015 ೥։ݯɼओཁߩᘔऀҝ Apple • ࢧԉ Linux, macOS, iOS & Windowsɻ • ࠷৽൛ຊҝ 5.5ɻ
  14. Swift ಛ৭ • Objective-C without C • ಉ࣌ࢧԉ OOP &

    FPɻ • ࢧԉ Value Type & Reference Typeɻ • ABI stableɼ޲ԼࢧԉલҰ൛తޠ๏ɻ • Generic, Protocol ɻ • 㚎ݐ Package managerɻ
  15. Swift Async / Await • Swift 5.5 త৽ޭೳ func fetch()

    async -> Int {...} let x = await fetch() async let y = fetch() await y
  16. Swift Actor • SE-0306 Actors መ࡞ྃ Actorɻୠੋ࿨ Actor model ฒෆ׬શ૬ಉɻ

    • ༻ىိ૾ੋ㚎ݐྃ mutex త classɻॴ༗త var/method ౎ඃ mutex อޢɻ actor Counter { 
 var count:Int = 0 
 func inc() async { 
 self.count += 1 
 } 
 }
  17. Swift actor message passing • ᔒ༗ message passingɼ୞༗ typed async

    method callɻ • ୞༗ࡏࣗݾతmethod ཫ࠽ೳ௚઀मվ varɻࡏଖଞ஍ํधཁ࢖༻ async/ awaitɻ actor Counter { 
 var count:Int = 0 
 func inc() async { 
 self.count += 1 
 } 
 }
  18. Swift Actor vs Actor model Local Value Message passing Mailbox

    Reply Swift Yes Static, Compiler invoke methods No, compiler invoke methods Automatic, Typed Classic Actor Yes Dynamic Send anything Yes Manual, Need to know sender
  19. Swift Actor መ຿ൣྫ • iOS 15 UIKit Framework ࢖༻ actor

    ိආ໔ࡏଖଞ thread मվ UI private func loadUser() { async { do { let user = try await loader.loadUser() nameLabel.text = user.name biographyLabel.text = user.biography } catch { showError(error) } } }
  20. ಹኄੋዎኄ၏ग़ိత䏆ʁ

  21. Swift ฤᩄྲྀఔ Lexer / Parser Semantic analysis SIL generation SIL

    guaranteed transformations SIL Optimizations LLVM IR Generation LLVM Source Code AST AST SIL SIL SIL LLVM IR
  22. Lexer / Parser • ሡ७จࣈతఔࣜᛰ᫚׵੒ந৅ޠ๏थ(AST, abstract syntax tree)ɻ • ෛ੹ᒾҰࣈ໘্తޠ๏ੋ൱ਖ਼֬ɻ

  23. Semantic analysis • ෼ੳޠ๏थɻ • ᒾҰྨผੋ൱ਖ਼֬ɻ • ॏഉӡࢉࢠ༏ઌᒟɻ • 㢨ఔࣜิ্༬ઃతመ࡞ɻ

  24. SIL generation • ሡޠ๏थ᫚׵੒ SIL ( Swift Intermediate Language )ɻ

    • SIL ੋ SSA Form త Platform agnostic IRɻሢҝ Swift ઃܭతɻ • ༗Ұࠣ࠷ՂԽࡏ IR ൺ Tree ޷၏ɻॴҎ༗ྃ SILɻ
  25. SIL guaranteed transformations • ਐߦҰࠣඞཁత IR ᫚׵ɻෆ؅༗ᔒ༗։࠷ՂԽ (-O) ౎။䋯 •

    return analysis • memory promotion
  26. SIL Optimizations • ਐߦ IR త࠷ՂԽɻ᮫ᎃ࠷ՂԽ (-Onone) త࿩ब။௓ա • Inline,

    Specialization, Devirtualization ౳౳ɻ
  27. LLVM IR Generation • ೺ SIL ᫚׵੒ LLVM IR (Intermediate

    Representationɼதհදࣔ)ɻ
  28. Actor ฤᩄྲྀఔ Lexer / Parser Semantic analysis SIL generation SIL

    guaranteed transformations SIL Optimizations LLVM IR Generation LLVM Source Code AST AST SIL SIL SIL LLVM IR
  29. Swift Actor ൣྫ actor Counter { 
 var count:Int =

    0 
 func inc() async { 
 self.count += 1 
 } 
 }
  30. ၷେॏᴍ • Async : ೗Կ֬อಉ࣌୞။༗Ұݸ actor method ӡߦɻ • State

    Isolation : ೗Կ֬อᏓᏐෆ။ඃଖଞ஍ํଘऔɻ
  31. Lexer / Parser • መࡍ্ੋᙛ੒ class ိ parse • lib/Parse/ParseDecl.cpp

    line 7532 ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags, DeclAttributes &Attributes) { bool isExplicitActorDecl = 
 Tok.isContextualKeyword("actor");
  32. Semantic analysis • ᒾҰ state isolationɻ lib/sema/TypeCheckConcurrency.cpp line 2256 bool

    checkMemberReference( Expr *base, ConcreteDeclRef memberRef, SourceLoc memberLoc, Optional<PartialApplyThunkInfo> partialApply = None, Expr *context = nullptr) { { switch (auto isolation = ActorIsolationRestriction::forDeclaration( memberRef, getDeclContext())) { case ActorIsolationRestriction::CrossActorSelf: { return diagnoseNonConcurrentTypesInReference(memberRef, getDeclContext()->getParentModule(), memberLoc, ConcurrentReferenceKind::CrossActor); }
  33. 㗞ੜ SIL • swiftc -emit-sil counter.swift

  34. ฤᩄޙత SIL • sil_stage canonical • import Builtin • import

    Swift • import SwiftShims • import Foundation • actor Counter { • @_hasStorage @_hasInitialValue var count: Int { get set } • func inc() async • @objc deinit • init() • } • @_hasStorage @_hasInitialValue let task: Task<(), Never> { get } • // task • sil_global hidden [let] @$s7counter4tasks4TaskVyyts5NeverOGvp : $Task<(), Never> • // main • sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { • bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): • alloc_global @$s7counter4tasks4TaskVyyts5NeverOGvp // id: %2 • %3 = global_addr @$s7counter4tasks4TaskVyyts5NeverOGvp : $*Task<(), Never> // user: %13 • %4 = metatype $@thin Task<(), Never>.Type // user: %13 • %5 = alloc_stack $Optional<TaskPriority> // users: %15, %14, %13, %6 • inject_enum_addr %5 : $*Optional<TaskPriority>, #Optional.none!enumelt // id: %6 • // function_ref closure #1 in • %7 = function_ref @$s7counteryyYaYbcfU_ : $@convention(thin) @Sendable @async () -> () // user: %8 • %8 = thin_to_thick_function %7 : $@convention(thin) @Sendable @async () -> () to $@Sendable @async @callee_guaranteed () -> () // user: %10 • // function_ref thunk for @escaping @callee_guaranteed @Sendable @async () -> () • %9 = function_ref @$sIeghH_ytIeghHr_TR : $@convention(thin) @Sendable @async (@guaranteed @Sendable @async @callee_guaranteed () -> ()) -> @out () // user: %10 • %10 = partial_apply [callee_guaranteed] %9(%8) : $@convention(thin) @Sendable @async (@guaranteed @Sendable @async @callee_guaranteed () -> ()) -> @out () // user: %11 • %11 = convert_function %10 : $@Sendable @async @callee_guaranteed () -> @out () to $@Sendable @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()> // user: %13 • // function_ref static Task<>.detached(priority:operation:) • %12 = function_ref @$ss4TaskVss5NeverORs_rlE8detached8priority9operationAByxADGs0A8PriorityVSg_xyYaYbcntFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_1 == Never> (@in_guaranteed Optional<TaskPriority>, @owned @Sendable @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>, @thin Task<τ_0_0, Never>.Type) -> @out Task<τ_0_0, Never> // user: %13 • %13 = apply %12<(), Never>(%3, %5, %11, %4) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_1 == Never> (@in_guaranteed Optional<TaskPriority>, @owned @Sendable @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>, @thin Task<τ_0_0, Never>.Type) -> @out Task<τ_0_0, Never> • destroy_addr %5 : $*Optional<TaskPriority> // id: %14 • dealloc_stack %5 : $*Optional<TaskPriority> // id: %15 • %16 = integer_literal $Builtin.Int32, 1 // user: %17 • %17 = struct $UInt32 (%16 : $Builtin.Int32) // user: %19 • // function_ref _sleep • %18 = function_ref @_sleep : $@convention(c) (UInt32) -> UInt32 // user: %19 • %19 = apply %18(%17) : $@convention(c) (UInt32) -> UInt32 • %20 = integer_literal $Builtin.Int32, 0 // user: %21 • %21 = struct $Int32 (%20 : $Builtin.Int32) // user: %22 • return %21 : $Int32 // id: %22 • } // end sil function 'main' • // variable initialization expression of Counter.count • sil hidden [transparent] @$s7counter7CounterC5countSivpfi : $@convention(thin) () -> Int { • bb0: • %0 = integer_literal $Builtin.Int64, 0 // user: %1 • %1 = struct $Int (%0 : $Builtin.Int64) // user: %2 • return %1 : $Int // id: %2 • } // end sil function '$s7counter7CounterC5countSivpfi' • // Int.init(_builtinIntegerLiteral:) • sil public_external [transparent] @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int { • // %0 // user: %2 • bb0(%0 : $Builtin.IntLiteral, %1 : $@thin Int.Type): • %2 = builtin "s_to_s_checked_trunc_IntLiteral_Int64"(%0 : $Builtin.IntLiteral) : $(Builtin.Int64, Builtin.Int1) // user: %3 • %3 = tuple_extract %2 : $(Builtin.Int64, Builtin.Int1), 0 // user: %4 • %4 = struct $Int (%3 : $Builtin.Int64) // user: %5 • return %4 : $Int // id: %5 • } // end sil function '$sSi22_builtinIntegerLiteralSiBI_tcfC' • // Counter.count.getter • sil hidden [transparent] @$s7counter7CounterC5countSivg : $@convention(method) (@guaranteed Counter) -> Int { • // %0 "self" // users: %2, %1 • bb0(%0 : $Counter): • debug_value %0 : $Counter, let, name "self", argno 1 // id: %1 • %2 = ref_element_addr %0 : $Counter, #Counter.count // user: %3 • %3 = begin_access [read] [dynamic] %2 : $*Int // users: %4, %5 • %4 = load %3 : $*Int // user: %6 • end_access %3 : $*Int // id: %5 • return %4 : $Int // id: %6 • } // end sil function '$s7counter7CounterC5countSivg' • // Counter.count.setter • sil hidden [transparent] @$s7counter7CounterC5countSivs : $@convention(method) (Int, @guaranteed Counter) -> () { • // %0 "value" // users: %6, %2 • // %1 "self" // users: %4, %3 • bb0(%0 : $Int, %1 : $Counter): • debug_value %0 : $Int, let, name "value", argno 1 // id: %2 • debug_value %1 : $Counter, let, name "self", argno 2 // id: %3 • %4 = ref_element_addr %1 : $Counter, #Counter.count // user: %5 • %5 = begin_access [modify] [dynamic] %4 : $*Int // users: %6, %7 • store %0 to %5 : $*Int // id: %6 • end_access %5 : $*Int // id: %7 • %8 = tuple () // user: %9 • return %8 : $() // id: %9 • } // end sil function '$s7counter7CounterC5countSivs' • // Counter.count.modify • sil hidden [transparent] @$s7counter7CounterC5countSivM : $@yield_once @convention(method) (@guaranteed Counter) -> @yields @inout Int { • // %0 "self" // users: %2, %1 • bb0(%0 : $Counter): • debug_value %0 : $Counter, let, name "self", argno 1 // id: %1 • %2 = ref_element_addr %0 : $Counter, #Counter.count // user: %3 • %3 = begin_access [modify] [dynamic] %2 : $*Int // users: %5, %8, %4 • yield %3 : $*Int, resume bb1, unwind bb2 // id: %4 • bb1: // Preds: bb0 • end_access %3 : $*Int // id: %5 • %6 = tuple () // user: %7 • return %6 : $() // id: %7 • bb2: // Preds: bb0 • end_access %3 : $*Int // id: %8 • unwind // id: %9 • } // end sil function '$s7counter7CounterC5countSivM' • // Counter.inc() • sil hidden @$s7counter7CounterC3incyyYaF : $@convention(method) @async (@guaranteed Counter) -> () { • // %0 "self" // users: %5, %4, %2, %1 • bb0(%0 : $Counter): • debug_value %0 : $Counter, let, name "self", argno 1 // id: %1 • hop_to_executor %0 : $Counter // id: %2 • %3 = integer_literal $Builtin.Int64, 1 // user: %10 • %4 = class_method %0 : $Counter, #Counter.count!modify : (Counter) -> () -> (), $@yield_once @convention(method) (@guaranteed Counter) -> @yields @inout Int // user: %5 • (%5, %6) = begin_apply %4(%0) : $@yield_once @convention(method) (@guaranteed Counter) -> @yields @inout Int // users: %15, %7, %17 • %7 = struct_element_addr %5 : $*Int, #Int._value // user: %8 • %8 = load %7 : $*Builtin.Int64 // user: %10 • %9 = integer_literal $Builtin.Int1, -1 // user: %10 • %10 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %3 : $Builtin.Int64, %9 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) // users: %12, %11 • %11 = tuple_extract %10 : $(Builtin.Int64, Builtin.Int1), 0 // user: %14 • %12 = tuple_extract %10 : $(Builtin.Int64, Builtin.Int1), 1 // user: %13 • cond_fail %12 : $Builtin.Int1, "arithmetic overflow" // id: %13 • %14 = struct $Int (%11 : $Builtin.Int64) // user: %15 • store %14 to %5 : $*Int // id: %15 • %16 = tuple () • end_apply %6 // id: %17 • %18 = tuple () // user: %19 • return %18 : $() // id: %19 • } // end sil function '$s7counter7CounterC3incyyYaF' • // static Int.+= infix(_:_:) • sil public_external [transparent] @$sSi2peoiyySiz_SitFZ : $@convention(method) (@inout Int, Int, @thin Int.Type) -> () { • // %0 // users: %12, %3 • // %1 // user: %5 • bb0(%0 : $*Int, %1 : $Int, %2 : $@thin Int.Type): • %3 = struct_element_addr %0 : $*Int, #Int._value // user: %4 • %4 = load %3 : $*Builtin.Int64 // user: %7 • %5 = struct_extract %1 : $Int, #Int._value // user: %7 • %6 = integer_literal $Builtin.Int1, -1 // user: %7 • %7 = builtin "sadd_with_overflow_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64, %6 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) // users: %9, %8 • %8 = tuple_extract %7 : $(Builtin.Int64, Builtin.Int1), 0 // user: %11 • %9 = tuple_extract %7 : $(Builtin.Int64, Builtin.Int1), 1 // user: %10 • cond_fail %9 : $Builtin.Int1, "arithmetic overflow" // id: %10 • %11 = struct $Int (%8 : $Builtin.Int64) // user: %12 • store %11 to %0 : $*Int // id: %12 • %13 = tuple () // user: %14 • return %13 : $() // id: %14 • } // end sil function '$sSi2peoiyySiz_SitFZ' • // Counter.deinit • sil hidden @$s7counter7CounterCfd : $@convention(method) (@guaranteed Counter) -> @owned Builtin.NativeObject { • // %0 "self" // users: %3, %2, %1 • bb0(%0 : $Counter): • debug_value %0 : $Counter, let, name "self", argno 1 // id: %1 • %2 = builtin "destroyDefaultActor"(%0 : $Counter) : $() • %3 = unchecked_ref_cast %0 : $Counter to $Builtin.NativeObject // user: %4 • return %3 : $Builtin.NativeObject // id: %4 • } // end sil function '$s7counter7CounterCfd' • // Counter.__deallocating_deinit • sil hidden @$s7counter7CounterCfD : $@convention(method) (@owned Counter) -> () { • // %0 "self" // users: %3, %1 • bb0(%0 : $Counter): • debug_value %0 : $Counter, let, name "self", argno 1 // id: %1 • // function_ref Counter.deinit • %2 = function_ref @$s7counter7CounterCfd : $@convention(method) (@guaranteed Counter) -> @owned Builtin.NativeObject // user: %3 • %3 = apply %2(%0) : $@convention(method) (@guaranteed Counter) -> @owned Builtin.NativeObject // user: %4 • %4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $Counter // user: %5 • dealloc_ref %4 : $Counter // id: %5 • %6 = tuple () // user: %7 • return %6 : $() // id: %7 • } // end sil function '$s7counter7CounterCfD' 360 ߦ
  35. SIL ॏᴍઅ㑚 inc // Counter.inc() sil hidden @$s7counter7CounterC3incyyYaF : $@convention(method)

    @async (@guaranteed Counter) -> () { // %0 "self" // users: %5, %4, %2, %1 bb0(%0 : $Counter): debug_value %0 : $Counter, let, name "self", argno 1 // id: %1 hop_to_executor %0 : $Counter // id: %2 ... %10 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %3 : $Builtin.Int64, %9 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) // users: %12, %11 ... }
  36. SIL generation • ೺ actor ᙛ੒ class ိgenerate SILɻୠੋಛผ㗞ੜ hop_to_executor

    ɻ • lib/SILGen/SILGenProlog.cpp Line 407 void SILGenFunction::emitProlog(CaptureInfo captureInfo, ...) { switch (actorIsolation.getKind()) { ... case ActorIsolation::ActorInstance: { if (F.isAsync() || (wantDataRaceChecks && funcDecl->isLocalCapture())) { auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation()); ManagedValue selfArg = ManagedValue::forUnmanaged(F.getSelfArgument()); ExpectedExecutor = emitLoadActorExecutor(loc, selfArg); } break; }
  37. SIL generation • ೺ actor ᙛ੒ class ိgenerate SILɻୠੋಛผ㗞ੜ hop_to_executor

    ɻ • lib/SILGen/SILGenProlog.cpp Line 569 void SILGenFunction::emitProlog(CaptureInfo captureInfo, ...) { ... // Jump to the expected executor. if (ExpectedExecutor) { if (F.isAsync()) { // For an async function, hop to the executor. B.createHopToExecutor( RegularLocation::getAutoGeneratedLocation(F.getLocation()), ExpectedExecutor, /*mandatory*/ false);
  38. SIL ॏᴍઅ㑚 count getter // Counter.count.getter sil hidden [transparent] @$s7counter7CounterC5countSivg

    : $@convention(method) (@guaranteed Counter) -> Int { // %0 "self" // users: %2, %1 bb0(%0 : $Counter): debug_value %0 : $Counter, let, name "self", argno 1 // id: %1 %2 = ref_element_addr %0 : $Counter, #Counter.count // user: %3 %3 = begin_access [read] [dynamic] %2 : $*Int // users: %4, %5 %4 = load %3 : $*Int // user: %6 end_access %3 : $*Int // id: %5 return %4 : $Int // id: %6 } // end sil function '$s7counter7CounterC5countSivg'
  39. SIL ॏᴍઅ㑚 count setter // Counter.count.setter sil hidden [transparent] @$s7counter7CounterC5countSivs

    : $@convention(method) (Int, @guaranteed Counter) -> () { // %0 "value" // users: %6, %2 // %1 "self" // users: %4, %3 bb0(%0 : $Int, %1 : $Counter): ... %4 = ref_element_addr %1 : $Counter, #Counter.count // user: %5 %5 = begin_access [modify] [dynamic] %4 : $*Int // users: %6, %7 store %0 to %5 : $*Int // id: %6 end_access %5 : $*Int // id: %7 %8 = tuple () // user: %9 return %8 : $() // id: %9 } // end sil function '$s7counter7CounterC5countSivs'
  40. SIL generation • ࡏଘऔత࣌ީ။؃ੋෆੋࡏ actor ཫɼੋత࿩ब။Ճ্ beginAccess • lib/SILGen/SILGenLValue.cpp Line

    615 SILValue UnenforcedAccess::beginAccess(SILGenFunction &SGF, SILLocation loc, SILValue address, SILAccessKind kind) { if (!SGF.getOptions().VerifyExclusivity) return address; ... auto BAI = SGF.B.createBeginAccess(loc, address, kind, SILAccessEnforcement::Unsafe, /*hasNoNestedConflict=*/false, /*fromBuiltin=*/false); return BAI; }
  41. SIL generation • ޙ໘໵။Ճ্ሣጯత endAccess • lib/SILGen/SILGenLValue.cpp Line 639 void

    UnenforcedAccess::emitEndAccess(SILGenFunction &SGF) { if (!beginAccessPtr) return; SGF.B.createEndAccess(beginAccessPtr->getLoc(), beginAccessPtr.get(), /*abort*/ false); }
  42. 㗞ੜ LLVM IR • swiftc -emit-ir counter.swift

  43. ฤᩄޙత LLVM IR ; ModuleID = '<swift-imported-modules>' source_filename = "<swift-imported-modules>"

    target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" module asm ".section .swift1_autolink_entries,\220x80000000\22" %TScT = type <{ %swift.refcounted* }> %swift.refcounted = type { %swift.type*, i64 } %swift.type = type { i64 } %swift.async_func_pointer = type <{ i32, i32 }> %swift.full_boxmetadata = type { void (%swift.refcounted*)*, i8**, %swift.type, i32, i8* } %swift.full_type = type { i8**, %swift.type } %swift.protocol = type { i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i32, i32, i32, i32, i32, i32 } %swift.method_descriptor = type { i32, i32 } %T7counter7CounterC = type <{ %swift.refcounted, %swift.defaultactor, %TSi }> %swift.defaultactor = type { [12 x i8*] } %TSi = type <{ i64 }> %swift.type_metadata_record = type { i32 } %swift.vwtable = type { i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i64, i32, i32 } %TScPSg = type <{}> %swift.opaque = type opaque %swift.metadata_response = type { %swift.type*, i64 } %swift.function = type { i8*, %swift.refcounted* } %swift.type_descriptor = type opaque %"$s7counter7CounterC5countSivM.Frame" = type { [24 x i8] } %swift.context = type { %swift.context*, void (%swift.context*)*, i64 } %"$s7counter7CounterC3incyyYaF.Frame" = type { %swift.context*, %T7counter7CounterC*, %T7counter7CounterC* } %"$s7counteryyYaYbcfU_.Frame" = type { %swift.context*, %T7counter7CounterC*, i64, %T7counter7CounterC*, i8*, i64, i64, i64 } %swift.executor = type { i64, i64 } %Ts28__ContiguousArrayStorageBaseC = type opaque %Any = type { [24 x i8], %swift.type* } %swift.bridge = type opaque %TSa = type <{ %Ts22_ContiguousArrayBufferV }> %Ts22_ContiguousArrayBufferV = type <{ %Ts28__ContiguousArrayStorageBaseC* }> %"$sIeghH_ytIeghHr_TR.Frame" = type { %swift.context*, i8* } %"$sIeghH_ytIeghHr_TRTA.Frame" = type { %swift.context*, i8* } %swift.async_task_and_context = type { %swift.task*, %swift.context* } %swift.task = type { %swift.refcounted, i8*, i8*, i32, i32, i8*, i8*, i8*, %swift.context*, i64 } %"$sxIeghHr_xs5Error_pIegHrzo_s5NeverORs_r0_lTR.Frame" = type { %swift.context*, i8* } %swift.error = type opaque %"$sxIeghHr_xs5Error_pIegHrzo_s5NeverORs_r0_lTRTA.Frame" = type { %swift.context*, i8* } @"$s7counter4taskScTyyts5NeverOGvp" = hidden global %TScT zeroinitializer, align 8 @"symbolic ScPSg" = linkonce_odr hidden constant <{ [5 x i8], i8 }> <{ [5 x i8] c"ScPSg", i8 0 }>, section "swift5_typeref", align 2 @"$sScPSgMD" = linkonce_odr hidden global { i32, i32 } { i32 trunc (i64 sub (i64 ptrtoint (<{ [5 x i8], i8 }>* @"symbolic ScPSg" to i64), i64 ptrtoint ({ i32, i32 }* @"$sScPSgMD" to i64)) to i32), i32 -5 }, align 8 @"$s7counteryyYaYbcfU_Tu" = internal global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (void (%swift.context*)* @"$s7counteryyYaYbcfU_" to i64), i64 ptrtoint (%swift.async_func_pointer* @"$s7counteryyYaYbcfU_Tu" to i64)) to i32), i32 96 }>, section ".rodata", align 8 @"$sIeghH_ytIeghHr_TRTu" = linkonce_odr hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (void (%swift.opaque*, %swift.context*, i8*, %swift.refcounted*)* @"$sIeghH_ytIeghHr_TR" to i64), i64 ptrtoint (%swift.async_func_pointer* @"$sIeghH_ytIeghHr_TRTu" to i64)) to i32), i32 48 }>, section ".rodata", align 8 @"symbolic IeghH_" = linkonce_odr hidden constant <{ [6 x i8], i8 }> <{ [6 x i8] c"IeghH_", i8 0 }>, section "swift5_typeref", align 2 @"\01l__swift5_reflection_descriptor" = private constant { i32, i32, i32, i32 } { i32 1, i32 0, i32 0, i32 trunc (i64 sub (i64 ptrtoint (<{ [6 x i8], i8 }>* @"symbolic IeghH_" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i32, i32, i32, i32 }, { i32, i32, i32, i32 }* @"\01l__swift5_reflection_descriptor", i32 0, i32 3) to i64)) to i32) }, section "swift5_capture", align 4 @metadata = private constant %swift.full_boxmetadata { void (%swift.refcounted*)* @objectdestroy, i8** null, %swift.type { i64 1024 }, i32 16, i8* bitcast ({ i32, i32, i32, i32 }* @"\01l__swift5_reflection_descriptor" to i8*) }, align 8 @"$sIeghH_ytIeghHr_TRTATu" = internal global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (void (%swift.opaque*, %swift.context*, %swift.refcounted*)* @"$sIeghH_ytIeghHr_TRTA" to i64), i64 ptrtoint (%swift.async_func_pointer* @"$sIeghH_ytIeghHr_TRTATu" to i64)) to i32), i32 48 }>, section ".rodata", align 8 @"$sytN" = external global %swift.full_type @"$s7counter7CounterC3incyyYaFTu" = hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (void (%swift.context*, %T7counter7CounterC*)* @"$s7counter7CounterC3incyyYaF" to i64), i64 ptrtoint (%swift.async_func_pointer* @"$s7counter7CounterC3incyyYaFTu" to i64)) to i32), i32 48 }>, section ".rodata", align 8 @"$sScAMp" = external global %swift.protocol, align 4 @"got.$sScAMp" = private unnamed_addr constant %swift.protocol* @"$sScAMp" @"$sScA15unownedExecutorScevgTq" = external global %swift.method_descriptor, align 4 @"got.$sScA15unownedExecutorScevgTq" = private unnamed_addr constant %swift.method_descriptor* @"$sScA15unownedExecutorScevgTq" @"$s7counter7CounterCScAAAMcMK" = internal global [16 x i8*] zeroinitializer @"$s7counter7CounterCScAAAMc" = hidden constant { i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 } { i32 add (i32 trunc (i64 sub (i64 ptrtoint (%swift.protocol** @"got.$sScAMp" to i64), i64 ptrtoint ({ i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }* @"$s7counter7CounterCScAAAMc" to i64)) to i32), i32 1), i32 trunc (i64 sub (i64 ptrtoint (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>* @"$s7counter7CounterCMn" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }, { i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }* @"$s7counter7CounterCScAAAMc", i32 0, i32 1) to i64)) to i32), i32 0, i32 196608, i32 1, i32 add (i32 trunc (i64 sub (i64 ptrtoint (%swift.method_descriptor** @"got.$sScA15unownedExecutorScevgTq" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }, { i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }* @"$s7counter7CounterCScAAAMc", i32 0, i32 5) to i64)) to i32), i32 1), i32 trunc (i64 sub (i64 ptrtoint ({ i64, i64 } (%T7counter7CounterC*, %swift.type*, i8**)* @"$s7counter7CounterCScAAAScA15unownedExecutorScevgTW" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }, { i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }* @"$s7counter7CounterCScAAAMc", i32 0, i32 6) to i64)) to i32), i16 0, i16 1, i32 0, i32 trunc (i64 sub (i64 ptrtoint ([16 x i8*]* @"$s7counter7CounterCScAAAMcMK" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }, { i32, i32, i32, i32, i32, i32, i32, i16, i16, i32, i32 }* @"$s7counter7CounterCScAAAMc", i32 0, i32 10) to i64)) to i32) }, section ".rodata", align 4 @"\01l_entry_point" = private constant { i32 } { i32 trunc (i64 sub (i64 ptrtoint (i32 (i32, i8**)* @main to i64), i64 ptrtoint ({ i32 }* @"\01l_entry_point" to i64)) to i32) }, section "swift5_entry", align 4 @"$s7counter7CounterC5countSivpWvd" = hidden constant i64 112, align 8 @"$sBoWV" = external global i8*, align 8 @0 = private constant [8 x i8] c"counter\00" @"$s7counterMXM" = linkonce_odr hidden constant <{ i32, i32, i32 }> <{ i32 0, i32 0, i32 trunc (i64 sub (i64 ptrtoint ([8 x i8]* @0 to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32 }>, <{ i32, i32, i32 }>* @"$s7counterMXM", i32 0, i32 2) to i64)) to i32) }>, section ".rodata", align 4 @1 = private constant [8 x i8] c"Counter\00" 1357 ߦ
  44. LLVM IR inc ॏᴍઅ㑚 define hidden swifttailcc void @"$s7counter7CounterC3incyyYaF"(%swift.context* swiftasync

    %0, %T7counter7CounterC* swiftself %1) #0 { entry: ... musttail call swifttailcc void @swift_task_switch(%swift.context* swiftasync %6, i8* bitcast (void (i8*)* @"$s7counter7CounterC3incyyYaFTY0_" to i8*), i64 %5, i64 0) #7 ret void }
  45. LLVM IR inc ॏᴍઅ㑚 define internal swifttailcc void @"$s7counter7CounterC3incyyYaFTY0_"(i8* swiftasync

    %0) #0 { entryresume.0: %async.ctx.frameptr1 = getelementptr inbounds i8, i8* %0, i32 24 %FramePtr = bitcast i8* %async.ctx.frameptr1 to %"$s7counter7CounterC3incyyYaF.Frame"* ... %15 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %14, i64 1) ... }
  46. LLVM IR Generation • lib/IRGen/IRGenSIL.cpp Line 6173 void IRGenSILFunction::visitHopToExecutorInst(HopToExecutorInst *i)

    { assert(i->getTargetExecutor()->getType().getOptionalObjectType() .is<BuiltinExecutorType>()); llvm::Value *resumeFn = Builder.CreateIntrinsicCall( llvm::Intrinsic::coro_async_resume, {}); Explosion executor; getLoweredExplosion(i->getOperand(), executor); emitSuspensionPoint(executor, resumeFn); }
  47. LLVM IR Generation • lib/IRGen/GenFunc.cpp Line 2402 void IRGenFunction::emitSuspensionPoint(Explosion &toExecutor,

    llvm::Value *asyncResume) { // Setup the suspend point. ... llvm::Function *suspendFn = createAsyncSuspendFn(); ... }
  48. LLVM IR Generation • lib/IRGen/GenFunc.cpp Line 2438 llvm::Function *IRGenFunction::createAsyncSuspendFn() {

    ... auto *suspendCall = Builder.CreateCall( IGM.getTaskSwitchFuncFn(), { context, resumeFunction, targetExecutorFirst, targetExecutorSecond });
  49. LLVM IR Generation • include/swift/Runtime/RuntimeFunctions.def Line 1569 FUNCTION(TaskSwitchFunc, swift_task_switch, SwiftAsyncCC,

    ConcurrencyAvailability, RETURNS(VoidTy), ARGS(SwiftContextPtrTy, Int8PtrTy, ExecutorFirstTy, ExecutorSecondTy), ATTRS(NoUnwind))
  50. LLVM IR count getter ॏᴍઅ㑚 define hidden swiftcc i64 @"$s7counter7CounterC5countSivg"(%T7counter7CounterC*

    swiftself %0) #0 { entry: ... call void @swift_beginAccess(i8* %3, [24 x i8]* %access-scratch, i64 32, i8* null) #7 %._value = getelementptr inbounds %TSi, %TSi* %1, i32 0, i32 0 %4 = load i64, i64* %._value, align 16 call void @swift_endAccess([24 x i8]* %access-scratch) #7 ... ret i64 %4 }
  51. LLVM IR count setter ॏᴍઅ㑚 define hidden swiftcc void @"$s7counter7CounterC5countSivs"(i64

    %0, %T7counter7CounterC* swiftself %1) #0 { entry: ... call void @swift_beginAccess(i8* %4, [24 x i8]* %access-scratch, i64 33, i8* null) #7 %._value = getelementptr inbounds %TSi, %TSi* %2, i32 0, i32 0 store i64 %0, i64* %._value, align 16 call void @swift_endAccess([24 x i8]* %access-scratch) #7 ... }
  52. Async : ೗Կ֬อಉ࣌୞။༗Ұݸ actor method ӡߦ • ࡏ semantic analysis

    త࣌ީ䔪ᎃᔒ༗ async తݺڣɻ • ೺ method ຊᱪ แࡏҰݸ async helper ཫɻ • ࡏ async helper औಘ actor త thread(Executor)ɻ • ࡏ async helper ೺ method ຊᱪഉਐ actor thread 
 త task queueɻ • ༻task queue ိࣥߦ method ຊᱪɻ
  53. State Isolation : ೗Կ֬อᏓᏐෆ။ඃଖଞ஍ํଘऔ • ࡏ semantic analysis త࣌ީ䔪ᎃଖଞ஍ํతଘऔ •

    ೺ଘऔ౎༻ getter/setter method แىိɻ • ࡏ getter/setter ཫ࢖༻ swift_beginAccess/swift_endAccess 
 ိ࠯ఆᏓᏐ
  54. ݁࿦ • actor ੋඃᙛ੒Ұछ conform to Actor Protocol త Class

    ိ႔ཧɻ • State isolation ੋ༻ type check enforceɻ • State access ။༻ begin_access & end_access ࠯ఆɻ • ॴ༗త actor method call ౎༗Ճ্ hop_to_executor SIL • hop_to_executor ။Ꮣ੒ swift_task_switch IRɼࡏ task queue
 ཫংྻࣥߦɻ
  55. References • https://swift.org/swift-compiler/#compiler-architecture • https://github.com/apple/swift • https://www.swiftbysundell.com/articles/the-main-actor-attribute/ • https://llvm.org/docs/Coroutines.html#switched-resume-lowering •

  56. Q&A John Lin Twitter: @johnlinvc ౤Өย QR code ໢ᅿɿ
 https://tinyurl.com/3ur2stp8