5.8 · Symbol names, linkage, lazy globals and reflection metadata: what is in the binary

The compiled module has names, visibility and tables of its own: how a declaration becomes a symbol, why an unused internal function can vanish, when a global is initialised, and what the reflection tables cost and enable.

Mental model. Source-level access control becomes linkage, source names become mangled symbols, and a type also leaves metadata behind. Each of those is something you can look at.

Names and visibility

How a declaration is named in the object file, and which ones survive.

  1. What is name mangling in Swift, how do you read a symbol such as $s4Main3FooV3baryyF, and where do you meet mangled names in practice? 5.8.1 · L5
    Swift has overloading, generics, modules and nested types, so a plain name cannot identify a function in an object file. The compiler builds a mangled name…
  2. How do access levels become linkage in the object file, and why can an unused internal function disappear in a release build but a public one cannot? 5.8.2 · L5
    The compiler maps access control onto symbol visibility. public and open declarations are exported: they stay in the module’s API, keep a default-visibility…

Initialisation and metadata

When globals run, and what reflection tables ship.

  1. When is a Swift global or static property initialised, what is swift_once, and when does the optimiser make the initialiser disappear? 5.8.3 · L5
    Globals and static let properties in a normal file are lazy: the initialiser runs the first time the value is read, exactly once, even if several threads race.…
  2. What reflection metadata does the compiler emit for every type, what depends on it, and what does -disable-reflection-metadata do? 5.8.4 · L5
    For each struct, class and enum the compiler emits field descriptors: tables of stored-property names and types, in sections such as __swift5_fieldmd and…

More in Compiler & language internals