5.9 · Optimisation levels, closure contexts, ownership conventions and value layout
What the optimisation flags remove, where a closure keeps its captures, who owns an argument at a call, and how big Optional, enums and existentials really are.
Mental model. Four things you can measure instead of guessing: which checks a level keeps, stack or heap for a capture, +0 or +1 for an argument, and bytes for a value.
Levels and closures
What -O, -Osize and -Ounchecked change, and where captures live.
- What do -Onone, -O, -Osize and -Ounchecked each change, and which safety checks survive in a release build?
-Onone is the debug default: no optimisation, fast to compile, easy to step through. -O optimises for speed and is the usual release setting; -Osize prefers… - Where does a captured variable live: on the stack or in a heap box, and what decides it?
A closure is a function pointer plus a context holding what it captured. For a non-escaping closure the compiler knows the closure cannot outlive the call, so…
Ownership and layout
Argument conventions in SIL, and sizes of Optional, enums and existentials.
- What do @guaranteed and @owned mean in SIL, which does Swift use by default for parameters and initialisers, and how does that explain retain and release traffic?
Every parameter in SIL has an ownership convention. @guaranteed means the caller keeps ownership and guarantees the value stays alive for the whole call (a… - How big are Optional, enums and existentials in memory, and why is Int? nine bytes but Bool? and a class reference optional free?
Swift packs an enum’s case tag into spare bits or invalid values of its payload when it can. A class reference has an invalid value (null), so K? is 8 bytes.…
More in Compiler & language internals
- 5.1 · From source to machine code, and how to look inside
- 5.2 · Devirtualisation, whole-module optimisation, inlining, exclusivity
- 5.3 · Specialisation, witness tables, and opaque vs existential in the compiled code
- 5.4 · Library evolution, module interfaces, and the ABI boundary
- 5.5 · How Swift macros work, and the roles they play
- 5.6 · Why it compiles slowly, and what rebuilds
- 5.7 · Swift 6 language mode and upcoming features
- 5.8 · Symbol names, linkage, lazy globals and reflection metadata: what is in the binary
- 5.10 · What property wrappers, result builders, async and throws compile to
- 5.11 · Package access, SPI, internal imports, strict memory safety and pre-specialisation