Generating SIL files
Since the SIL generation article was covered last time, let’s briefly examine the SIL file. Type the same code as last time in main.swift:
import Foundation
class Teacher {
var age: Int = 18
var name: String = "Tom"
}
var person = Teacher()
person.age = 6
Copy the code
View it after generating the main.sil file
Declare the Teacher class
When you open the file, the first thing you see is the Teacher’s statement:
class Teacher {
@_hasStorage @_hasInitialValue var age: Int { get set }
@_hasStorage @_hasInitialValue var name: String { get set }
@objc deinit
init(a)
}
@_hasStorage @_hasInitialValue var person: Teacher { get set }
// person
sil_global hidden @main.person : main.Teacher : $Teacher
Copy the code
@_hasStorage
Represents a storage property@_hasInitialValue
That means it has an initial value@sil_global
Represents a global variable
Here we declare the Teacher class and define a global person attribute that belongs to the Teacher class
The main function
Every program starts with main, swift is no exception, but the main function in Swift is hidden. The main. Swift file represents the entire main function, and the code written in the file is run in main.
Let’s look at the main function in the SIL file
Int main(int argc, char * argv[])
sil @main : $@convention(c) (Int32.UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8- > > > >)Int32 {
bb0(%0 : $Int32.%1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) :// Initialize the global variable person
alloc_global @main.person : main.Teacher // id: %2
// Create a reference to the address of the global variable previously initialized by alloc_global
%3 = global_addr @main.person : main.Teacher : $*Teacher // users: %7, %8
// Teacher
%4 = metatype $@thick Teacher.Type // user: %6
// a reference to the __allocating_init() method
%5 = function_ref @main.Teacher.__allocating_init() -> main.Teacher : $@convention(method) (@thick Teacher.Type) - >@owned Teacher // user: %6
// Call the function __allocating_init and pass in the argument element type Teacher
%6 = apply %5(%4) : $@convention(method) (@thick Teacher.Type) - >@owned Teacher // user: %7
// Store the result of the __allocating_init function into a reference to person
store %6 to %3 : $*Teacher // id: %7
// Start accessing a reference to the global variable address
%8 = begin_access [read] [dynamic] %3 : $*Teacher // users: %9, %11
// Load the contents into %9
%9 = load %8 : $*Teacher // users: %16, %14, %15, %10
// Add one to the reference count
strong_retain %9 : $Teacher // id: %10
// End the visit
end_access %8 : $*Teacher // id: %11
// Create the literal 6
%12 = integer_literal $Builtin.Int64.6 // user: %13
// Generate an Int value of 6. In swift Int is a structure
%13 = struct $Int (%12 : $Builtin.Int64) / /user: % 15 / /Teacher.agethesetterMethods 14 = %class_method %9 : $Teacher#,Teacher.age!setter : (Teacher) - > (Int) - > (),$@convention(method) (IntThe @guaranteed Teacher) - > () / /user: %15 // callsetterMethod, passed inIntValue 6, and the class instance itself %15 =apply13, 14 (% % % 9) :$@convention(method) (IntThe @guaranteed Teacher) -> () // The reference count is reduced by onestrong_release%9 :// Create literal 0 %17 =integer_literal $Builtin.Int32, 0 / /user: %18 // GeneratedIntThe value of 0,swiftIn theIntIs the structure %18 =struct $Int32 (%17 : $Builtin.Int32) / /user: %19 // Finally 0 frommainFunction returns outreturn %18 : $Int32 $Teacher // idCreate literal 0 %17 =integer_literal $Builtin.Int32, 0 / /user: %18 // GeneratedIntThe value of 0,swiftIn theIntIs the structure %18 =struct $Int32 (%17 : $Builtin.Int32) / /user: %19 // Finally 0 frommainFunction returns outreturn %18 : $Int32 // id19: %} / /end sil function 'main'
Copy the code
The main function basically does what we wrote, creating an instance of Teacher via alloc_init and assigning 6 to setter methods of age. But there are a lot of details, like the retain and release methods that Xcode automatically added to show up, a simple 6 that is struct initialized, and so on.
Here are some set collocations:
- Initialize a reference
// Initialize the global variable person
alloc_global @main.person : main.Teacher
// Create a reference to the address of the global variable previously initialized by alloc_global
%3 = global_addr @main.person : main.Teacher
Copy the code
- Calling a method
// a reference to the __allocating_init() method
%5 = function_ref @main.Teacher.__allocating_init() -> main.Teacher : $@convention(method) (@thick Teacher.Type) - >@owned Teacher
// Call the function __allocating_init and pass in the argument element type Teacher
%6 = apply %5(%4) : $@convention(method) (@thick Teacher.Type) - >@owned Teacher
Copy the code
- Get the basic type of swFIT
// Create the literal 6
%12 = integer_literal $Builtin.Int64.6
// Generate an Int value of 6. In swift Int is a structure
%13 = struct $Int (%12 : $Builtin.Int64)
Copy the code
These are not commented in detail
Explore alloc init
An implementation of this method can be found by searching the SIL file for @main.teacher.__allocating_init () as found in the main function:
// Teacher.__allocating_init()
sil hidden [exact_self_class] @main.Teacher.__allocating_init() -> main.Teacher : $@convention(method) (@thick Teacher.Type) - >@owned Teacher {
// %0 "$metatype"
bb0(%0 : $@thick Teacher.Type) :// Assign an object with a reference of type Teacher
%1 = alloc_ref $Teacher // user: %3
// function_ref Teacher.init()
// Call init
%2 = function_ref @main.Teacher.init() -> main.Teacher : $@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 'main.Teacher.__allocating_init() -> main.Teacher'
Copy the code
This method is relatively simple. First, allocate space to the reference object, and then call init on the reference object.
// Teacher.init()
sil hidden @main.Teacher.init() -> main.Teacher : $@convention(method) (@owned Teacher) -> @owned Teacher {
// %0 "self" // users: %18, %14, %4, %1
bb0(%0 : $Teacher):
debug_value %0 : $Teacher, let, name "self", argno 1 // id: %1
// Initialize age to 18
%2 = integer_literal $Builtin.Int64, 18 // user: %3
%3 = struct $Int (%2 : $Builtin.Int64) // user: %6
%4 = ref_element_addr %0 : $Teacher, #Teacher.age // user: %5
%5 = begin_access [modify] [dynamic] %4 : $*Int // users: %6, %7
store %3 to %5 : $*Int // id: %6
end_access %5 : $*Int // id: %7
// Initialize name to Tom
%8 = string_literal utf8 "Tom" // user: %13
%9 = integer_literal $Builtin.Word, 3 // user: %13
%10 = integer_literal $Builtin.Int1, - 1 // user: %13
%11 = metatype $@thin String.Type // user: %13
// function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
%12 = function_ref @Swift.String.init(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %13
%13 = apply %12(%8%,9%,10%,11) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %16
%14 = ref_element_addr %0 : $Teacher, #Teacher.name // user: %15
%15 = begin_access [modify] [dynamic] %14 : $*String // users: %16, %17
store %13 to %15 : $*String // id: %16
end_access %15 : $*String // id: %17
return %0 : $Teacher // id: %18
} // end sil function 'main.Teacher.init() -> main.Teacher'
Copy the code
The init method looks long, but it actually does two properties. Note that assignment calls the store directly, not the setter method called.
Assembly validation
We can set a sign breakpointTeacher.init
And then runWe can see that the stack above meets the expectations of the analysis, and we point to__allocating_init
Look at theWe can see the allocation space callswift_allocObject
So that we can locate the Swift source and see the structure of the class. We will analyze this later.
fromswift_allocObject
Analyze the composition of a Class