17
17
// unnecessary relocation at dynamic linking time. This header contains types
18
18
// to help dereference these relative addresses.
19
19
//
20
+ // Theory of references to objects
21
+ // -------------------------------
22
+ //
23
+ // A reference can be absolute or relative:
24
+ //
25
+ // - An absolute reference is a pointer to the object.
26
+ //
27
+ // - A relative reference is a (signed) offset from the address of the
28
+ // reference to the address of its direct referent.
29
+ //
30
+ // A relative reference can be direct, indirect, or symbolic.
31
+ //
32
+ // In a direct reference, the direct referent is simply the target object.
33
+ // Generally, a statically-emitted relative reference can only be direct
34
+ // if it can be resolved to a constant offset by the linker, because loaders
35
+ // do not support forming relative references. This means that either the
36
+ // reference and object must lie within the same linkage unit or the
37
+ // difference must be computed at runtime by code.
38
+ //
39
+ // In a symbolic reference, the direct referent is a string holding the symbol
40
+ // name of the object. A relative reference can only be symbolic if the
41
+ // object actually has a symbol at runtime, which may require exporting
42
+ // many internal symbols that would otherwise be strippable.
43
+ //
44
+ // In an indirect reference, the direct referent is a variable holding an
45
+ // absolute reference to the object. An indirect relative reference may
46
+ // refer to an arbitrary symbol, be it anonymous within the linkage unit
47
+ // or completely external to it, but it requires the introduction of an
48
+ // intermediate absolute reference that requires load-time initialization.
49
+ // However, this initialization can be shared among all indirect references
50
+ // within the linkage unit, and the linker will generally place all such
51
+ // references adjacent to one another to improve load-time locality.
52
+ //
53
+ // A reference can be made a dynamic union of more than one of these options.
54
+ // This allows the compiler/linker to use a direct reference when possible
55
+ // and a less-efficient option where required. However, it also requires
56
+ // the cases to be dynamically distinguished. This can be done by setting
57
+ // a low bit of the offset, as long as the difference between the direct
58
+ // referent's address and the reference is a multiple of 2. This works well
59
+ // for "indirectable" references because most objects are known to be
60
+ // well-aligned, and the cases that aren't (chiefly functions and strings)
61
+ // rarely need the flexibility of this kind of reference. It does not
62
+ // work quite as well for "possibly symbolic" references because C strings
63
+ // are not naturally aligned, and making them aligned generally requires
64
+ // moving them out of the linker's ordinary string section; however, it's
65
+ // still workable.
66
+ //
67
+ // Finally, a relative reference can be near or far. A near reference
68
+ // is potentially smaller, but it requires the direct referent to lie
69
+ // within a certain distance of the reference, even if dynamically
70
+ // initialized.
71
+ //
72
+ // In Swift, we always prefer to use a near direct relative reference
73
+ // when it is possible to do so: that is, when the relationship is always
74
+ // between two global objects emitted in the same linkage unit, and there
75
+ // is no compatibility constraint requiring the use of an absolute reference.
76
+ //
77
+ // When more flexibility is required, there are several options:
78
+ //
79
+ // 1. Use an absolute reference. Size penalty on 64-bit. Requires
80
+ // load-time work.
81
+ //
82
+ // 2. Use a far direct relative reference. Size penalty on 64-bit.
83
+ // Requires load-time work when object is outside linkage unit.
84
+ // Generally not directly supported by loaders.
85
+ //
86
+ // 3. Use an always-indirect relative reference. Size penalty of one
87
+ // pointer (shared). Requires load-time work even when object is
88
+ // within linkage unit.
89
+ //
90
+ // 4. Use a near indirectable relative reference. Size penalty of one
91
+ // pointer (shared) when reference exceeds range. Runtime / code-size
92
+ // penalty on access. Requires load-time work (shared) only when
93
+ // object is outside linkage unit.
94
+ //
95
+ // 5. Use a far indirectable relative reference. Size penalty on 64-bit.
96
+ // Size penalty of one pointer (shared) when reference exceeds range
97
+ // and is initialized statically. Runtime / code-size penalty on access.
98
+ // Requires load-time work (shared) only when object is outside linkage
99
+ // unit.
100
+ //
101
+ // 6. Use a near or far symbolic relative reference. No load-time work.
102
+ // Severe runtime penalty on access. Requires custom logic to statically
103
+ // optimize. Requires emission of symbol for target even if private
104
+ // to linkage unit.
105
+ //
106
+ // 7. Use a near or far direct-or-symbolic relative reference. No
107
+ // load-time work. Severe runtime penalty on access if object is
108
+ // outside of linkage unit. Requires custom logic to statically optimize.
109
+ //
110
+ // In general, it's our preference in Swift to use option #4 when there
111
+ // is no possibility of initializing the reference dynamically and option #5
112
+ // when there is. This is because it is infeasible to actually share the
113
+ // memory for the intermediate absolute reference when it must be allocated
114
+ // dynamically.
115
+ //
116
+ // Symbolic references are an interesting idea that we have not yet made
117
+ // use of. They may be acceptable in reflective metadata cases where it
118
+ // is desireable to heavily bias towards never using the metadata. However,
119
+ // they're only profitable if there wasn't any other indirect reference
120
+ // to the target, and it is likely that their optimal use requires a more
121
+ // intelligent toolchain from top to bottom.
122
+ //
123
+ // Note that the cost of load-time work also includes a binary-size penalty
124
+ // to store the loader metadata necessary to perform that work. Therefore
125
+ // it is better to avoid it even when there are dynamic optimizations in
126
+ // place to skip the work itself.
127
+ //
20
128
// ===----------------------------------------------------------------------===//
21
129
22
130
#ifndef SWIFT_BASIC_RELATIVEPOINTER_H
@@ -279,7 +387,8 @@ class RelativeDirectPointer<RetTy (ArgTy...), Nullable, Offset> :
279
387
280
388
// / A direct relative reference to an aligned object, with an additional
281
389
// / tiny integer value crammed into its low bits.
282
- template <typename PointeeTy, typename IntTy, typename Offset = int32_t >
390
+ template <typename PointeeTy, typename IntTy, bool Nullable = false ,
391
+ typename Offset = int32_t >
283
392
class RelativeDirectPointerIntPair {
284
393
Offset RelativeOffsetPlusInt;
285
394
@@ -305,9 +414,14 @@ class RelativeDirectPointerIntPair {
305
414
using PointerTy = PointeeTy*;
306
415
307
416
PointerTy getPointer () const & {
417
+ Offset offset = (RelativeOffsetPlusInt & ~getMask ());
418
+
419
+ // Check for null.
420
+ if (Nullable && offset == 0 )
421
+ return nullptr ;
422
+
308
423
// The value is addressed relative to `this`.
309
- uintptr_t absolute = detail::applyRelativeOffset (this ,
310
- RelativeOffsetPlusInt & ~getMask ());
424
+ uintptr_t absolute = detail::applyRelativeOffset (this , offset);
311
425
return reinterpret_cast <PointerTy>(absolute);
312
426
}
313
427
0 commit comments