diff --git a/src/internal/pkgbits/reloc.go b/src/internal/pkgbits/reloc.go index 5f6ec2ab79..6074296d9e 100644 --- a/src/internal/pkgbits/reloc.go +++ b/src/internal/pkgbits/reloc.go @@ -37,7 +37,68 @@ type AbsElemIdx = uint32 // relative to some other index, such as the start of a section. type RelElemIdx = Index -// TODO(markfreeman): Isn't this strictly less efficient than an AbsElemIdx? +/* +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.