| // Copyright 2021 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package pkgbits |
| |
| // A SectionKind indicates a section, as well as the ordering of sections within |
| // unified export data. Any object given a dedicated section can be referred to |
| // via a section / index pair (and thus dereferenced) in other sections. |
| type SectionKind int32 // TODO(markfreeman): Replace with uint8. |
| |
| const ( |
| SectionString SectionKind = iota |
| SectionMeta |
| SectionPosBase |
| SectionPkg |
| SectionName |
| SectionType |
| SectionObj |
| SectionObjExt |
| SectionObjDict |
| SectionBody |
| |
| numRelocs = iota |
| ) |
| |
| // An Index represents a bitstream element index *within* (i.e., relative to) a |
| // particular section. |
| type Index int32 |
| |
| // An AbsElemIdx, or absolute element index, is an index into the elements |
| // that is not relative to some other index. |
| type AbsElemIdx = uint32 |
| |
| // TODO(markfreeman): Make this its own type. |
| // A RelElemIdx, or relative element index, is an index into the elements |
| // relative to some other index, such as the start of a section. |
| type RelElemIdx = Index |
| |
| /* |
| All elements are preceded by a reference table. Reference tables provide an |
| additional indirection layer for element references. That is, for element A to |
| reference element B, A encodes the reference table index pointing to B, rather |
| than the table entry itself. |
| |
| # Functional Considerations |
| Reference table layout is important primarily to the UIR linker. After noding, |
| the UIR linker sees a UIR file for each package with imported objects |
| represented as stubs. In a simple sense, the job of the UIR linker is to merge |
| these "stubbed" UIR files into a single "linked" UIR file for the target package |
| with stubs replaced by object definitions. |
| |
| To do this, the UIR linker walks each stubbed UIR file and pulls in elements in |
| dependency order; that is, if A references B, then B must be placed into the |
| linked UIR file first. This depth-first traversal is done by recursing through |
| each element's reference table. |
| |
| When placing A in the linked UIR file, the reference table entry for B must be |
| updated, since B is unlikely to be at the same relative element index as it was |
| in the stubbed UIR file. |
| |
| Without reference tables, the UIR linker would need to read in the element to |
| discover its references. Note that the UIR linker cannot jump directly to the |
| reference locations after discovering merely the type of the element; |
| variable-width primitives prevent this. |
| |
| After updating the reference table, the rest of the element may be copied |
| directly into the linked UIR file. Note that the UIR linker may decide to read |
| in the element anyway (for unrelated reasons). |
| |
| In short, reference tables provide an efficient mechanism for traversing, |
| discovering, and updating element references during UIR linking. |
| |
| # Storage Considerations |
| Reference tables also have compactness benefits: |
| - If A refers to B multiple times, the entry is deduplicated and referred to |
| more compactly by the index. |
| - Relative (to a section) element indices are typically smaller than absolute |
| element indices, and thus fit into smaller varints. |
| - Most elements do not reference many elements; thus table size indicators and |
| table indices are typically a byte each. |
| |
| Thus, the storage performance is as follows: |
| +-----------------------------+-----------+--------------+ |
| | Scenario | Best Case | Typical Case | |
| +-----------------------------+-----------+--------------+ |
| | First reference from A to B | 3 Bytes | 4 Bytes | |
| | Other reference from A to B | 1 Byte | 1 Byte | |
| +-----------------------------+-----------+--------------+ |
| |
| The typical case for the first scenario changes because many sections have more |
| than 127 (range of a 1-byte uvarint) elements and thus the relative index is |
| typically 2 bytes, though this depends on the distribution of referenced indices |
| within the section. |
| |
| The second does not because most elements do not reference more than 127 |
| elements and the table index can thus keep to 1 byte. |
| |
| Typically, A will only reference B once, so most references are 4 bytes. |
| */ |
| |
| // A RefTableEntry is an entry in an element's reference table. All |
| // elements are preceded by a reference table which provides locations |
| // for referenced elements. |
| type RefTableEntry struct { |
| Kind SectionKind |
| Idx RelElemIdx |
| } |
| |
| // Reserved indices within the [SectionMeta] section. |
| const ( |
| PublicRootIdx RelElemIdx = 0 |
| PrivateRootIdx RelElemIdx = 1 |
| ) |