<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">I’m trying to plan out changes to our type metadata record formats for ABI stability. I’ll start by looking at the current situation and then make suggestions about things we ought to change. We want to settle on a design that leaves room for future expansion and runtime changes, and still allows efficient access to the most frequently-accessed parts of metadata. I’ll be looking exclusively at metadata records themselves for this message, leaving other data structures for separate scrutiny. I'd appreciate all your feedback.</p><h1 id="abiconcernsfortypemetadatarecords" style="font-size: 37px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">ABI concerns for type metadata records</h1><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">These are the primary ways in which the compiler and runtime are exposed to direct binary layout of metadata records:</p><ol style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; list-style-position: inside; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">The compiler generates metadata records for some types, either as static data that’s expected to be directly usable as a type metadata record, or a&nbsp;<em style="line-height: 1;" class="">pattern</em>&nbsp;for a metadata record that’s fed as input to an instantiation process.</li><li style="font-size: 16.5px;" class="">The compiler generates code that interacts with metadata records. It generates&nbsp;<strong style="line-height: 1;" class="">metadata accesses</strong>&nbsp;to form the metadata pointer for a specific type. It also&nbsp;<strong style="line-height: 1;" class="">projects</strong>&nbsp;information out of metadata records of a known kind. This can take the form either of runtime calls or of direct projection into known offsets inside the metadata record, making a tradeoff between abstracting binary layout details and performance of generated code.</li></ol><h2 id="1compiler-generatedmetadatarecords" data-orig-id="1.compiler-generatedmetadatarecords" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">1. Compiler-generated metadata records</h2><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class=""><div style="word-wrap: break-word; margin: 0px; line-height: 1.3125em;" class="">For concrete&nbsp;<strong style="line-height: 1;" class="">struct</strong>&nbsp;and&nbsp;<strong style="line-height: 1;" class="">enum</strong>&nbsp;types, the compiler generates a metadata record as static data. If the type has known layout (no resilient fields), then the metadata record is expected to be usable as valid metadata as-is. If the type has unknown layout, the metadata record requires one-time initialization to become valid metadata.</div></li><li style="font-size: 16.5px;" class=""><div style="word-wrap: break-word; margin: 0px; line-height: 1.3125em;" class="">For concrete&nbsp;<strong style="line-height: 1;" class="">class</strong>&nbsp;types, the compiler generates a metadata record as static data. If the class is&nbsp;<code style="line-height: 1;" class="">@objc</code>, a pointer into this metadata record is also exported as the Objective-C class symbol for Objective-C binaries to link against. Class metadata records always require one-time initialization to become valid metadata because of, at minimum, Objective-C class realization. (On platforms without Objective-C interop, a concrete class with a fully concrete, non-resilient ancestry and no resilient fields could be made usable as-is as valid metadata.)</div></li><li style="font-size: 16.5px;" class=""><div style="word-wrap: break-word; margin: 0px; line-height: 1.3125em;" class="">For&nbsp;<strong style="line-height: 1;" class="">generic</strong>&nbsp;types, the compiler generates a&nbsp;<strong style="line-height: 1;" class="">generic metadata pattern</strong>. The&nbsp;<code style="line-height: 1;" class="">swift_getGenericMetadata</code>&nbsp;runtime function takes a pointer to a generic metadata pattern and a list of generic arguments and produces a valid metadata record for the generic type instantiated with those arguments.</div></li><li style="font-size: 16.5px;" class=""><div style="word-wrap: break-word; margin: 0px; line-height: 1.3125em;" class="">For&nbsp;<strong style="line-height: 1;" class="">Clang-imported</strong>&nbsp;types, the compiler generates a&nbsp;<strong style="line-height: 1;" class="">metadata candidate</strong>. This looks like a metadata record, with an added uniquing prefix. The&nbsp;<code style="line-height: 1;" class="">swift_getForeignMetadata</code>&nbsp;runtime function picks a metadata record to be the canonical metadata pointer, and performs one-time initialization if required.</div></li></ul><h2 id="2metadatacodegeneration" data-orig-id="2.metadatacodegeneration" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">2. Metadata code generation</h2><h3 id="abiconcernsforallmetadata" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">ABI concerns for all metadata</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler makes the following assumptions about all type metadata records:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Every formal Swift type has a corresponding type metadata record at a unique address, so pointer identity can be used to test type identity.&nbsp;<code style="line-height: 1;" class="">metadataPointerA == metadataPointerB</code>&nbsp;if and only if&nbsp;<code style="line-height: 1;" class="">metadataPointerA</code>&nbsp;and&nbsp;<code style="line-height: 1;" class="">metadataPointerB</code>&nbsp;represent the exact same formal type.</li><li style="font-size: 16.5px;" class="">The value witness table can be loaded at fixed offset&nbsp;<code style="line-height: 1;" class="">-1*sizeof(Int)</code>&nbsp;from the address point.</li></ul><h3 id="classes" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Classes</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler accesses concrete class metadata by calling&nbsp;<code style="line-height: 1;" class="">swift_getInitializedObjCClass</code>&nbsp;to perform one-time initialization of the metadata. Generic class metadata is instantiated using<code style="line-height: 1;" class="">swift_getGenericMetadata</code>, and the template is responsible for initialization of the generated class object.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">A subclass’s metadata record serves as a physical subtype of its parent class metadata record. Any projection pattern that works on the parent class metadata should also work equivalently on the subclass metadata, allowing for overrides of methods and other entries where the subclass customizes behavior.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">For all classes, the compiler expects access to the following fields:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Destructor</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">fixed offset&nbsp;<code style="line-height: 1;" class="">-2*sizeof(Int)</code></td></tr><tr style="border-spacing: 0px; background-color: rgba(200, 200, 200, 0.247059);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(255, 255, 255, 0.0588235);" class="">ObjC matter</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">fixed offset&nbsp;<code style="line-height: 1;" class="">(0...4)*sizeof(Int)</code></td></tr><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Nominal type descriptor</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">[1]</td></tr><tr style="border-spacing: 0px; background-color: rgba(200, 200, 200, 0.247059);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(255, 255, 255, 0.0588235);" class="">Generic arguments</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">[1]</td></tr><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Stored property offsets</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">[1]</td></tr></tbody></table><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">[1] For classes with fully-fragile ancestry, generic arguments and stored property offsets can be loaded at a fixed offset determined by the compiler. If the class has any resilient ancestry, such as a base class from another module, then the base offset into the subclass’s own entries must be determined at instantiation time and loaded indirectly.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">For classes with fully-fragile ancestry, the compiler can also emit fixed offset accesses for vtable entries.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The metadata currently includes field offsets for all stored properties, but this should be changed to include only the fields with offsets that are dependent on the struct’s generic arguments.</p><h3 id="structs" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Structs</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler accesses concrete, known-layout struct metadata by direct reference to the global symbol. If the struct contains resilient fields, the metadata is accessed through a runtime call for one-time initialization. Generic struct metadata is instantiatied using&nbsp;<code style="line-height: 1;" class="">swift_getGenericMetadata</code>.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">For all structs, the compiler expects access to the following fields:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Nominal type descriptor</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">fixed offset, compiler-determined</td></tr><tr style="border-spacing: 0px; background-color: rgba(200, 200, 200, 0.247059);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(255, 255, 255, 0.0588235);" class="">Generic arguments</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">fixed offset, compiler-determined</td></tr><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Stored property offsets</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">fixed offset, compiler-determined</td></tr></tbody></table><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The metadata currently includes field offsets for all stored properties, but this should be changed to include only the fields with offsets that are dependent on the struct’s generic arguments.</p><h3 id="enums" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Enums</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler accesses concrete, known-layout enum metadata by direct reference to the global symbol. If the enum contains resilient payloads, the metadata is accessed through a runtime call for one-time initialization. Generic enum metadata is instantiatied using&nbsp;<code style="line-height: 1;" class="">swift_getGenericMetadata</code>.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">For all enums, the compiler expects access to the following fields:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Nominal type descriptor</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">fixed offset, compiler-determined</td></tr><tr style="border-spacing: 0px; background-color: rgba(200, 200, 200, 0.247059);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(255, 255, 255, 0.0588235);" class="">Generic arguments</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">fixed offset, compiler-determined</td></tr></tbody></table><h3 id="tuples" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Tuples</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Tuple metadata records are accessed by calling the&nbsp;<code style="line-height: 1;" class="">swift_getTupleTypeMetadata*</code>&nbsp;runtime functions.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler expects access to the following fields:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Element offsets</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">fixed offset</td></tr></tbody></table><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">If we wanted to be able to satisfy type metadata requirements for element types from tuple metadata, we could also provide access to:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Element types</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">TBD</td></tr></tbody></table><h3 id="functions" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Functions</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Function metadata records are accessed by calling the&nbsp;<code style="line-height: 1;" class="">swift_get*FunctionTypeMetadata*</code>&nbsp;runtime functions.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler does not currently emit any projections into function type metadata.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">If we wanted to be able to satisfy type metadata requirements for input or output types from function metadata, we could also provide access to:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Return type</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">TBD</td></tr><tr style="border-spacing: 0px; background-color: rgba(200, 200, 200, 0.247059);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(255, 255, 255, 0.0588235);" class="">Argument types</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">TBD</td></tr></tbody></table><h3 id="existentialsexistentialmetatypes" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Existentials, existential metatypes</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Existential metadata records are accessed by calling the&nbsp;<code style="line-height: 1;" class="">swift_getExistentialTypeMetadata*</code>&nbsp;runtime functions.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler does not currently generate any code that reaches into existential metadata records.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">If we wanted to be able to satisfy type metadata requirements for input or output types from function metadata, we could also provide access to:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Generic signature</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">TBD</td></tr></tbody></table><h3 id="metatypes" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Metatypes</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Metatype metadata records are accessed by calling the&nbsp;<code style="line-height: 1;" class="">swift_getMetatypeMetadata</code>&nbsp;function.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler does not currently generate any code that reaches into metatype metadata records.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">If we wanted to be able to satisfy type metadata requirements for the instance type from metatype metadata, we could also provide access to:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Instance type</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">TBD</td></tr></tbody></table><h3 id="objective-cwrappers" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Objective-C wrappers</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Class objects for natively-Objective-C classes are not Swift metadata by themselves, so need a wrapper metadata record. This wrapper metadata is only produced by the Swift runtime (and could be produced more efficiently by future cooperation with the ObjC runtime). The compiler accesses Objective-C class metadata by calling the&nbsp;<code style="line-height: 1;" class="">swift_getObjCClassMetadata</code>&nbsp;function, which may return either a wrapper or pass through the input class object if it is already valid metadata.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler generates code against the following:</p><table style="margin: -1px 0px 1.3125em; border-spacing: 0px; border: 1px solid rgba(0, 0, 0, 0.247059); border-collapse: collapse; empty-cells: hide; padding: 0px; table-layout: fixed; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><colgroup style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""><col style="border-spacing: 0px;" class=""></colgroup><thead style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.14902); border-width: 1px; border-style: solid; border-color: rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.14902) rgba(0, 0, 0, 0.2);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Information</th><th style="border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Projection strategy</th></tr></thead><tbody style="border-spacing: 0px; background-color: rgba(0, 0, 0, 0.0470588);" class=""><tr style="border-spacing: 0px; background-color: rgba(255, 255, 255, 0.0588235);" class=""><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px;" class="">Class object</td><td style="word-wrap: break-word; border-spacing: 0px; font-size: 1.1em; line-height: 1.3; padding: 0.5em 1em 0px; background-color: rgba(200, 200, 200, 0.247059);" class="">runtime call&nbsp;<code style="line-height: 1;" class="">swift_getObjCClassFromMetadata</code></td></tr></tbody></table><h3 id="corefoundationclass" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Core Foundation class</h3><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class=""><strong style="line-height: 1;" class="">Foreign class metadata</strong>&nbsp;records are generated by Swift’s Clang importer for imported Core Foundation class types. The records require runtime canonicalization to determine which metadata record uniquely identifies the type, since there is no home Swift module for the CF type. The compiler does not currently generate code against any fields of the metadata.</p><h1 id="recommendedchanges" style="font-size: 37px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Recommended changes</h1><h2 id="abstractawayfixedoffsetsacrossmodulesandforstructuralmetadata" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Abstract away fixed offsets across modules and for structural metadata</h2><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">Anything we lock down fixed offsets for in the ABI should justify itself by being necessary for performance or code size reasons. Unspecialized code relies heavily on:</p><ul style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">the value witness table</li><li style="font-size: 16.5px;" class="">stored property offsets</li><li style="font-size: 16.5px;" class="">generic arguments</li></ul><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">and these are the things that nominal type metadata currently makes directly available, for the most part. Anything else we emit direct access to (such as nominal type descriptors) should definitely be abstracted behind a runtime call. For structural type metadata (tuples, functions, existentials, metatypes), we already do so for most of the layout details, with the one exception of tuple element offsets, which are exposed for performance of unspecialized code.</p><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">For concrete nominal types, the compiler also currently generates metadata records that are expected to be directly usable as metadata. This is a nice code size optimization that’d be unfortunate to give up. At least for internal or private types, the emitted metadata format and all of the code that ought to be reaching into it are together in one resilience boundary, so one could say that the precise metadata record format for internal value types is a private contract of the compiler. However, even for public fragile types, it would be beneficial still to be able to directly export the symbol as usable metadata. For the performance-sensitive field offset and generic argument vectors, we could nonetheless avoid hard-coding offsets in the compiler. We could still guarantee that the generic arguments followed by (fragile) stored property offsets are stored contiguously, and abstract the&nbsp;<strong style="line-height: 1;" class="">base offset</strong>&nbsp;to the contiguous data structure. Possibilities for accessing the base offset include:</p><ol style="margin-top: 21px; margin-bottom: 21px; padding-left: 1.5em; list-style-position: inside; color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; font-size: 15px;" class=""><li style="font-size: 16.5px;" class="">Require a runtime call to get it</li><li style="font-size: 16.5px;" class="">Place the base offset somewhere else in the metadata</li><li style="font-size: 16.5px;" class="">Export the base offset as a separate symbol (possibly an absolute symbol, if it’s knowable at compile time for the home module, or a global variable, if it requires runtime computation).</li></ol><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">For classes with resilient ancestry, we already&nbsp;<em style="line-height: 1;" class="">must</em>&nbsp;have an approach that allows the offset to be computed at instantiation time and efficiently accessed in unspecialized code afterward. Technique (3) is proven by the Objective-C runtime and should be sufficient for our needs. It would impose a two- or three-instruction cost per type to load the base offset, which would sit on the dependency chain for any generic type or field offset loads based on that base offset, but would give us the flexibility to add new information to metadata records in future compilers.</p><h2 id="makemostmetadatakindsprivatetotheruntime" style="color: rgb(17, 17, 17); font-size: 27px; line-height: 42px; margin-top: 42px; margin-bottom: 21px; font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif;" class="">Make most metadata kinds private to the runtime</h2><p style="color: rgb(17, 17, 17); font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">The compiler does not emit any code that looks at metadata kinds for projection purposes. It does, however, use metadata kinds when it builds metadata records for nominal types. However, the metadata kind is already redundantly coded in the nominal type descriptor, so we could conceivably reduce the exposure of metadata kinds to a single “value type” kind (in addition to the “isa-pointer-in-the-kind-field-means-class” kind, imposed by ObjC compatibility).</p><div class=""><br class=""></div><div class="">-Joe</div></body></html>