Summary of Swift progress

Preface:

The previous article analyzed Pointers in Swift and the basic use of Pointers in Swift. This article mainly analyzed how methods are called in Swift, and method scheduling in Swift is divided into two types:

  • Static invocation (direct invocation)

  • Lookup calls (functions are stored sequentially in the Vtable and are called as address offset)

Static call

Functions on value objects are called statically (directly) dispatches (calls), or directly address calls (pointer calls), which means that the address of the current function has a fixed location in the Mach-O code segment after compilation and linking.

The typical value type in Swift is the structure, so we prove that the function call in the structure is static call through the following analysis.

Example, created in Xcode:

struct LGTeacher {
    func teach() {}
}
var t = LGTeacher()
t.teach()
print("end")
Copy the code

See function calls through assembly

In the assembly function call, it can be seen that the address 0x100002C10 is directly called by callq, so it can be seen that the Swift structure method call is directly distributed to the address

The Mach – O verification

Check whether the method is in the __text section in Mach -o:

As you can see from the above figure, the method’s storage address is in the __text section, so the verifiable function pointer is determined after compilation and linking, and stored in the code section

Symbol Table verification

  • To viewFunctions StartsRename all methods in theProject name + class name + function name

  • View the address offset of the symbol table

Function address :0000000100002C10, same as the address in assembly

  • View the Sting Table

  • Use terminal to view rename matches in the tables12NewSwiftDemo9LGTeacherV5teachyyFsymbol

  • Reduction of symbols

Dynamic dispatch

If there is a static dispatch, then of course there is a dynamic dispatch, which in Swift represents a function call in a class

Knowledge supplement

  • Assembly instruction supplement
  1. BLR: a jump instruction with a return that is followed by an address saved in a register
  2. Mov: to copy the value of a register to another register (used only between registers or constants, not memory addresses,mov x1,x0 to copy the value of register x0 to register X1)
  3. LDR: read the value from memory into register (LDR x0,[x1,x2] add register X1 and register X2 as the address, take the value of the memory address into register X0)
  4. STR: writes the value of register to memory (STR x0, [x0, x8] saves the value of register x0 to memory at [x0 + x8])
  5. Bl: Jumps to an address
  • Vtable profile

Swift vtable format in SIL file:

// Declare sil vtable keyword decl ::= SIL vtable contains keywords, identifiers (class names), all methods 2 SIL Vtable ::= 'sil_vtable' identifier '{' Sil-vtable-entry * '}' // The method contains the declaration and function name. 3 sil-vtable-entry ::= sil-decl-ref ':' SIL-linkage? sil-function-na meCopy the code

For LGTacher, the V-table in its SIL looks like this:

class LGTeacher{
    func teach(){}
    func teach2(){}
    func teach3(){}
    func teach4(){}
    @objc deinit{}
    init(){}
}
Copy the code

The function table can be understood as an array, and the methods declared inside the class are stored consecutively in our current address space without any keyword modification.

It can be seen from the above figure that the first address of the function table is a contiguous memory address

Source code analysis

Vtable memory storage mode is explored by assembly above, indicating that there must be a process of its creation in Vtable, open swift source code, global search:

It is encoded internally by the for loop, offset+index, and then gets the method, which is stored in the offset memory. From this, we can verify that the function is stored continuously. Therefore, for a class function, method scheduling is via v-taable. It’s essentially a contiguous memory space (array structure)

Methods in extension

Create LGTeacher extension

class LGTeacher{
    func teach(){}
    func teach1(){}
    func teach2(){}
    func teach3(){}
    func teach4(){}
}
extension LGTeacher {
    func teach5(){}
}
var t = LGTeacher()
t.teach5()
Copy the code

Look at the VTable method in the SIL file to see if it is saved to the function table during compilation

The extension method is not stored in the vtable table at compile time. View assembly code:

As can be seen from the figure above, the address of 0x100002B80 function directly callq by Extension belongs to static call.

Final, @objc, dynamic modifier functions

Create LGTeacher final,@objc,dynamic

class LGTeacher{
  final func teach(){}
    func teach1(){}
  @objc  func teach2(){}
    func teach3(){}
  dynamic  func teach4(){}
}
extension LGTeacher {
    func teach5(){}
}
var t = LGTeacher()
t.teach()
t.teach2()
t.teach4()
t.teach5()
Copy the code
  • final

View SIL file

We can see that the final modified function is not in vtable.

The final keyword modifiers directly callq are 0x100002b80 function addresses, which are static calls.

  • @bjc

In the sil file, we can see that @objc modifier still exists in the VTable.

For methods decorated with @objc, you actually generate two methods, one of which is our Swift native method and the other is the @objc method shown in the code above, and calls the Swift native method inside of it. So the essence of the @objc modifier is that the @objc method in sil code calls the method in Swift.

  • dynamic

In sil files, we can see that the methods that use the dynamic modifier are stored in the VTable. We don’t see any difference between swIF and swIF. Used with the @_dynamicreplacement keyword for method swapping

  • @objc + dynamic

Assembly breakpoint debugging:

You can see that the objc_msgSend process is followed, that is, dynamic message forwarding

conclusion

  • Method invocation in Swift is divided into static scheduling and dynamic scheduling

  • Methods in value types, such as structs, are statically scheduled

  • The method in the reference type is dynamic scheduling, where functions are scheduled through the V-table function Table, i.e., dynamic scheduling

  • Function scheduling in Extension and Final is static

  • The @objc modification of function scheduling is function table scheduling, and class must also inherit NSObject if it is needed in OC

  • Dynamic modifies functions that are scheduled in a function table manner, making the function dynamic

  • The scheduling method for methods that use both dynamic and @objc modifications is objc_msgSend