Skip to content

Commit edab098

Browse files
committed
[runtime] Metadata can be flagged static.
Added a new flag to the GenericMetadataPatternFlags flagset for whether the metadata has a set of flags at its tail. When that flag is set, there will be an extra uint64_t flagset at the end of the metadata. For struct metadata, the type of that flagset will be StructMetadataTrailingFlags. The first flag in that trailing flagset indicates whether the metadata was statically specialized. The second flag in that trailing flagset indicates whether the metadata is statically canonical. When verifying the metadata cache, a check is done for whether the metadata was statically specialized and whether it was known to be canonical statically. If so, verification is skipped. Skipping it is necessary because the known-canonical statically specialized metadata will not be in the cache. In that case, the canonical statically specialized metadata will be returned from the metadata accessor and never be cached.
1 parent cdf3817 commit edab098

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

include/swift/ABI/Metadata.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,8 @@ struct TargetMetadata {
697697

698698
bool satisfiesClassConstraint() const;
699699

700+
bool isCanonicalStaticallySpecializedGenericMetadata() const;
701+
700702
#if SWIFT_OBJC_INTEROP
701703
/// Get the ObjC class object for this type if it has one, or return null if
702704
/// the type is not a class (or not a class with a class object).
@@ -1348,6 +1350,34 @@ struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
13481350
return reinterpret_cast<const uint32_t *>(asWords + offset);
13491351
}
13501352

1353+
bool isCanonicalStaticallySpecializedGenericMetadata() const {
1354+
auto *description = getDescription();
1355+
if (!description->isGeneric())
1356+
return false;
1357+
1358+
auto *trailingFlags = getTrailingFlags();
1359+
if (trailingFlags == nullptr)
1360+
return false;
1361+
1362+
return trailingFlags->isCanonicalStaticSpecialization();
1363+
}
1364+
1365+
const MetadataTrailingFlags *getTrailingFlags() const {
1366+
auto description = getDescription();
1367+
auto flags = description->getFullGenericContextHeader()
1368+
.DefaultInstantiationPattern->PatternFlags;
1369+
if (!flags.hasTrailingFlags())
1370+
return nullptr;
1371+
auto fieldOffset = description->FieldOffsetVectorOffset;
1372+
auto offset =
1373+
fieldOffset +
1374+
// Pad to the nearest pointer.
1375+
((description->NumFields * sizeof(uint32_t) + sizeof(void *) - 1) /
1376+
sizeof(void *));
1377+
auto asWords = reinterpret_cast<const void *const *>(this);
1378+
return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
1379+
}
1380+
13511381
static constexpr int32_t getGenericArgumentOffset() {
13521382
return sizeof(TargetStructMetadata<Runtime>) / sizeof(StoredPointer);
13531383
}

include/swift/ABI/MetadataValues.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,10 @@ class GenericMetadataPatternFlags : public FlagSet<uint32_t> {
15111511
/// Does this pattern have an extra-data pattern?
15121512
HasExtraDataPattern = 0,
15131513

1514+
/// Do instances of this pattern have a bitset of flags that occur at the
1515+
/// end of the metadata, after the extra data if there is any?
1516+
HasTrailingFlags = 1,
1517+
15141518
// Class-specific flags.
15151519

15161520
/// Does this pattern have an immediate-members pattern?
@@ -1535,6 +1539,10 @@ class GenericMetadataPatternFlags : public FlagSet<uint32_t> {
15351539
hasExtraDataPattern,
15361540
setHasExtraDataPattern)
15371541

1542+
FLAGSET_DEFINE_FLAG_ACCESSORS(HasTrailingFlags,
1543+
hasTrailingFlags,
1544+
setHasTrailingFlags)
1545+
15381546
FLAGSET_DEFINE_FIELD_ACCESSORS(Value_MetadataKind,
15391547
Value_MetadataKind_width,
15401548
MetadataKind,
@@ -1667,6 +1675,30 @@ class MetadataRequest : public FlagSet<size_t> {
16671675
}
16681676
};
16691677

1678+
struct MetadataTrailingFlags : public FlagSet<uint64_t> {
1679+
enum {
1680+
/// Whether this metadata is a specialization of a generic metadata pattern
1681+
/// which was created during compilation.
1682+
IsStaticSpecialization = 0,
1683+
1684+
/// Whether this metadata is a specialization of a generic metadata pattern
1685+
/// which was created during compilation and made to be canonical by
1686+
/// modifying the metadata accessor.
1687+
IsCanonicalStaticSpecialization = 1,
1688+
};
1689+
1690+
explicit MetadataTrailingFlags(uint64_t bits) : FlagSet(bits) {}
1691+
constexpr MetadataTrailingFlags() {}
1692+
1693+
FLAGSET_DEFINE_FLAG_ACCESSORS(IsStaticSpecialization,
1694+
isStaticSpecialization,
1695+
setIsStaticSpecialization)
1696+
1697+
FLAGSET_DEFINE_FLAG_ACCESSORS(IsCanonicalStaticSpecialization,
1698+
isCanonicalStaticSpecialization,
1699+
setIsCanonicalStaticSpecialization)
1700+
};
1701+
16701702
/// Flags for Builtin.IntegerLiteral values.
16711703
class IntegerLiteralFlags {
16721704
public:

stdlib/public/runtime/Metadata.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4630,6 +4630,14 @@ const WitnessTable *swift::swift_getAssociatedConformanceWitness(
46304630
template <class Result, class Callbacks>
46314631
static Result performOnMetadataCache(const Metadata *metadata,
46324632
Callbacks &&callbacks) {
4633+
// TODO: Once more than just structs have canonical statically specialized
4634+
// metadata, calling an updated
4635+
// isCanonicalStaticallySpecializedGenericMetadata would entail
4636+
// dyn_casting to the same type more than once. Avoid that by combining
4637+
// that function's implementation with the dyn_casts below.
4638+
if (metadata->isCanonicalStaticallySpecializedGenericMetadata())
4639+
return std::move(callbacks).forOtherMetadata(metadata);
4640+
46334641
// Handle different kinds of type that can delay their metadata.
46344642
const TypeContextDescriptor *description;
46354643
if (auto classMetadata = dyn_cast<ClassMetadata>(metadata)) {
@@ -5211,6 +5219,14 @@ bool Metadata::satisfiesClassConstraint() const {
52115219
return isAnyClass();
52125220
}
52135221

5222+
template <>
5223+
bool Metadata::isCanonicalStaticallySpecializedGenericMetadata() const {
5224+
if (auto *metadata = dyn_cast<StructMetadata>(this))
5225+
return metadata->isCanonicalStaticallySpecializedGenericMetadata();
5226+
5227+
return false;
5228+
}
5229+
52145230
#if !NDEBUG
52155231
static bool referencesAnonymousContext(Demangle::Node *node) {
52165232
if (node->getKind() == Demangle::Node::Kind::AnonymousContext)

0 commit comments

Comments
 (0)