Swift如何在机器代码级别实现扩展?

问题描述 投票:2回答:1

我现在正在搞弄LLVM,这个问题浮现在脑海:Swift如何在二进制级别实现扩展?

在Swift中,可以提供一个基本扩展,该扩展简单地添加了方法,但是它们也可以提供符合另一协议的扩展。然后,将该类识别为具有所述协议的父级,并且可以将它们相互转换。如何实现的?

我了解vtable,它们可以定义函数定义的位置,但据我所知,它们是固定长度的,对吗? Swift是否能够通过其运行时库实现此功能,或者将类型映射到较低级的LLVM,并在定义新扩展时以某种方式操纵vtable?

swift llvm extension-methods
1个回答
0
投票

您要查找的答案在Swift ABI documentation中,特别是在TypeMetadata.rstTypeLayout.rst中。

Swift使用称为见证表的vtable来处理协议一致性。对于每种类型,每种类型都有一个见证表,该见证表对于该协议所需的每个功能都有一个条目。

[当我们有一个类型为existential的变量(即不是静态已知的)时,Swift将该变量存储在称为existential container的运行时结构中。 TypeLayout.rst描述了存在容器的格式:

Opaque Existential Containers

如果协议或协议组成没有类别限制类型,存在容器必须容纳一个值任意大小和对齐方式。它使用固定大小的缓冲区执行此操作,这是三个大小和指针对齐的指针。这要么如果值的大小和对齐方式都较小,则直接包含该值等于或等于固定大小的缓冲区,或者包含指向存在容器拥有的边分配。的类型包含的值由其类型元数据记录标识,并见证包含所有必需协议一致性的表格。的布局就像在以下C结构中声明的一样:

struct OpaqueExistentialContainer {
  void *fixedSizeBuffer[3];
  Metadata *type;
  WitnessTable *witnessTables[NUM_WITNESS_TABLES];
};

witnessTables数组为我们的存在性已知为静态的每个协议包含一个条目-因此,如果我们的变量的类型为P1 & P2,则存在性将恰好包含两个见证表指针(一个存在性容器特定于其协议约束,因此将忽略具体类型所符合的任何其他协议)。只要我们有一个描述类型符合协议的见证表,我们就可以创建一个存在的容器,将其传递给它,然后使用见证表来调用协议方法。

那么我们如何通过扩展名为类型添加一致性?好吧,我们实际上不必修改类型本身的任何属性;我们只需要创建一个新的见证表。为了在存在类型之间实现动态转换,我们需要某种方式来向Swift运行时注册一致性。这是通过将协议一致性记录放在二进制文件的指定部分(运行时知道要在其中查找它)中完成的:

Protocol Conformance Records

A 协议一致性记录指出给定类型符合特定协议。协议一致性记录被发送到自己的部分,需要时由Swift运行时进行扫描(例如,响应swift_conformsToProtocol()查询)。每协议一致性记录包含:

  • protocol descriptor描述一致性的协议,表示为(可能是间接的)32位偏移量相对于领域。低位指示它是否是间接的抵消第二个最低位保留给以后使用。

  • conform type]的引用,表示为相对于该字段的32位偏移量。低两位指示类型表示为:

    • 0:直接引用标称类型描述符。
    • 1:对标称类型描述符的间接引用。
    • 2:保留供将来使用。
    • 3:对指向Objective-C类对象的指针的引用。
  • 见证表字段

  • 提供对描述一致性本身的见证表的访问,表示为直接32位相对偏移。低两位指示见证表是如何代表:
    • 0:见证表字段是对见证表的引用。
    • 1:见证表字段是对见证表访问器函数的无条件符合性的引用。
    • 2:见证表字段是对条件符合性的见证表访问器函数的引用。
    • 3:保留供将来使用。
  • 保留一个32位值供将来使用。

  • © www.soinside.com 2019 - 2024. All rights reserved.