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.

  1. What do -Onone, -O, -Osize and -Ounchecked each change, and which safety checks survive in a release build? 5.9.1 · L3
    -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…
  2. Where does a captured variable live: on the stack or in a heap box, and what decides it? 5.9.2 · L5
    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.

  1. 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? 5.9.3 · L5
    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…
  2. How big are Optional, enums and existentials in memory, and why is Int? nine bytes but Bool? and a class reference optional free? 5.9.4 · L5
    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