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

Getting Under Swift’s Skin

06609d73ad2165c4aafcf65a1ddb9563?s=47 Greg Heo
February 07, 2018

Getting Under Swift’s Skin

Staying on the surface, we deal with the Swift language, runtime, and standard library all the time. In this talk, we’ll go one small level down and look underneath the surface: Swift Intermediate Language (SIL), reflection, and debug-enabled toolchains. What can we learn, why should we bother, and most importantly, how can it help improve our programming lives?

06609d73ad2165c4aafcf65a1ddb9563?s=128

Greg Heo

February 07, 2018
Tweet

Transcript

  1. @gregheo NSMeetup February 7, 2018

  2. Stack views Auto Layout Frame calculations UIViews CALayers Core Animation

    OpenGL Metal putpixel() OLEDs Individual photons Quantum physics GUI toolkits Standard library Unix processes fork vs exec bash Kernel modules Operating systems Linkers Compilers Assembly Toggle switches emacs
  3. None
  4. — Jesse Squires

  5. Swift Runtime Instances Standard Library SIL Reflection Debug Toolchains

  6. None
  7. SIL IR Object CodeGen IRGen AST Sema SILGen Parse

  8. None
  9. 00 e3 8e c0 〇〇〇 〇〇〇〇〇〇〇〇 〇〇〇〇〇〇 〇〇〇〇 add bl,ah

    mov es,eax
  10. ASM Binary

  11. ASM C Binary C++

  12. ASM C Binary C++ Obj-C

  13. ASM C Binary C++ Obj-C

  14. ASM C Binary C++ IR Obj-C

  15. printf(“hello world!”); subq $32, %rsp leaq L_.str(%rip), %rax movl $0,

    -4(%rbp) movl %edi, -8(%rbp) movq %rsi, -16(%rbp) movq %rax, %rdi movb $0, %al callq_printf define i32 @main(i32, i8**) #0 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 store i8** %1, i8*** %5, align 8 %6 = call i32 (i8*, …)
 @printf(i8* getelementptr inbounds… ret i32 0 }
  16. ASM C Binary C++ IR Obj-C

  17. SIL IR …

  18. None
  19. class NSMeetup { func sayHello() { print("Hello") } } let

    m = NSMeetup() m.sayHello()
  20. sil_stage canonical import Builtin import Swift import SwiftShims // m

    sil_global hidden [let] @_T06simple1mAA8NSMeetupCv : $NSMeetup // _swiftEmptyArrayStorage sil_global [serialized] @_swiftEmptyArrayStorage : $_SwiftEmptyArrayStorage // main sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : $Int32, %1 :
  21. sil_vtable NSMeetup { #NSMeetup.sayHello!1: (NSMeetup) -> () -> () :

    _T06simple8NSMeetupC8sayHelloyyF // NSMeetup.sayHello() #NSMeetup.init!initializer.1: (NSMeetup.Type) -> () -> NSMeetup : _T06simple8NSMeetupCACycfc // NSMeetup.init() #NSMeetup.deinit!deallocator: _T06simple8NSMeetupCfD // NSMeetup.__deallocating_deinit } sil_vtable _ContiguousArrayStorage { #_SwiftNativeNSArrayWithContiguousStorage.withUnsafeBufferOfObjects!1 <R> (_SwiftNativeNSArrayWithContiguousStorage) -> ((UnsafeBufferPointer<AnyObject>) throws -> R) throws -> R : _T0s27_ContiguousArrayStorageBaseC25withUnsafeBufferOfObjectsxxSRyyXlGK KlF // _ContiguousArrayStorageBase.withUnsafeBufferOfObjects<A>(_:) #_ContiguousArrayStorageBase._withVerbatimBridgedUnsafeBuffer!1: <R> (_ContiguousArrayStorageBase) -> ((UnsafeBufferPointer<AnyObject>)
  22. // NSMeetup.sayHello() sil hidden @_T06simple8NSMeetupC8sayHelloyyF : $@convention(method) (@guaranteed NSMeetup) ->

    () { // %0 // user: %1 bb0(%0 : $NSMeetup): debug_value %0 : $NSMeetup, let, name "self", argno 1 // id: %1 // function_ref print(_:separator:terminator:) %2 = function_ref @_T0s5printySayypGd_SS9separatorSS10terminatortF : $@convention(thin) (@owned Array<Any>, @owned String, @owned String) -> () // user: %23 %3 = integer_literal $Builtin.Word, 1 // user: %5 // function_ref specialized _allocateUninitializedArray<A>(_:) %4 = function_ref @_T0s27_allocateUninitializedArraySayxG_BptBwlFyp_Tgq5 : $@convention(thin) (Builtin.Word) -> (@owned Array<Any>, Builtin.RawPointer) // user: %5 %5 = apply %4(%3) : $@convention(thin) (Builtin.Word) -> (@owned
  23. $ xcrun swift-demangle
 _T0s5printySayypGd_SS9separatorSS10terminatortF
 Swift.print(Any...,
 separator: Swift.String,
 terminator: Swift.String) ->

    ()
  24. retain_value %6 : $Array<Any> // id: %7 %8 = tuple_extract

    %5 : $(Array<Any>, Builtin.RawPointer), 1 // user: %10 release_value %5 : $(Array<Any>, Builtin.RawPointer) // id: %9 %10 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Any / user: %11 %11 = init_existential_addr %10 : $*Any, $String // user: %18 %12 = string_literal utf8 "Hello" // user: %17 %13 = integer_literal $Builtin.Word, 5 // user: %17 %14 = integer_literal $Builtin.Int1, -1 // user: %17 %15 = metatype $@thin String.Type // user: %17 // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:) %16 = function_ref @_T0S2SBp21_builtinStringLiteral_Bw17utf8CodeUnitCountBi1_7isASCIItcfC $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %17 %17 = apply %16(%12, %13, %14, %15) : $@convention(method)
  25. class NSMeetup { func sayHello() { print("Hello") } } //

    let m = NSMeetup()
 var m = NSMeetup()
 m.sayHello()
  26. %9 = load %8 : $*NSMeetup %10 = class_method %9

    : $NSMeetup, #NSMeetup.sayHello!1 : (NSMeetup) -> () -> (), $@convention(method) (@guaranteed NSMeetup) -> () %11 = apply %10(%9) : $@convention(method) (@guaranteed NSMeetup) -> ()
  27. %8 = begin_access [read] [dynamic] %3 : $*NSMeetup %9 =

    load %8 : $*NSMeetup strong_retain %9 : $NSMeetup end_access %8 : $*NSMeetup %10 = class_method %9 : $NSMeetup, #NSMeetup.sayHello!1 : (NSMeetup) -> () -> (), $@convention(method) (@guaranteed NSMeetup) -> () %11 = apply %10(%9) : $@convention(method) (@guaranteed NSMeetup) -> () strong_release %9 : $NSMeetup
  28. call void @llvm.lifetime.start(i64 -1, i8* %13) call void @swift_beginAccess(i8* bitcast

    (%TSi* @_T011simpleprint1aSiv to i8*), [24 x i8]* %access-scratch, i64 0, i8* null) #6 %14 = load i64, i64* getelementptr inbounds (%TSi, %TSi* @_T011simpleprint1aSiv, i32 0, i32 0), align 8 call void @swift_endAccess([24 x i8]* %access-scratch) #6 %15 = bitcast [24 x i8]* %access-scratch to i8* call void @llvm.lifetime.end(i64 -1, i8* %15) %._value = getelementptr inbounds %TSi, %TSi* %12, i32 0, i32 0 store i64 %14, i64* %._value, align 8 %16 = call swiftcc { i64, i64, i64 } @_T0s5printySayypGd_SS9separatorSS10terminatortFfA0_() %17 = extractvalue { i64, i64, i64 } %16, 0 %18 = extractvalue { i64, i64, i64 } %16, 1 %19 = extractvalue { i64, i64, i64 } %16, 2
  29. call void @llvm.lifetime.start(i64 -1, i8* %13) call void @swift_beginAccess(i8* bitcast

    (%TSi* @_T011simpleprint1aSiv to i8*), [24 x i8]* %access-scratch, i64 0, i8* null) #6
 
 call void @#__tsan_read8(i8* bitcast (%TSi* @_T011simpleprint1aSiv to i8*)) %14 = load i64, i64* getelementptr inbounds (%TSi, %TSi* @_T011simpleprint1aSiv, i32 0, i32 0), align 8 call void @swift_endAccess([24 x i8]* %access-scratch) #6 %15 = bitcast [24 x i8]* %access-scratch to i8* call void @llvm.lifetime.end(i64 -1, i8* %15) %._value = getelementptr inbounds %TSi, %TSi* %12, i32 0, i32 0 store i64 %14, i64* %._value, align 8 %16 = call swiftcc { i64, i64, i64 } @_T0s5printySayypGd_SS9separatorSS10terminatortFfA0_()
  30. • Your code, lowered • ARC & memory management •

    Change code; see diffs on SIL
  31. None
  32. Queries Modifications Construction

  33. Reflection Demo

  34. • Objective-C runtime functions • Mirror for “read-only reflection” •

    Direct pointer access • More advanced reflection to come?
  35. ASM C Binary C++ IR Obj-C

  36. Language Standard Library

  37. Standard library demo

  38. • Standard library is open source! • Standard library code

    in the debugger • Running custom Xcode toolchains
  39. Swift Runtime Instances Standard Library SIL Reflection Debug Toolchains

  40. So What?

  41. None
  42. None
  43. None
  44. https://gregheo.com

  45. Getting Under
 Swift’s Skin @gregheo NSMeetup February 7, 2018