Skip to content

Commit 32872cb

Browse files
committed
IRGen/Runtime: Relative-reference the nominal type descriptor and parent type from metadata.
Save a couple relocations per concrete value type, leaving only the value witness table as an absolute symbol.
1 parent 51e89de commit 32872cb

File tree

16 files changed

+430
-203
lines changed

16 files changed

+430
-203
lines changed

include/swift/Basic/RelativePointer.h

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,26 @@ static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
4242
return base + extendOffset;
4343
}
4444

45+
/// Measure the relative offset between two pointers. This measures
46+
/// (referent - base) using wrapping arithmetic. The result is truncated if
47+
/// Offset is smaller than a pointer, with an assertion that the
48+
/// pre-truncation result is a sign extension of the truncated result.
49+
template<typename Offset, typename A, typename B>
50+
static inline Offset measureRelativeOffset(A *referent, B *base) {
51+
static_assert(std::is_integral<Offset>::value &&
52+
std::is_signed<Offset>::value,
53+
"offset type should be signed integer");
54+
55+
auto distance = (uintptr_t)referent - (uintptr_t)base;
56+
// Truncate as unsigned, then wrap around to signed.
57+
auto truncatedDistance =
58+
(Offset)(typename std::make_unsigned<Offset>::type)distance;
59+
// Assert that the truncation didn't discard any non-sign-extended bits.
60+
assert((intptr_t)truncatedDistance == (intptr_t)distance
61+
&& "pointers are too far apart to fit in offset type");
62+
return truncatedDistance;
63+
}
64+
4565
} // namespace detail
4666

4767
/// A relative reference to an object stored in memory. The reference may be
@@ -70,7 +90,34 @@ class RelativeIndirectablePointer {
7090
= delete;
7191

7292
public:
93+
/// Allow construction and reassignment from an absolute pointer.
94+
/// These always produce a direct relative offset.
95+
RelativeIndirectablePointer(ValueTy *absolute)
96+
: RelativeOffsetPlusIndirect(
97+
Nullable && absolute == nullptr
98+
? 0
99+
: detail::measureRelativeOffset<Offset>(absolute, this)) {
100+
if (!Nullable)
101+
assert(absolute != nullptr &&
102+
"constructing non-nullable relative pointer from null");
103+
}
104+
105+
RelativeIndirectablePointer &operator=(ValueTy *absolute) & {
106+
if (!Nullable)
107+
assert(absolute != nullptr &&
108+
"constructing non-nullable relative pointer from null");
109+
110+
RelativeOffsetPlusIndirect = Nullable && absolute == nullptr
111+
? 0
112+
: detail::measureRelativeOffset<Offset>(absolute, this);
113+
return *this;
114+
}
115+
73116
const ValueTy *get() const & {
117+
static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
118+
"alignment of value and offset must be at least 2 to "
119+
"make room for indirectable flag");
120+
74121
// Check for null.
75122
if (Nullable && RelativeOffsetPlusIndirect == 0)
76123
return nullptr;
@@ -118,17 +165,42 @@ class RelativeDirectPointerImpl {
118165
/// RelativePointers should appear in statically-generated metadata. They
119166
/// shouldn't be constructed or copied.
120167
RelativeDirectPointerImpl() = delete;
121-
RelativeDirectPointerImpl(RelativeDirectPointerImpl &&) = delete;
122-
RelativeDirectPointerImpl(const RelativeDirectPointerImpl &) = delete;
123-
RelativeDirectPointerImpl &operator=(RelativeDirectPointerImpl &&)
124-
= delete;
125-
RelativeDirectPointerImpl &operator=(const RelativeDirectPointerImpl&)
126-
= delete;
127168

128169
public:
129170
using ValueTy = T;
130171
using PointerTy = T*;
131172

173+
// Allow construction and reassignment from an absolute pointer.
174+
RelativeDirectPointerImpl(PointerTy absolute)
175+
: RelativeOffset(Nullable && absolute == nullptr
176+
? 0
177+
: detail::measureRelativeOffset<Offset>(absolute, this))
178+
{
179+
if (!Nullable)
180+
assert(absolute != nullptr &&
181+
"constructing non-nullable relative pointer from null");
182+
}
183+
explicit constexpr RelativeDirectPointerImpl(std::nullptr_t)
184+
: RelativeOffset (0) {
185+
static_assert(Nullable, "can't construct non-nullable pointer from null");
186+
}
187+
188+
RelativeDirectPointerImpl &operator=(PointerTy absolute) & {
189+
if (!Nullable)
190+
assert(absolute != nullptr &&
191+
"constructing non-nullable relative pointer from null");
192+
RelativeOffset = Nullable && absolute == nullptr
193+
? 0
194+
: detail::measureRelativeOffset<Offset>(absolute, this);
195+
return *this;
196+
}
197+
198+
// Can copy-construct by recalculating the relative offset at the new
199+
// position.
200+
RelativeDirectPointerImpl(const RelativeDirectPointerImpl &p) {
201+
*this = p.get();
202+
}
203+
132204
PointerTy get() const & {
133205
// Check for null.
134206
if (Nullable && RelativeOffset == 0)
@@ -153,6 +225,12 @@ class RelativeDirectPointer :
153225
using super = RelativeDirectPointerImpl<T, Nullable, Offset>;
154226
public:
155227
using super::get;
228+
using super::super;
229+
230+
RelativeDirectPointer &operator=(T *absolute) & {
231+
super::operator=(absolute);
232+
return *this;
233+
}
156234

157235
operator typename super::PointerTy() const & {
158236
return this->get();
@@ -178,7 +256,13 @@ class RelativeDirectPointer<RetTy (ArgTy...), Nullable, Offset> :
178256
using super = RelativeDirectPointerImpl<RetTy (ArgTy...), Nullable, Offset>;
179257
public:
180258
using super::get;
259+
using super::super;
181260

261+
RelativeDirectPointer &operator=(RetTy (*absolute)(ArgTy...)) & {
262+
super::operator=(absolute);
263+
return *this;
264+
}
265+
182266
operator typename super::PointerTy() const & {
183267
return this->get();
184268
}
@@ -229,5 +313,16 @@ class RelativeDirectPointerIntPair {
229313
}
230314
};
231315

316+
// Type aliases for "far" relative pointers, which need to be able to reach
317+
// across the full address space instead of only across a single small-code-
318+
// model image.
319+
320+
template<typename T, bool Nullable = false>
321+
using FarRelativeIndirectablePointer =
322+
RelativeIndirectablePointer<T, Nullable, intptr_t>;
323+
324+
template<typename T, bool Nullable = false>
325+
using FarRelativeDirectPointer = RelativeDirectPointer<T, Nullable, intptr_t>;
326+
232327
}
233328

include/swift/Runtime/Metadata.h

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,7 @@ struct EnumTypeDescriptor;
12461246
/// descriptor is shared for all instantiations of the generic type.
12471247
struct NominalTypeDescriptor {
12481248
/// The mangled name of the nominal type, with no generic parameters.
1249-
RelativeDirectPointer<char> Name;
1249+
RelativeDirectPointer<const char> Name;
12501250

12511251
/// The following fields are kind-dependent.
12521252
union {
@@ -1266,7 +1266,7 @@ struct NominalTypeDescriptor {
12661266

12671267
/// The field names. A doubly-null-terminated list of strings, whose
12681268
/// length and order is consistent with that of the field offset vector.
1269-
RelativeDirectPointer<char, /*nullable*/ true> FieldNames;
1269+
RelativeDirectPointer<const char, /*nullable*/ true> FieldNames;
12701270

12711271
/// The field type vector accessor. Returns a pointer to an array of
12721272
/// type metadata references whose order is consistent with that of the
@@ -1290,7 +1290,7 @@ struct NominalTypeDescriptor {
12901290

12911291
/// The field names. A doubly-null-terminated list of strings, whose
12921292
/// length and order is consistent with that of the field offset vector.
1293-
RelativeDirectPointer<char, /*nullable*/ true> FieldNames;
1293+
RelativeDirectPointer<const char, /*nullable*/ true> FieldNames;
12941294

12951295
/// The field type vector accessor. Returns a pointer to an array of
12961296
/// type metadata references whose order is consistent with that of the
@@ -1313,7 +1313,7 @@ struct NominalTypeDescriptor {
13131313
/// The names of the cases. A doubly-null-terminated list of strings,
13141314
/// whose length is NumNonEmptyCases + NumEmptyCases. Cases are named in
13151315
/// tag order, non-empty cases first, followed by empty cases.
1316-
RelativeDirectPointer<char, /*nullable*/ true> CaseNames;
1316+
RelativeDirectPointer<const char, /*nullable*/ true> CaseNames;
13171317
/// The field type vector accessor. Returns a pointer to an array of
13181318
/// type metadata references whose order is consistent with that of the
13191319
/// CaseNames. Only types for payload cases are provided.
@@ -1372,20 +1372,19 @@ typedef void (*ClassIVarDestroyer)(HeapObject *);
13721372
struct ClassMetadata : public HeapMetadata {
13731373
ClassMetadata() = default;
13741374
constexpr ClassMetadata(const HeapMetadata &base,
1375-
const ClassMetadata *superClass,
1376-
uintptr_t data,
1377-
ClassFlags flags,
1378-
const NominalTypeDescriptor *description,
1379-
ClassIVarDestroyer ivarDestroyer,
1380-
uintptr_t size, uintptr_t addressPoint,
1381-
uintptr_t alignMask,
1382-
uintptr_t classSize, uintptr_t classAddressPoint)
1375+
const ClassMetadata *superClass,
1376+
uintptr_t data,
1377+
ClassFlags flags,
1378+
ClassIVarDestroyer ivarDestroyer,
1379+
uintptr_t size, uintptr_t addressPoint,
1380+
uintptr_t alignMask,
1381+
uintptr_t classSize, uintptr_t classAddressPoint)
13831382
: HeapMetadata(base), SuperClass(superClass),
13841383
CacheData{nullptr, nullptr}, Data(data),
13851384
Flags(flags), InstanceAddressPoint(addressPoint),
13861385
InstanceSize(size), InstanceAlignMask(alignMask),
13871386
Reserved(0), ClassSize(classSize), ClassAddressPoint(classAddressPoint),
1388-
Description(description), IVarDestroyer(ivarDestroyer) {}
1387+
Description(nullptr), IVarDestroyer(ivarDestroyer) {}
13891388

13901389
/// The metadata for the superclass. This is null for the root class.
13911390
const ClassMetadata *SuperClass;
@@ -1443,7 +1442,8 @@ struct ClassMetadata : public HeapMetadata {
14431442
/// if this is an artificial subclass. We currently provide no
14441443
/// supported mechanism for making a non-artificial subclass
14451444
/// dynamically.
1446-
const NominalTypeDescriptor *Description;
1445+
FarRelativeDirectPointer<const NominalTypeDescriptor,
1446+
/*nullable*/ true> Description;
14471447

14481448
/// A function for destroying instance variables, used to clean up
14491449
/// after an early return from a constructor.
@@ -1462,6 +1462,10 @@ struct ClassMetadata : public HeapMetadata {
14621462
assert(!isArtificialSubclass());
14631463
return Description;
14641464
}
1465+
1466+
void setDescription(const NominalTypeDescriptor *description) {
1467+
Description = description;
1468+
}
14651469

14661470
ClassIVarDestroyer getIVarDestroyer() const {
14671471
assert(isTypeMetadata());
@@ -1713,14 +1717,40 @@ struct ForeignClassMetadata : public ForeignTypeMetadata {
17131717
}
17141718
};
17151719

1716-
/// The structure of type metadata for structs.
1717-
struct StructMetadata : public Metadata {
1720+
/// The common structure of metadata for structs and enums.
1721+
struct ValueMetadata : public Metadata {
1722+
ValueMetadata(MetadataKind Kind, const NominalTypeDescriptor *description,
1723+
const Metadata *parent)
1724+
: Metadata(Kind), Description(description), Parent(parent)
1725+
{}
1726+
17181727
/// An out-of-line description of the type.
1719-
const NominalTypeDescriptor *Description;
1728+
FarRelativeDirectPointer<const NominalTypeDescriptor> Description;
17201729

17211730
/// The parent type of this member type, or null if this is not a
17221731
/// member type.
1723-
const Metadata *Parent;
1732+
FarRelativeIndirectablePointer<const Metadata, /*nullable*/ true> Parent;
1733+
1734+
static bool classof(const Metadata *metadata) {
1735+
return metadata->getKind() == MetadataKind::Struct
1736+
|| metadata->getKind() == MetadataKind::Enum
1737+
|| metadata->getKind() == MetadataKind::Optional;
1738+
}
1739+
1740+
/// Retrieve the generic arguments of this type.
1741+
const Metadata * const *getGenericArgs() const {
1742+
if (Description->GenericParams.NumParams == 0)
1743+
return nullptr;
1744+
1745+
const void* const *asWords = reinterpret_cast<const void * const *>(this);
1746+
asWords += Description->GenericParams.Offset;
1747+
return reinterpret_cast<const Metadata * const *>(asWords);
1748+
}
1749+
};
1750+
1751+
/// The structure of type metadata for structs.
1752+
struct StructMetadata : public ValueMetadata {
1753+
using ValueMetadata::ValueMetadata;
17241754

17251755
/// Get a pointer to the field offset vector, if present, or null.
17261756
const uintptr_t *getFieldOffsets() const {
@@ -1740,29 +1770,14 @@ struct StructMetadata : public Metadata {
17401770
return getter(this);
17411771
}
17421772

1743-
/// Retrieve the generic arguments of this struct.
1744-
const Metadata * const *getGenericArgs() const {
1745-
if (Description->GenericParams.NumParams == 0)
1746-
return nullptr;
1747-
1748-
const void* const *asWords = reinterpret_cast<const void * const *>(this);
1749-
asWords += Description->GenericParams.Offset;
1750-
return reinterpret_cast<const Metadata * const *>(asWords);
1751-
}
1752-
17531773
static bool classof(const Metadata *metadata) {
17541774
return metadata->getKind() == MetadataKind::Struct;
17551775
}
17561776
};
17571777

17581778
/// The structure of type metadata for enums.
1759-
struct EnumMetadata : public Metadata {
1760-
/// An out-of-line description of the type.
1761-
const NominalTypeDescriptor *Description;
1762-
1763-
/// The parent type of this member type, or null if this is not a
1764-
/// member type.
1765-
const Metadata *Parent;
1779+
struct EnumMetadata : public ValueMetadata {
1780+
using ValueMetadata::ValueMetadata;
17661781

17671782
/// True if the metadata records the size of the payload area.
17681783
bool hasPayloadSize() const {
@@ -1788,16 +1803,6 @@ struct EnumMetadata : public Metadata {
17881803
return *asWords;
17891804
}
17901805

1791-
/// Retrieve the generic arguments of this enum.
1792-
const Metadata * const *getGenericArgs() const {
1793-
const void* const *asWords = reinterpret_cast<const void * const *>(this);
1794-
if (Description->GenericParams.NumParams == 0)
1795-
return nullptr;
1796-
1797-
asWords += Description->GenericParams.Offset;
1798-
return reinterpret_cast<const Metadata * const *>(asWords);
1799-
}
1800-
18011806
static bool classof(const Metadata *metadata) {
18021807
return metadata->getKind() == MetadataKind::Enum
18031808
|| metadata->getKind() == MetadataKind::Optional;
@@ -2215,7 +2220,7 @@ struct GenericWitnessTable {
22152220
/*nullable*/ true> Protocol;
22162221

22172222
/// The pattern.
2218-
RelativeDirectPointer<WitnessTable> Pattern;
2223+
RelativeDirectPointer<const WitnessTable> Pattern;
22192224

22202225
/// The instantiation function, which is called after the template is copied.
22212226
RelativeDirectPointer<void(WitnessTable *instantiatedTable,
@@ -2240,7 +2245,7 @@ struct TypeMetadataRecord {
22402245
// Some description of the type that is resolvable at runtime.
22412246
union {
22422247
/// A direct reference to the metadata.
2243-
RelativeDirectPointer<Metadata> DirectType;
2248+
RelativeDirectPointer<const Metadata> DirectType;
22442249

22452250
/// The nominal type descriptor for a resilient or generic type.
22462251
RelativeDirectPointer<NominalTypeDescriptor> TypeDescriptor;
@@ -2327,7 +2332,7 @@ struct ProtocolConformanceRecord {
23272332
// The conformance, or a generator function for the conformance.
23282333
union {
23292334
/// A direct reference to the witness table for the conformance.
2330-
RelativeDirectPointer<WitnessTable> WitnessTable;
2335+
RelativeDirectPointer<const WitnessTable> WitnessTable;
23312336

23322337
/// A function that produces the witness table given an instance of the
23332338
/// type. The function may return null if a specific instance does not
@@ -2502,7 +2507,7 @@ swift_allocateGenericClassMetadata(GenericMetadata *pattern,
25022507

25032508
// Callback to allocate a generic struct/enum metadata object.
25042509
SWIFT_RUNTIME_EXPORT
2505-
extern "C" Metadata *
2510+
extern "C" ValueMetadata *
25062511
swift_allocateGenericValueMetadata(GenericMetadata *pattern,
25072512
const void *arguments);
25082513

0 commit comments

Comments
 (0)