For an introduction and motivation into Embedded Swift, please see "A Vision for Embedded Swift", a Swift Evolution document highlighting the main goals and approaches.
The ABI of code generated by Embedded Swift is not currently stable. For a concrete compiler version, it will be consistent, but do not mix code built with different compiler versions.
Similarly, do not mix Embedded Swift code with full Swift code, as the ABIs are different. Details are described in the following sections.
Since Swift 5.0, the stable ABI mangling schema uses the $s
prefix on all Swift symbols. Because Embedded Swift's ABI differs from the stable ABI, and furthermore because it's not expected to be stable, Embedded Swift uses a $e
mangling prefix. The logic and structure of the mangling stays the same, the only difference is the prefix.
As of today, Embedded Swift has identical calling convention to full Swift. However, this does not need to continue in the future, and there should not be expectations that the ABI of Embedded Swift is compatible with full Swift.
The compiler respects the ABIs and calling conventions of C and C++ when interoperating with code in those languages. Calling C/C++ functions from Embedded Swift code is supported, and similarly exporting Swift code via @_extern
, @_cdecl
or @_expose
will match the right calling conventions that C/C++ expects.
Embedded Swift eliminates almost all metadata compared to full Swift. However, class and existential metadata are still used, because those serve as vtables and witness tables for dynamic dispatch of methods to implement runtime polymorphism with classes and existentials.
The layout of Embedded Swift's class metadata is different from full Swift:
- The super pointer pointing to the class metadata record for the superclass is stored at offset 0. If the class is a root class, it is null.
- The destructor pointer is stored at offset 1. This function is invoked by Swift's deallocator when the class instance is destroyed.
- The ivar destroyer is stored at offset 2. This function is invoked to destroy instance members when creation of the object is cancelled (e.g. in a failable initializer).
- Lastly, the vtable is stored at offset 3: For each Swift class in the class's inheritance hierarchy, in order starting from the root class and working down to the most derived class, the function pointers to the implementation of every method of the class in declaration order in stored.
The layout of Embedded Swift's witness tables is different from full Swift:
- The first word is always a null pointer (TODO: it can be eliminated)
- The following words are witness table entries which can be one of the following:
- A method witness: a pointer to the witness function.
- An associated conformance witness: a pointer to the witness table of the associated conformance
Note that witness tables in Embedded Swift do not contain associated type entries.
Witness functions are always specialized for concrete types. This also means that parameters and return values are passed directly (if possible).
Heap objects have the following layout in Embedded Swift:
- The isa pointer (pointer to the class metadata) is stored at offset 0.
- The refcount is stored inline at offset 1.
- Normal stored properties follow.