美文网首页
swift--类

swift--类

作者: Mjs | 来源:发表于2020-12-10 13:48 被阅读0次

iOS开发的语⾔不管是 OC 还是 Swift 后端都是通过 LLVM 进⾏编译的,如下图所示:


LLVM.png

可以看到:

OC 通过 clang 编译器,编译成IR,然后再⽣成可执⾏⽂件.o(这⾥也就是我们的机器码)

Swift 则是通过 Swift编译器 编译成IR,然后在⽣成可执⾏⽂件。

我们再来看⼀下,⼀个 ⽂件的编译过程都经历了哪些步骤:

Swift编译过程.png
swift 在编译过程中使⽤的前端编译器是 swiftc ,和我们之前在 OC 中使⽤的 Clang 是有所区别的。 我
们可以通过如下命令查看 swiftc 都能做什么样的事情:
swiftx -h
USAGE: swiftc

MODES:
  -dump-ast              Parse and type-check input file(s) and dump AST(s)
  -dump-parse            Parse input file(s) and dump AST(s)
  -dump-pcm              Dump debugging information about a precompiled Clang module
  -dump-scope-maps <expanded-or-list-of-line:column>
                         Parse and type-check input file(s) and dump the scope map(s)
  -dump-type-info        Output YAML dump of fixed-size types from all imported modules
  -dump-type-refinement-contexts
                         Type-check input file(s) and dump type refinement contexts(s)
  -emit-assembly         Emit assembly file(s) (-S)
  -emit-bc               Emit LLVM BC file(s)
  -emit-executable       Emit a linked executable
  -emit-imported-modules Emit a list of the imported modules
  -emit-ir               Emit LLVM IR file(s)
  -emit-library          Emit a linked library
  -emit-object           Emit object file(s) (-c)
  -emit-pcm              Emit a precompiled Clang module from a module map
  -emit-sibgen           Emit serialized AST + raw SIL file(s)
  -emit-sib              Emit serialized AST + canonical SIL file(s)
  -emit-silgen           Emit raw SIL file(s)
  -emit-sil              Emit canonical SIL file(s)
  -index-file            Produce index data for a source file
  -parse                 Parse input file(s)
  -print-ast             Parse and type-check input file(s) and pretty print AST(s)
  -resolve-imports       Parse and resolve imports in input file(s)
  -typecheck             Parse and type-check input file(s)

SIL分析

class Teacher{
    var age:Int = 18
    var name:String = "abc"
}
var t = Teacher()   //OC:alloc(内存分配) init(初始化)

通过swiftc -emit-sil main.swift >> ./main.sil编译

// t
sil_global hidden @$s4main1tAA7TeacherCvp : $Teacher

// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @$s4main1tAA7TeacherCvp            // id: %2
  %3 = global_addr @$s4main1tAA7TeacherCvp : $*Teacher // user: %7
  %4 = metatype $@thick Teacher.Type              // user: %6
  // function_ref Teacher.__allocating_init()
  %5 = function_ref @$s4main7TeacherCACycfC : $@convention(method) (@thick Teacher.Type) -> @owned Teacher // user: %6
  %6 = apply %5(%4) : $@convention(method) (@thick Teacher.Type) -> @owned Teacher // user: %7
  store %6 to %3 : $*Teacher                      // id: %7
  %8 = integer_literal $Builtin.Int32, 0          // user: %9
  %9 = struct $Int32 (%8 : $Builtin.Int32)        // user: %10
  return %9 : $Int32                              // id: %10
} // end sil function 'main'

这里粘贴了些主要内容

  • @main 这⾥标识我们当前 main.swift 的⼊⼝函数,SIL 中的标识符名称以 @ 作为前缀
  • %0, %1... 在 SIL 也叫做寄存器,这⾥我们可以理解为我们⽇常开发中的常量,⼀旦赋值之后就不可以再修改,如果 SIL 中还要继续使⽤,那么就不断的累加数字。 同时这⾥所说的寄存器是虚拟的,最终运⾏到我们的机器上,会使⽤真的寄存器。
  • alloc_global创建⼀个全局变量
  • global_addr拿到全局变量的地址,赋值给 %3
  • metatype拿到TeacherMetadata 赋值给 %4
  • allocation_init的函数地址赋值给 %5
  • apply调⽤allocation_init, 并把返回值给 %6
  • 将 %6 的值存储到 %3(也就是我们刚刚创建的全局变量的地址)
  • 构 建 Int , 并 return
    alloc_global @$s4main1tAA7TeacherCvp 定义一个全局的变量,我们可以通过命令xcrun swift-demangle s4main1tAA7TeacherCvp查看其实就是下面
$s4main1tAA7TeacherCvp ---> main.t : main.Teacher

%0%1相当于虚拟的寄存器。相当于常量。所以这段意思也就是5%为初始化方法,将元类型放进去,然后得出结果6%放入全局变量3%。初始化一个实例变量地址赋值给全局变量。
5%的方法s4main7TeacherCACycfC

// Teacher.__allocating_init()
sil hidden [exact_self_class] [ossa] @$s4main7TeacherCACycfC : $@convention(method) (@thick Teacher.Type) -> @owned Teacher {
bb0(%0 : $@thick Teacher.Type):
  %1 = alloc_ref $Teacher                         // user: %3  //堆上分配内存空间
  // function_ref Teacher.init()
  %2 = function_ref @$s4main7TeacherCACycfc : $@convention(method) (@owned Teacher) -> @owned Teacher // user: %3
  %3 = apply %2(%1) : $@convention(method) (@owned Teacher) -> @owned Teacher // user: %4
  return %3 : $Teacher                            // id: %4
} // end sil function '$s4main7TeacherCACycfC'

指令解释

我们在这里看到了__allocating_init方法,在xcode中添加条件断点。


    0x100001c04 <+20>: callq  0x100001d58               ; symbol stub for: swift_allocObject
    0x100001c09 <+25>: movq   %rax, %r13
    0x100001c0c <+28>: callq  0x100001c40               ; swiftTest.Teacher.init() -> swiftTest.Teacher at main.swift:11

__allocating_init里调用了swift_allocObject
我们去swift源码中找到 _swift_allocObject方法

_swift_allocObject_.png
开辟空间,根据metadata创建HeapObject对象
  InlineRefCounts refCounts

/// The Swift heap-object header.
/// This must match RefCountedStructTy in IRGen.
struct HeapObject {
  /// This is always a valid pointer to a metadata object.
  HeapMetadata const *metadata;

  SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;

#ifndef __swift__
  HeapObject() = default;

  // Initialize a HeapObject header as appropriate for a newly-allocated object.
  constexpr HeapObject(HeapMetadata const *newMetadata) 
    : metadata(newMetadata)
    , refCounts(InlineRefCounts::Initialized)  //引用计数
  { }
  

Swift对象的内存结构HeapObject,有两个属性: ⼀个是Metadata,⼀个是RefCount,默认占⽤16字节⼤⼩
Int 8字节

print(MemoryLayout<String>.stride)
·····················
16

我们可以看到String占用的内存时16
所以最后占用了40字节大小。

类结构探索

using HeapMetadata = TargetHeapMetadata<InProcess>;

HeapMetadata其实是TargetHeapMetadata,而TargetHeapMetadata里面并没有属性,找到他的父类TargetMetadata

private:
  /// The kind. Only valid for non-class metadata; getKind() must be used to get
  /// the kind value.
  StoredPointer Kind;

只有一个属性StoredPointerkind,这里记录这什么类型的元数据。
从方法里去寻找


  /// Get the class object for this type if it has one, or return null if the
  /// type is not a class (or not a class with a class object).
  const TargetClassMetadata<Runtime> *getClassObject() const;

继承链为TargetClassMetadata -->TargetAnyClassMetadata-->TargetHeapMetadata-->TargetMetadata

经过源码的阅读,我们应该能得出当前 metadata 的数据结构体了

struct swift_class_t: NSObject{
void *kind; //isa, kind(unsigned long)
void *superClass;
void *cacheData
void *data
uint32_t flags; //4
uint32_t instanceAddressOffset; //4
uint32_t instanceSize;//4
uint16_t instanceAlignMask; //2
uint16_t reserved; //2 11
uint32_t classSize; //4
uint32_t classAddressOffset; //4
void *description; 
    // ...
 };

相关文章

  • swift--类

    类的属性 1.存储属性:存储常量和变量 2.计算属性:通过某种方式计算出来的属性 3.类的属性:与整个类目相关联的...

  • swift--类

    iOS开发的语⾔不管是 OC 还是 Swift 后端都是通过 LLVM 进⾏编译的,如下图所示: 可以看到: OC...

  • Swift--类继承

    继承概念 构造函数继承 重写 类型检查与转换 在Swift中,类的继承只能是单继承,而多继承可以通过遵从多个协议实...

  • Swift4.0--一个好用的金融类游标卡尺

    Swift--一个好用的金融类游标卡尺 思路:使用UICollectionView制作一个游标卡尺,每一个cell...

  • The Awesome Raywenderlich.com: 经

    Swift--弹性动画--Swift Swift--CALayer 教程: Getting Started超棒的源...

  • Swift--类和结构体

    类是引用类型 类是引用类型,结构体和枚举是值类型 特征运算符 为了比较两个类实例是否是同一个实例,引入===和!=...

  • Swift--结构体和类

    结构体 在Swift标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分 比如Bool、Int、Dou...

  • Swift--类的生命周期

    iOS开发的语言不管是OC还是Swift后端都是通过LLVM进行编译的,如下图: OC通过clang编译器,编译成...

  • swift--字典

    字典的介绍 1.字典允许按照某个键访问元素 2.字典是由两部分组成,一个键(key)集合,一个是值(value)集...

  • swift--元组

网友评论

      本文标题:swift--类

      本文链接:https://www.haomeiwen.com/subject/ckwzwktx.html