zoukankan      html  css  js  c++  java
  • swift protocol 见证容器 虚函数表 与 动态派发

    一、测试代码:

    //protocol DiceGameDelegate: AnyObject {

    //}

    //

    //@objc protocol OcProtocol{

    //    @objc func OcFunc()

    //}

    protocol SeedProtocol {

        func NormalFunc()

        func ExtenImpFunc()

        //@objc func OcFunc()

    }

    extension SeedProtocol{

        func ExtenImpFunc(){}

        func ExtenDefineFunc(){}

    }

    struct NormalStruct:SeedProtocol {

        func NormalFunc(){}

    }

    struct FullImpStruct:SeedProtocol {

        func NormalFunc(){}

        func ExtenImpFunc(){}

        func ExtenDefineFunc(){}

    }

    struct EmptyStruct {}

    extension EmptyStruct:SeedProtocol{

        func NormalFunc(){}

    }

    func CallProtocol(_ object:SeedProtocol)

    {

        object.NormalFunc()

        object.ExtenImpFunc()

        object.ExtenDefineFunc()

    }

    func DoTest(){

        CallProtocol(NormalStruct())

    //    CallProtocol(FullImpStruct())

    //    CallProtocol(EmptyStruct())

    }

    二、见证容器

    • Existential Container

    20170429105028_748.jpg

    这是一个最普通的 Existential Container。

    • 前三个word:Value buffer。用来存储Inline的值,如果word数大于3,则采用指针的方式,在堆上分配对应需要大小的内存
    • 第四个word:Value Witness Table(VWT)。每个类型都对应这样一个表,用来存储值的创建,释放,拷贝等操作函数。(管理 Existential Container 生命周期)
    • 第五个word:Protocol Witness Table(PWT),用来存储协议的函数。

    用伪代码表示如下:

    所以,对于上文代码中的 Point 和 Line 最后的数据结构大致如下:

    20170429105028_236.jpg

    这里需要注意的几个点:

    • 在 ABI 稳定之前 value buffer 的 size 可能会变,对于是不是 3个 word 还在 Swift 团队还在权衡.
    • Existential Container 的 size 不是只有 5 个 word。示例如下:

    20170429105028_637.jpg

    对于这个大小差异最主要在于这个 PWT 指针,对于 Any 来说,没有具体的函数实现,所以不需要 PWT 这个指针,但是对于 ProtocolOne&ProtocolTwo 的组合协议,是需要两个 PWT 指针来表示的。

    OK,由于 Existential Container 的引入,我们可以将协议作为类型来解决 平凡类型 没有继承的问题,所以 Struct:Protocol 和 抽象类就越来越像了。

    https://www.cnblogs.com/feng9exe/p/9680824.html

    三、虚函数表:

    sil_witness_table hidden NormalStruct: ProtocolCase module ProtocolCase {

      method #ProtocolCase.NormalFunc!1: <Self where Self : ProtocolCase> (Self) -> () -> () : @protocol witness for ProtocolCase.ProtocolCase.NormalFunc() -> () in conformance ProtocolCase.NormalStruct : ProtocolCase.ProtocolCase in ProtocolCase // protocol witness for ProtocolCase.NormalFunc() in conformance NormalStruct

      method #ProtocolCase.ExtenImpFunc!1: <Self where Self : ProtocolCase> (Self) -> () -> () : @protocol witness for ProtocolCase.ProtocolCase.ExtenImpFunc() -> () in conformance ProtocolCase.NormalStruct : ProtocolCase.ProtocolCase in ProtocolCase // protocol witness for ProtocolCase.ExtenImpFunc() in conformance NormalStruct

    }

    sil_witness_table hidden FullImpStruct: ProtocolCase module ProtocolCase {

      method #ProtocolCase.NormalFunc!1: <Self where Self : ProtocolCase> (Self) -> () -> () : @protocol witness for ProtocolCase.ProtocolCase.NormalFunc() -> () in conformance ProtocolCase.FullImpStruct : ProtocolCase.ProtocolCase in ProtocolCase // protocol witness for ProtocolCase.NormalFunc() in conformance FullImpStruct

      method #ProtocolCase.ExtenImpFunc!1: <Self where Self : ProtocolCase> (Self) -> () -> () : @protocol witness for ProtocolCase.ProtocolCase.ExtenImpFunc() -> () in conformance ProtocolCase.FullImpStruct : ProtocolCase.ProtocolCase in ProtocolCase // protocol witness for ProtocolCase.ExtenImpFunc() in conformance FullImpStruct

    }

    sil_witness_table hidden EmptyStruct: ProtocolCase module ProtocolCase {

      method #ProtocolCase.NormalFunc!1: <Self where Self : ProtocolCase> (Self) -> () -> () : @protocol witness for ProtocolCase.ProtocolCase.NormalFunc() -> () in conformance ProtocolCase.EmptyStruct : ProtocolCase.ProtocolCase in ProtocolCase // protocol witness for ProtocolCase.NormalFunc() in conformance EmptyStruct

      method #ProtocolCase.ExtenImpFunc!1: <Self where Self : ProtocolCase> (Self) -> () -> () : @protocol witness for ProtocolCase.ProtocolCase.ExtenImpFunc() -> () in conformance ProtocolCase.EmptyStruct : ProtocolCase.ProtocolCase in ProtocolCase // protocol witness for ProtocolCase.ExtenImpFunc() in conformance EmptyStruct

    }

    四、动态派发机制

    // CallProtocol(_:)

    sil hidden @ProtocolCase.CallProtocol(ProtocolCase.SeedProtocol) -> () : $@convention(thin) (@in_guaranteed SeedProtocol) -> () {

    // %0                                             // users: %8, %5, %2, %1

    bb0(%0 : $*SeedProtocol):

      debug_value_addr %0 : $*SeedProtocol, let, name "object", argno 1 // id: %1

      %2 = open_existential_addr immutable_access %0 : $*SeedProtocol to $*@opened("C73DB366-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol // users: %4, %4, %3

      %3 = witness_method $@opened("C73DB366-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol, #SeedProtocol.NormalFunc!1 : <Self where Self : SeedProtocol> (Self) -> () -> (), %2 : $*@opened("C73DB366-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol : $@convention(witness_method: SeedProtocol) <τ_0_0 where τ_0_0 : SeedProtocol> (@in_guaranteed τ_0_0) -> () // type-defs: %2; user: %4

      %4 = apply %3<@opened("C73DB366-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol>(%2) : $@convention(witness_method: SeedProtocol) <τ_0_0 where τ_0_0 : SeedProtocol> (@in_guaranteed τ_0_0) -> () // type-defs: %2

      %5 = open_existential_addr immutable_access %0 : $*SeedProtocol to $*@opened("C73E23AA-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol // users: %7, %7, %6

      %6 = witness_method $@opened("C73E23AA-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol, #SeedProtocol.ExtenImpFunc!1 : <Self where Self : SeedProtocol> (Self) -> () -> (), %5 : $*@opened("C73E23AA-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol : $@convention(witness_method: SeedProtocol) <τ_0_0 where τ_0_0 : SeedProtocol> (@in_guaranteed τ_0_0) -> () // type-defs: %5; user: %7

      %7 = apply %6<@opened("C73E23AA-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol>(%5) : $@convention(witness_method: SeedProtocol) <τ_0_0 where τ_0_0 : SeedProtocol> (@in_guaranteed τ_0_0) -> () // type-defs: %5

      %8 = open_existential_addr immutable_access %0 : $*SeedProtocol to $*@opened("C73E2738-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol // users: %10, %10

      // function_ref SeedProtocol.ExtenDefineFunc()

      %9 = function_ref @(extension in ProtocolCase):ProtocolCase.SeedProtocol.ExtenDefineFunc() -> () : $@convention(method) <τ_0_0 where τ_0_0 : SeedProtocol> (@in_guaranteed τ_0_0) -> () // user: %10

      %10 = apply %9<@opened("C73E2738-4AFB-11E9-B4BE-ACBC329BAA1D") SeedProtocol>(%8) : $@convention(method) <τ_0_0 where τ_0_0 : SeedProtocol> (@in_guaranteed τ_0_0) -> () // type-defs: %8

      %11 = tuple ()                                  // user: %12

      return %11 : $()                                // id: %12

    } // end sil function 'ProtocolCase.CallProtocol(ProtocolCase.SeedProtocol) -> ()'

    // DoTest()

    sil hidden @ProtocolCase.DoTest() -> () : $@convention(thin) () -> () {

    bb0:

      %0 = alloc_stack $SeedProtocol                  // users: %9, %8, %7, %4

      %1 = metatype $@thin NormalStruct.Type          // user: %3

      // function_ref NormalStruct.init()

      %2 = function_ref @ProtocolCase.NormalStruct.init() -> ProtocolCase.NormalStruct : $@convention(method) (@thin NormalStruct.Type) -> NormalStruct // user: %3

      %3 = apply %2(%1) : $@convention(method) (@thin NormalStruct.Type) -> NormalStruct // user: %5

      %4 = init_existential_addr %0 : $*SeedProtocol, $NormalStruct // user: %5

      store %3 to %4 : $*NormalStruct                 // id: %5

      // function_ref CallProtocol(_:)

      %6 = function_ref @ProtocolCase.CallProtocol(ProtocolCase.SeedProtocol) -> () : $@convention(thin) (@in_guaranteed SeedProtocol) -> () // user: %7

      %7 = apply %6(%0) : $@convention(thin) (@in_guaranteed SeedProtocol) -> ()

      destroy_addr %0 : $*SeedProtocol                // id: %8

      dealloc_stack %0 : $*SeedProtocol               // id: %9

      %10 = tuple ()                                  // user: %11

      return %10 : $()                                // id: %11

    } // end sil function 'ProtocolCase.DoTest() -> ()'

    五、补充说明

    Existential Container Layout

    Values of protocol type, protocol composition type, or Any type are laid out using existential containers (so-called because these types are "existential types" in type theory).

    Opaque Existential Containers

    If there is no class constraint on a protocol or protocol composition type, the existential container has to accommodate a value of arbitrary size and alignment. It does this using a fixed-size buffer, which is three pointers in size and pointer-aligned. This either directly contains the value, if its size and alignment are both less than or equal to the fixed-size buffer's, or contains a pointer to a side allocation owned by the existential container. The type of the contained value is identified by its type metadata record, and witness tables for all of the required protocol conformances are included. The layout is as if declared in the following C struct:

    struct OpaqueExistentialContainer {

      void *fixedSizeBuffer[3];

      Metadata *type;

      WitnessTable *witnessTables[NUM_WITNESS_TABLES];

    };

    Class Existential Containers

    If one or more of the protocols in a protocol or protocol composition type have a class constraint, then only class values can be stored in the existential container, and a more efficient representation is used. Class instances are always a single pointer in size, so a fixed-size buffer and potential side allocation is not needed, and class instances always have a reference to their own type metadata, so the separate metadata record is not needed. The layout is thus as if declared in the following C struct:

    struct ClassExistentialContainer {

      HeapObject *value;

      WitnessTable *witnessTables[NUM_WITNESS_TABLES];

    };

    Note that if no witness tables are needed, such as for the "any class" type protocol<class> or an Objective-C protocol type, then the only element of the layout is the heap object pointer. This is ABI-compatible with id and id <Protocol> types in Objective-C.

    https://github.com/apple/swift/blob/master/docs/ABI/TypeLayout.rst

  • 相关阅读:
    献给正在奋斗的人
    Delphi TRzTreeView 或者TRzCheckTree或者TTreeView离开焦点还显示灰色的选择状态
    笑话(三)
    王永庆建立企业奖励机制
    DbGridEh表格Tile居中,但是内容左对齐的做法
    DelPhi LockWindowUpdate的函数的用法
    Delphi DbgridEh实现鼠标拖动选中列,并使复选框选中
    国足输球,总结原因
    TPath
    TMemoryStream、String与OleVariant互转
  • 原文地址:https://www.cnblogs.com/feng9exe/p/10573980.html
Copyright © 2011-2022 走看看