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

Getting Under Swift’s Skin

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?

Greg Heo

February 07, 2018
Tweet

More Decks by Greg Heo

Other Decks in Technology

Transcript

  1. 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
  2. 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 }
  3. 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 :
  4. 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>)
  5. // 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
  6. 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)
  7. class NSMeetup { func sayHello() { print("Hello") } } //

    let m = NSMeetup()
 var m = NSMeetup()
 m.sayHello()
  8. %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) -> ()
  9. %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
  10. 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
  11. 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_()
  12. • Objective-C runtime functions • Mirror for “read-only reflection” •

    Direct pointer access • More advanced reflection to come?
  13. • Standard library is open source! • Standard library code

    in the debugger • Running custom Xcode toolchains