Summary of Swift progress

Brief introduction:

This article mainly introduces the content:

  • SIL analysis

  • Class results explored

Swift Compilation

Create a simple class in Swift and instantiate it by default

class LGPerson {  
  var age: Int = 18  
  var name: String = "World"
}
let t = LGPerson()
Copy the code

The question is, what exactly does this instantiation do? So we introduced the Swift Intermediate Language (SIL), and before we read the SIL code, let’s take a look at what SIL is.

Both OC and Swift backends of iOS development are compiled using LLVM, as shown below:

You can see:

OC is compiled by the CLang compiler into IR, which is then regenerated into an executable file. O.

Swift is compiled into IR by Swift compiler and then generates executable files.

Let’s take a look at the steps taken to compile a Swift file:

The compilation process can be referred to: WWDC-2015 LLVM Video

SIL analysis

SIL common syntax commands

-dump-ast Syntax and type check, print ast syntax tree -dump-parse syntax check, Print AST syntax tree -dump-pCM dumps debugging information about precompiled Clang modules -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 outputs an LLVM BC file -emit-executable outputs an executable file -emit-imported-modules displays a list of imported modules -emit-ir O machine file -emit- PCM emit a precompiled Clang module from a module map Standard SIL file of SIB -emit-silgen Display original SIL file of SIB -emit-silgen display standard SIL file of SIB -emit- SIL display index-file Generate index data for source file -parse parse file -print-ast Parse file and print (nice/concise) syntax tree -resolve-imports parse import import file -typecheck check file typeCopy the code

For SIL syntax commands, see the SIL Documentation.

Complete the Swift test case you just created with the SIL command:

Open terminal command CD to project root directory:

  • View the abstract syntax tree:swiftc -dump-ast main.swift

  • Generate SIL files:swiftc -emit-sil main.swift >> ./main.sil, where the entry function of main is found in the root directory as followsCompiled. SilFile,VSCodeOpen the

  • fromSIL fileIn, it can be seen that the code is passedconfusionCan be restored through the following command tos4main1tAA8LGPersonCvpAs an example in

Terminal input :xcrun swift-demangle s4main1tAA8LGPersonCvp

S4main1tAA8LGPersonCvp represents the main.lgPerson class

Search s4main1tAA8LGPersonCvp to find the method to find the function based on the @thick parameter passed in main

  • Breakpoint debugging

Open Xcode, add _allocating_init breakpoint, use assembly debugging, and you can see the conclusion

What happens in Swift memory allocation, __allocating_init —–>swift_allocObject —–> _ swift_allocObject_ —–> swift_slowAlloc —–>Malloc

The source code to debug

Swift_allocObject Breakpoint debugging

Write the following code in terminal debugging (you can also copy it), search swift_allocObject, add a breakpoint, and define an instance object

_swift_allocObject_ source code analysis

Open the _swift_allocObject_ source code

  • Swift_slowAlloc source code analysis

Note: The swift_slowAlloc method is systematically commented, please check it out

  • HeapObject source code analysis

Find the HeapObject source code, enter the heapObject. h file, find the HeapObject initialization

  1. The metadata type is HeapMetadata, which is a pointer type and occupies 8 bytes

  2. RefCounts (reference counts of type InlineRefCounts, which is an 8-byte alias of class refCounts), Swift uses arc reference counts

  3. In this case, object is a strong HeapObject type, which is actually an object pointer to the memory space, and HeapObject needs to be initialized using metadata

Conclusion:

  • Swift class creation process:

  • Viewing memory size

    ********* @frozen public struct Int: FixedWidthInteger, SignedInteger {… }

    / / * * * * * * * * * the String to the underlying definition * * * * * * * * * @ frozen public struct String {… }

    / / * * * * * * * * * verify * * * * * * * * * print (MemoryLayout. Stride) print (MemoryLayout. Stride)

    //********* The result is printed ********* 8 16

  • conclusion

As you can see from the printed result, Int takes up 8 bytes and String takes up 16 bytes (more on that later), which is different from OC

So this explains why LGPerson’s memory size is equal to 40, i.e. 40 = metadata (8 bytes) +refCount (8 bytes) + Int (8 bytes) + String (16 bytes)

Explore the composition of the Swift class

Enter the HeapObject structure:

RefCount = InlineRefCounts->RefCounts Swift also uses ARC for memory management

Enter the TargetHeapMetaData definition, which is essentially a template type that defines some of the required data structures. This structure has no attributes, only an initializer that passes in a MetadataKind parameter (the structure doesn’t have one, so it’s only in the parent class) where kind is passed in as an Inprocess

Thus it can be seen that:

  1. Swift classNature isHeapObject
  2. HeapObjectThe default size is16 bytes:metadata(struct)8 bytesandrefCounts(class)8 bytes
  3. LGPersontheage(Int)8 bytes.name(String)16 bytes

Continue looking at the TargetMetadata structure and look at getClassObject

Look for the getClassObject implementation

To sum up, when metadata kind is Class, there is the following inheritance chain

The attributes stored in memory before the Class consist of the TargetClassMetadata attribute + TargetAnyClassMetaData attribute + TargetMetaData attribute, so the resulting metadata data structure is shown as follows

struct swift_class_t: NSObject{ void *kind; // Equivalent to isa in OC, the actual type of kind is unsigned long void *superClass; void *cacheData; void *data; uint32_t flags; //4 bytes uint32_t instanceAddressOffset; //4 bytes uint32_t instanceSize; //4 bytes uint16_t instanceAlignMask; //2 bytes uint16_t reserved; //2 bytes uint32_t classSize; // uint32_t classAddressOffset; //4 bytes void *description; . }Copy the code

Once the structure analysis of this class is complete, the next chapter examines the class’s attributes & attribute observer and lazy attributes