Skip to content

Commit a5524d2

Browse files
authored
Merge pull request #18214 from rjmccall/in-place-value-metadata-dependencies
Resolve cyclic dependencies in in-place metadata initialization of value types
2 parents 15305aa + dc052e6 commit a5524d2

25 files changed

+963
-253
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Globals
5656
global ::= nominal-type 'Mr' // generic type completion function
5757
global ::= nominal-type 'Mi' // generic type instantiation function
5858
global ::= nominal-type 'MI' // generic type instantiation cache
59+
global ::= nominal-type 'Ml' // in-place type initialization cache
5960
global ::= nominal-type 'Mm' // class metaclass
6061
global ::= nominal-type 'Mn' // nominal type descriptor
6162
global ::= module 'MXM' // module descriptor

include/swift/ABI/Metadata.h

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,6 +3364,14 @@ class TargetTypeContextDescriptor
33643364
return TypeContextDescriptorFlags(this->Flags.getKindSpecificFlags());
33653365
}
33663366

3367+
/// Does this type have non-trivial "in place" metadata initialization?
3368+
///
3369+
/// The type of the initialization-control structure differs by subclass,
3370+
/// so it doesn't appear here.
3371+
bool hasInPlaceMetadataInitialization() const {
3372+
return getTypeContextDescriptorFlags().hasInPlaceMetadataInitialization();
3373+
}
3374+
33673375
const TargetTypeGenericContextDescriptorHeader<Runtime> &
33683376
getFullGenericContextHeader() const;
33693377

@@ -3709,10 +3717,49 @@ class TargetClassDescriptor final
37093717

37103718
using ClassDescriptor = TargetClassDescriptor<InProcess>;
37113719

3720+
/// The cache structure for non-trivial initialization of singleton value
3721+
/// metadata.
3722+
template <typename Runtime>
3723+
struct TargetInPlaceValueMetadataCache {
3724+
/// The metadata pointer. Clients can do dependency-ordered loads
3725+
/// from this, and if they see a non-zero value, it's a Complete
3726+
/// metadata.
3727+
std::atomic<TargetMetadataPointer<Runtime, TargetMetadata>> Metadata;
3728+
3729+
/// The private cache data.
3730+
std::atomic<TargetPointer<Runtime, void>> Private;
3731+
};
3732+
using InPlaceValueMetadataCache =
3733+
TargetInPlaceValueMetadataCache<InProcess>;
3734+
3735+
/// The control structure for performing non-trivial initialization of
3736+
/// singleton value metadata, which is required when e.g. a non-generic
3737+
/// value type has a resilient component type.
3738+
template <typename Runtime>
3739+
struct TargetInPlaceValueMetadataInitialization {
3740+
/// The initialization cache. Out-of-line because mutable.
3741+
TargetRelativeDirectPointer<Runtime,
3742+
TargetInPlaceValueMetadataCache<Runtime>>
3743+
InitializationCache;
3744+
3745+
/// The incomplete metadata.
3746+
TargetRelativeDirectPointer<Runtime, TargetMetadata<Runtime>>
3747+
IncompleteMetadata;
3748+
3749+
/// The completion function. The pattern will always be null.
3750+
TargetRelativeDirectPointer<Runtime, MetadataCompleter>
3751+
CompletionFunction;
3752+
};
3753+
37123754
template <typename Runtime>
37133755
class TargetValueTypeDescriptor
37143756
: public TargetTypeContextDescriptor<Runtime> {
37153757
public:
3758+
using InPlaceMetadataInitialization =
3759+
TargetInPlaceValueMetadataInitialization<Runtime>;
3760+
3761+
const InPlaceMetadataInitialization &getInPlaceMetadataInitialization() const;
3762+
37163763
static bool classof(const TargetContextDescriptor<Runtime> *cd) {
37173764
return cd->getKind() == ContextDescriptorKind::Struct ||
37183765
cd->getKind() == ContextDescriptorKind::Enum;
@@ -3724,16 +3771,30 @@ template <typename Runtime>
37243771
class TargetStructDescriptor final
37253772
: public TargetValueTypeDescriptor<Runtime>,
37263773
public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
3727-
TargetTypeGenericContextDescriptorHeader> {
3774+
TargetTypeGenericContextDescriptorHeader,
3775+
TargetInPlaceValueMetadataInitialization<Runtime>> {
3776+
public:
3777+
using InPlaceMetadataInitialization =
3778+
TargetInPlaceValueMetadataInitialization<Runtime>;
3779+
37283780
private:
37293781
using TrailingGenericContextObjects =
37303782
TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
3731-
TargetTypeGenericContextDescriptorHeader>;
3783+
TargetTypeGenericContextDescriptorHeader,
3784+
InPlaceMetadataInitialization>;
37323785

37333786
using TrailingObjects =
37343787
typename TrailingGenericContextObjects::TrailingObjects;
37353788
friend TrailingObjects;
37363789

3790+
template<typename T>
3791+
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
3792+
3793+
using TrailingGenericContextObjects::numTrailingObjects;
3794+
size_t numTrailingObjects(OverloadToken<InPlaceMetadataInitialization>) const{
3795+
return this->hasInPlaceMetadataInitialization() ? 1 : 0;
3796+
}
3797+
37373798
public:
37383799
using TrailingGenericContextObjects::getGenericContext;
37393800
using TrailingGenericContextObjects::getGenericContextHeader;
@@ -3752,6 +3813,11 @@ class TargetStructDescriptor final
37523813
/// its stored properties.
37533814
bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
37543815

3816+
const InPlaceMetadataInitialization &getInPlaceMetadataInitialization() const{
3817+
assert(this->hasInPlaceMetadataInitialization());
3818+
return *this->template getTrailingObjects<InPlaceMetadataInitialization>();
3819+
}
3820+
37553821
static constexpr int32_t getGenericArgumentOffset() {
37563822
return TargetStructMetadata<Runtime>::getGenericArgumentOffset();
37573823
}
@@ -3767,16 +3833,30 @@ template <typename Runtime>
37673833
class TargetEnumDescriptor final
37683834
: public TargetValueTypeDescriptor<Runtime>,
37693835
public TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
3770-
TargetTypeGenericContextDescriptorHeader> {
3836+
TargetTypeGenericContextDescriptorHeader,
3837+
TargetInPlaceValueMetadataInitialization<Runtime>> {
3838+
public:
3839+
using InPlaceMetadataInitialization =
3840+
TargetInPlaceValueMetadataInitialization<Runtime>;
3841+
37713842
private:
37723843
using TrailingGenericContextObjects =
37733844
TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
3774-
TargetTypeGenericContextDescriptorHeader>;
3845+
TargetTypeGenericContextDescriptorHeader,
3846+
InPlaceMetadataInitialization>;
37753847

37763848
using TrailingObjects =
37773849
typename TrailingGenericContextObjects::TrailingObjects;
37783850
friend TrailingObjects;
37793851

3852+
template<typename T>
3853+
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
3854+
3855+
using TrailingGenericContextObjects::numTrailingObjects;
3856+
size_t numTrailingObjects(OverloadToken<InPlaceMetadataInitialization>) const{
3857+
return this->hasInPlaceMetadataInitialization() ? 1 : 0;
3858+
}
3859+
37803860
public:
37813861
using TrailingGenericContextObjects::getGenericContext;
37823862
using TrailingGenericContextObjects::getGenericContextHeader;
@@ -3813,6 +3893,11 @@ class TargetEnumDescriptor final
38133893
return TargetEnumMetadata<Runtime>::getGenericArgumentOffset();
38143894
}
38153895

3896+
const InPlaceMetadataInitialization &getInPlaceMetadataInitialization() const{
3897+
assert(this->hasInPlaceMetadataInitialization());
3898+
return *this->template getTrailingObjects<InPlaceMetadataInitialization>();
3899+
}
3900+
38163901
static bool classof(const TargetContextDescriptor<Runtime> *cd) {
38173902
return cd->getKind() == ContextDescriptorKind::Enum;
38183903
}
@@ -3901,6 +3986,21 @@ TargetTypeContextDescriptor<Runtime>::getGenericParams() const {
39013986
}
39023987
}
39033988

3989+
template<typename Runtime>
3990+
inline const TargetInPlaceValueMetadataInitialization<Runtime> &
3991+
TargetValueTypeDescriptor<Runtime>::getInPlaceMetadataInitialization() const {
3992+
switch (this->getKind()) {
3993+
case ContextDescriptorKind::Enum:
3994+
return llvm::cast<TargetEnumDescriptor<Runtime>>(this)
3995+
->getInPlaceMetadataInitialization();
3996+
case ContextDescriptorKind::Struct:
3997+
return llvm::cast<TargetStructDescriptor<Runtime>>(this)
3998+
->getInPlaceMetadataInitialization();
3999+
default:
4000+
swift_runtime_unreachable("Not a value type descriptor.");
4001+
}
4002+
}
4003+
39044004
} // end namespace swift
39054005

39064006
#pragma clang diagnostic pop

include/swift/ABI/MetadataValues.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,14 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
12021202
/// declarations associated with the same declaration.
12031203
IsSynthesizedRelatedEntity = 3,
12041204

1205+
/// Set if the type requires non-trivial but non-generic metadata
1206+
/// initialization. It may or may not be truly "in place" depending
1207+
/// on the kind of metadata.
1208+
///
1209+
/// Currently only meaningful for value descriptors, but will be
1210+
/// extended to class descriptors.
1211+
HasInPlaceMetadataInitialization = 4,
1212+
12051213
/// Set if the context descriptor is includes metadata for dynamically
12061214
/// constructing a class's vtables at metadata instantiation time.
12071215
///
@@ -1237,6 +1245,10 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
12371245
isSynthesizedRelatedEntity,
12381246
setIsSynthesizedRelatedEntity)
12391247

1248+
FLAGSET_DEFINE_FLAG_ACCESSORS(HasInPlaceMetadataInitialization,
1249+
hasInPlaceMetadataInitialization,
1250+
setHasInPlaceMetadataInitialization)
1251+
12401252
FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
12411253
class_hasVTable,
12421254
class_setHasVTable)

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ NODE(TypeMetadataAccessFunction)
183183
NODE(TypeMetadataCompletionFunction)
184184
NODE(TypeMetadataInstantiationCache)
185185
NODE(TypeMetadataInstantiationFunction)
186+
NODE(TypeMetadataInPlaceInitializationCache)
186187
NODE(TypeMetadataLazyCache)
187188
NODE(UncurriedFunctionType)
188189
#define REF_STORAGE(Name, ...) NODE(Name)

include/swift/IRGen/Linking.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ class LinkEntity {
163163
/// The pointer is a NominalTypeDecl*.
164164
TypeMetadataInstantiationFunction,
165165

166+
/// The in-place initialization cache for a generic nominal type.
167+
/// The pointer is a NominalTypeDecl*.
168+
TypeMetadataInPlaceInitializationCache,
169+
166170
/// The completion function for a generic or resilient nominal type.
167171
/// The pointer is a NominalTypeDecl*.
168172
TypeMetadataCompletionFunction,
@@ -503,12 +507,19 @@ class LinkEntity {
503507
return entity;
504508
}
505509

506-
static LinkEntity forTypeMetadataInstantiationFunction(NominalTypeDecl *decl){
510+
static LinkEntity forTypeMetadataInstantiationFunction(NominalTypeDecl *decl) {
507511
LinkEntity entity;
508512
entity.setForDecl(Kind::TypeMetadataInstantiationFunction, decl);
509513
return entity;
510514
}
511515

516+
static LinkEntity forTypeMetadataInPlaceInitializationCache(
517+
NominalTypeDecl *decl) {
518+
LinkEntity entity;
519+
entity.setForDecl(Kind::TypeMetadataInPlaceInitializationCache, decl);
520+
return entity;
521+
}
522+
512523
static LinkEntity forTypeMetadataCompletionFunction(NominalTypeDecl *decl) {
513524
LinkEntity entity;
514525
entity.setForDecl(Kind::TypeMetadataCompletionFunction, decl);

include/swift/Remote/MetadataReader.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,8 +1050,10 @@ class MetadataReader {
10501050
sizeof(flags)))
10511051
return nullptr;
10521052

1053+
TypeContextDescriptorFlags typeFlags(flags.getKindSpecificFlags());
10531054
unsigned baseSize = 0;
10541055
unsigned genericHeaderSize = sizeof(GenericContextDescriptorHeader);
1056+
unsigned inPlaceInitSize = 0;
10551057
bool hasVTable = false;
10561058
switch (auto kind = flags.getKind()) {
10571059
case ContextDescriptorKind::Module:
@@ -1067,16 +1069,23 @@ class MetadataReader {
10671069
case ContextDescriptorKind::Class:
10681070
baseSize = sizeof(TargetClassDescriptor<Runtime>);
10691071
genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
1070-
hasVTable = TypeContextDescriptorFlags(flags.getKindSpecificFlags())
1071-
.class_hasVTable();
1072+
hasVTable = typeFlags.class_hasVTable();
10721073
break;
10731074
case ContextDescriptorKind::Enum:
10741075
baseSize = sizeof(TargetEnumDescriptor<Runtime>);
10751076
genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
1077+
if (typeFlags.hasInPlaceMetadataInitialization()) {
1078+
inPlaceInitSize =
1079+
sizeof(TargetInPlaceValueMetadataInitialization<Runtime>);
1080+
}
10761081
break;
10771082
case ContextDescriptorKind::Struct:
10781083
baseSize = sizeof(TargetStructDescriptor<Runtime>);
10791084
genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
1085+
if (typeFlags.hasInPlaceMetadataInitialization()) {
1086+
inPlaceInitSize =
1087+
sizeof(TargetInPlaceValueMetadataInitialization<Runtime>);
1088+
}
10801089
break;
10811090
case ContextDescriptorKind::Protocol:
10821091
baseSize = sizeof(TargetProtocolDescriptorRef<Runtime>);
@@ -1122,7 +1131,7 @@ class MetadataReader {
11221131
+ header.VTableSize * sizeof(TargetMethodDescriptor<Runtime>);
11231132
}
11241133

1125-
unsigned size = baseSize + genericsSize + vtableSize;
1134+
unsigned size = baseSize + genericsSize + vtableSize + inPlaceInitSize;
11261135
auto buffer = (uint8_t *)malloc(size);
11271136
if (!Reader->readBytes(RemoteAddress(address), buffer, size)) {
11281137
free(buffer);

include/swift/Runtime/Metadata.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,13 @@ ClassMetadataBounds getResilientMetadataBounds(
335335
const ClassDescriptor *descriptor);
336336
int32_t getResilientImmediateMembersOffset(const ClassDescriptor *descriptor);
337337

338+
/// \brief Fetch a uniqued metadata object for a nominal type which requires
339+
/// in-place metadata initialization.
340+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
341+
MetadataResponse
342+
swift_getInPlaceMetadata(MetadataRequest request,
343+
const TypeContextDescriptor *description);
344+
338345
/// \brief Fetch a uniqued metadata object for a generic nominal type.
339346
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
340347
MetadataResponse

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,13 @@ FUNCTION(GetForeignWitnessTable, swift_getForeignWitnessTable, C_CC,
653653
ProtocolDescriptorPtrTy),
654654
ATTRS(NoUnwind, ReadNone))
655655

656+
// MetadataResponse swift_getInPlaceMetadata(MetadataRequest request,
657+
// TypeContextDescriptor *type);
658+
FUNCTION(GetInPlaceMetadata, swift_getInPlaceMetadata, SwiftCC,
659+
RETURNS(TypeMetadataResponseTy),
660+
ARGS(SizeTy, TypeContextDescriptorPtrTy),
661+
ATTRS(NoUnwind, ReadNone))
662+
656663
// MetadataResponse swift_getGenericMetadata(MetadataRequest request,
657664
// const void * const *arguments,
658665
// TypeContextDescriptor *type);

lib/Demangling/Demangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,9 @@ NodePointer Demangler::demangleMetatype() {
14691469
return createWithPoppedType(Node::Kind::TypeMetadataInstantiationFunction);
14701470
case 'r':
14711471
return createWithPoppedType(Node::Kind::TypeMetadataCompletionFunction);
1472+
case 'l':
1473+
return createWithPoppedType(
1474+
Node::Kind::TypeMetadataInPlaceInitializationCache);
14721475
case 'L':
14731476
return createWithPoppedType(Node::Kind::TypeMetadataLazyCache);
14741477
case 'm':

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ class NodePrinter {
429429
case Node::Kind::TypeMetadataCompletionFunction:
430430
case Node::Kind::TypeMetadataInstantiationCache:
431431
case Node::Kind::TypeMetadataInstantiationFunction:
432+
case Node::Kind::TypeMetadataInPlaceInitializationCache:
432433
case Node::Kind::TypeMetadataLazyCache:
433434
case Node::Kind::UncurriedFunctionType:
434435
#define REF_STORAGE(Name, ...) \
@@ -1509,6 +1510,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
15091510
Printer << "type metadata instantiation function for ";
15101511
print(Node->getChild(0));
15111512
return nullptr;
1513+
case Node::Kind::TypeMetadataInPlaceInitializationCache:
1514+
Printer << "type metadata in-place initialization cache for ";
1515+
print(Node->getChild(0));
1516+
return nullptr;
15121517
case Node::Kind::TypeMetadataCompletionFunction:
15131518
Printer << "type metadata completion function for ";
15141519
print(Node->getChild(0));

lib/Demangling/OldRemangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,11 @@ void Remangler::mangleTypeMetadataInstantiationFunction(Node *node) {
716716
mangleSingleChildNode(node); // type
717717
}
718718

719+
void Remangler::mangleTypeMetadataInPlaceInitializationCache(Node *node) {
720+
Out << "Ml";
721+
mangleSingleChildNode(node); // type
722+
}
723+
719724
void Remangler::mangleTypeMetadataCompletionFunction(Node *node) {
720725
Out << "Mr";
721726
mangleSingleChildNode(node); // type

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,6 +1766,11 @@ void Remangler::mangleTypeMetadataInstantiationFunction(Node *node) {
17661766
Buffer << "Mi";
17671767
}
17681768

1769+
void Remangler::mangleTypeMetadataInPlaceInitializationCache(Node *node) {
1770+
mangleSingleChildNode(node);
1771+
Buffer << "Ml";
1772+
}
1773+
17691774
void Remangler::mangleTypeMetadataCompletionFunction(Node *node) {
17701775
mangleSingleChildNode(node);
17711776
Buffer << "Mr";

0 commit comments

Comments
 (0)