“This is the 11th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
IOS development language, no matter OC or Swift, is compiled through LLVM, and finally generates.o files. The compilation process is shown as follows:
OC
throughclang
Compiler, compiles toIR
, and then regenerate it into an executable file.o
(our machine code);Swift
bySwift
Compiler generationIR
, and then regenerate it into an executable file.o
;
Swift Compilation process
Swift language compilation flow chart is as follows:
Swift
The code through-dump-parse
Command toSyntax analysis
To generate theAbstract syntax tree AST
;Abstract syntax tree
through-dump-ast
forSemantic analysis
(such as type checking for correctness and security);Semantic analysis
After that,Swift
The code will be degraded toSIL
, that is,Swift intermediate language
(Swift Intermediate Language);SIL
Divided intoRaw SIL
(native, no optimization option enabled) andSILOpt Canonical SIL
Optimized;- Finally through
LLVM
Downgraded toIR
, and then compiled into different architectures through the following codeMachine code
;
The commands involved are as follows:
Swiftc main. Swif-dump-parse // Analyze and check the type of output AST swiftc main. Swif-dump-ast // generate intermediate language (SIL), Swiftc main. Swift - EMIT - Silgen // Generate intermediate Language (SIL) Swift-emit -sil // Generates LLVM intermediate language (.ll file) swifTC main. Swift-emit -ir // generates LLVM intermediate language (.bc file) swifTC Swift -emit-assembly // Compilation generates executable. Out file swiftc-o main.o main.swiftCopy the code
In the OC, there is a security check for our code with SIL, as opposed to SIL.
The int8_t type we defined will fail because int8_t is only one byte and its result has been overflowed, giving an incorrect result in OC; Let’s look at what happens in Siwft:
As we have seen, the same code in Swift will report an error at compile time, avoiding unpredictable errors later; This is all because of SIL;
SIL file analysis
So what are the syntax rules for SIL? Let’s generate a SIL file for analysis; Let’s start with a simple code:
Next we generate this code into a SIL file:
For viewing purposes, we can also output sil files as main.sil files using the swiftc main.swift-emma-sil >./main.sil command.
Due to the large SIL file, we select only the important parts for analysis:
The Teacher’s statement
First, let’s take a look at Teacher’s declaration in the SIL phase:
As you can see from the Teacher definition, there are initialized storage attributes age and name, a deinit function identified as @objc, and the default initializer init();
The main function
@main
: identifies the entry function inSIL
In the@
As aidentifier
;% 0
—% 9
: it’s written in the bookSIL
Is also known asregister
, can be understood as a constant during the development process. Once assigned, it cannot be changed again. It’s important to note that hereregister
isVirtual register
When running on a specific device, the real one will be usedregister
;alloc_global @$s4main1tAA7TeacherCvp
: Assigns a global variable whose name isMix writing
Yes, we can use terminal commandsxcrun swift-demangle
Restore it:
You can see that this corresponds to the t variable in main and Teacher in main.
%3 = global_addr @$s4main1tAA7TeacherCvp
: to get theThe global variable
The address to% 3
;%4 = metatype $@thick Teacher.Type
: getTeacher.Type
The metatype of% 4
;- According to the notes
% 5
isTeacher.__allocating_init()
A reference to a function, that is, its pointer address; %6 = apply %5(%4)
Will:% % 5 (4)
The result of theta is thetaTeacher
To the instance variable of% 6
;store %6 to %3
Will:% 6
Which is the memory address of the instance variable% 3
In this global variable;- in
Swift
In the bottomInt
Is aStruct
Type,% 8
and% 9
It’s building aInt32
Integer type of0
Similar to usOC
In themain
Function finalreturn 0
;
For SIL syntax rules, see the official SIL documentation
__allocating_init () function
In the SIL code above, s4main7TeacherCACycfC (teach.__allocating_init ()) is called to create the current instance object. We locate this function in SIL:
- The function needs one
Teacher.Type
, which we can understand asisa
; %1 = alloc_ref $Teacher
:alloc_ref
Will create aTeacher
Of the instance variable whose reference count is initialized to1
;alloc_ref
In fact, that is to goThe heap area
Apply for memory space; If identified asobjc
theSwift class
Will useObjective-C
the+allocWithZone:
Initialization method; How do you test that? We add the following breakpoint to our code:
Run the program to view the assembly instruction:
We see that the teach.__allocating_init () function will be called, so how is this function implemented? Breakpoint to enter the function:
Swift_allocObject and teacher.init () are mainly called in __allocating_init();
swift_allocObject
Find the appropriate memory space in the heap to initialize;Teacher.init()
Initialize a member variable;
This is a pure Swift class, so what happens if we inherit Teacher from NSObject?
We repeat the assembly debugging steps above and enter the teach.__allocating_init () function:
We see that the initialization function becomes objc_allocWithZone and objc_msgSend;
objc_allocWithZone
callmalloc
Function to request memory space;objc_msgSend
sendinit
Message;
swift_allocObject
Swift_allocObject is called during initialization of the Swift class. What does this function do? We need to use Swift source code for analysis; Find the stdlib->public-> Runtime -> heapObject. CPP file in this directory, which is related to our Swift class initialization; In this file locate the _swift_allocObject_ function, which is a private function called by swift::swift_allocObject:
_swift_allocObject_ is implemented as follows:
This function takes three arguments:
HdapMetadata const *metadata
: Metadata type;requiredSize
: Required size;requiredAlignmentMask
: Specifies the mask required for alignmentobjc
That is, the source code7
Because is8
Byte alignment;
RequiredSize and requiredAlignmentMask are passed to the swift_slowAlloc function, which returns a pointer of type HeapObject; Reinterpret_cast is used to perform a pointer type conversion;
new (object) HeapObject(metadata)
:HeapObject
Initialization;
So what is swift_slowAlloc used for?
swift_slowAlloc
Its implementation is as follows:
In swift_slowAlloc, malloc is called to open up memory;
The process to summarize
So, we can roughly summarize the process of memory allocation for Swift objects:
- It first calls
_allocating_init()
: This function hasThe compiler
Generated; - For pure
Swift
The class will be called againswift_allocObject()
Functions; - Then, in
swift_allocObjec()
Private functions are always called_swift_allocObject
; - And then through the function
swift_slowAlloc
callmalloc
To apply forThe heap area
Memory space;