Skip to content

Commit c55431c

Browse files
committed
Runtime: Add superclass constraint to existential type metadata
1 parent 890dbf1 commit c55431c

File tree

4 files changed

+121
-12
lines changed

4 files changed

+121
-12
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ class ExistentialTypeFlags {
404404
enum : int_type {
405405
NumWitnessTablesMask = 0x00FFFFFFU,
406406
ClassConstraintMask = 0x80000000U,
407-
SpecialProtocolMask = 0x7F000000U,
407+
HasSuperclassMask = 0x40000000U,
408+
SpecialProtocolMask = 0x3F000000U,
408409
SpecialProtocolShift = 24U,
409410
};
410411
int_type Data;
@@ -421,6 +422,11 @@ class ExistentialTypeFlags {
421422
| (bool(c) ? ClassConstraintMask : 0));
422423
}
423424
constexpr ExistentialTypeFlags
425+
withHasSuperclass(bool hasSuperclass) const {
426+
return ExistentialTypeFlags((Data & ~HasSuperclassMask)
427+
| (hasSuperclass ? HasSuperclassMask : 0));
428+
}
429+
constexpr ExistentialTypeFlags
424430
withSpecialProtocol(SpecialProtocol sp) const {
425431
return ExistentialTypeFlags((Data & ~SpecialProtocolMask)
426432
| (int_type(sp) << SpecialProtocolShift));
@@ -433,7 +439,11 @@ class ExistentialTypeFlags {
433439
ProtocolClassConstraint getClassConstraint() const {
434440
return ProtocolClassConstraint(bool(Data & ClassConstraintMask));
435441
}
436-
442+
443+
bool hasSuperclassConstraint() const {
444+
return bool(Data & HasSuperclassMask);
445+
}
446+
437447
/// Return whether this existential type represents an uncomposed special
438448
/// protocol.
439449
SpecialProtocol getSpecialProtocol() const {

include/swift/Runtime/Metadata.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2445,9 +2445,16 @@ struct TargetExistentialTypeMetadata : public TargetMetadata<Runtime> {
24452445
return Flags.getClassConstraint() == ProtocolClassConstraint::Class;
24462446
}
24472447

2448-
const Metadata *getSuperclassConstraint() const {
2449-
// FIXME
2450-
return nullptr;
2448+
const TargetMetadata<Runtime> *getSuperclassConstraint() const {
2449+
if (!Flags.hasSuperclassConstraint())
2450+
return nullptr;
2451+
2452+
// Get a pointer to tail-allocated storage for this metadata record.
2453+
auto Pointer = reinterpret_cast<
2454+
ConstTargetMetadataPointer<Runtime, TargetMetadata> const *>(this + 1);
2455+
2456+
// The superclass immediately follows the list of protocol descriptors.
2457+
return Pointer[Protocols.NumProtocols];
24512458
}
24522459

24532460
static bool classof(const TargetMetadata<Runtime> *metadata) {

stdlib/public/runtime/Metadata.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2085,10 +2085,16 @@ class ExistentialCacheEntry {
20852085
}
20862086

20872087
static size_t getExtraAllocationSize(Key key) {
2088-
return sizeof(const ProtocolDescriptor *) * key.NumProtocols;
2088+
return (sizeof(const ProtocolDescriptor *) * key.NumProtocols +
2089+
(key.SuperclassConstraint != nullptr
2090+
? sizeof(const Metadata *)
2091+
: 0));
20892092
}
20902093
size_t getExtraAllocationSize() const {
2091-
return sizeof(const ProtocolDescriptor *) * Data.Protocols.NumProtocols;
2094+
return (sizeof(const ProtocolDescriptor *) * Data.Protocols.NumProtocols +
2095+
(Data.Flags.hasSuperclassConstraint()
2096+
? sizeof(const Metadata *)
2097+
: 0));
20922098
}
20932099
};
20942100

@@ -2548,9 +2554,18 @@ ExistentialCacheEntry::ExistentialCacheEntry(Key key) {
25482554
.withNumWitnessTables(numWitnessTables)
25492555
.withClassConstraint(key.ClassConstraint)
25502556
.withSpecialProtocol(special);
2551-
// FIXME
2552-
//Data.Superclass = key.superclassConstraint;
2553-
assert(!key.SuperclassConstraint);
2557+
2558+
if (key.SuperclassConstraint != nullptr) {
2559+
Data.Flags = Data.Flags.withHasSuperclass(true);
2560+
2561+
// Get a pointer to tail-allocated storage for this metadata record.
2562+
auto Pointer = reinterpret_cast<
2563+
const Metadata **>(&Data + 1);
2564+
2565+
// The superclass immediately follows the list of protocol descriptors.
2566+
Pointer[key.NumProtocols] = key.SuperclassConstraint;
2567+
}
2568+
25542569
Data.Protocols.NumProtocols = key.NumProtocols;
25552570
for (size_t i = 0; i < key.NumProtocols; ++i)
25562571
Data.Protocols[i] = key.Protocols[i];

unittests/runtime/Metadata.cpp

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,8 @@ TEST(MetadataTest, getExistentialMetadata) {
402402
EXPECT_EQ(0U, any->Protocols.NumProtocols);
403403
EXPECT_EQ(SpecialProtocol::None,
404404
any->Flags.getSpecialProtocol());
405+
EXPECT_EQ(nullptr,
406+
any->getSuperclassConstraint());
405407
return any;
406408
});
407409

@@ -420,6 +422,8 @@ TEST(MetadataTest, getExistentialMetadata) {
420422
EXPECT_EQ(&ProtocolA, a->Protocols[0]);
421423
EXPECT_EQ(SpecialProtocol::None,
422424
a->Flags.getSpecialProtocol());
425+
EXPECT_EQ(nullptr,
426+
a->getSuperclassConstraint());
423427
return a;
424428
});
425429

@@ -439,6 +443,8 @@ TEST(MetadataTest, getExistentialMetadata) {
439443
EXPECT_EQ(&ProtocolB, b->Protocols[0]);
440444
EXPECT_EQ(SpecialProtocol::None,
441445
b->Flags.getSpecialProtocol());
446+
EXPECT_EQ(nullptr,
447+
b->getSuperclassConstraint());
442448
return b;
443449
});
444450

@@ -472,8 +478,8 @@ TEST(MetadataTest, getExistentialMetadata) {
472478
|| (ab->Protocols[0]==&ProtocolB && ab->Protocols[1]==&ProtocolA));
473479
EXPECT_EQ(SpecialProtocol::None,
474480
ab->Flags.getSpecialProtocol());
475-
EXPECT_EQ(SpecialProtocol::None,
476-
ba->Flags.getSpecialProtocol());
481+
EXPECT_EQ(nullptr,
482+
ab->getSuperclassConstraint());
477483
return ab;
478484
});
479485

@@ -494,6 +500,8 @@ TEST(MetadataTest, getExistentialMetadata) {
494500
EXPECT_EQ(SpecialProtocol::None,
495501
classConstrained->Flags.getSpecialProtocol());
496502
EXPECT_EQ(&ProtocolClassConstrained, classConstrained->Protocols[0]);
503+
EXPECT_EQ(nullptr,
504+
classConstrained->getSuperclassConstraint());
497505
return classConstrained;
498506
});
499507

@@ -514,6 +522,8 @@ TEST(MetadataTest, getExistentialMetadata) {
514522
EXPECT_EQ(SpecialProtocol::None,
515523
noWitnessTable->Flags.getSpecialProtocol());
516524
EXPECT_EQ(&ProtocolNoWitnessTable, noWitnessTable->Protocols[0]);
525+
EXPECT_EQ(nullptr,
526+
noWitnessTable->getSuperclassConstraint());
517527
return noWitnessTable;
518528
});
519529

@@ -536,6 +546,8 @@ TEST(MetadataTest, getExistentialMetadata) {
536546
EXPECT_EQ(3U, mixedWitnessTable->Protocols.NumProtocols);
537547
EXPECT_EQ(SpecialProtocol::None,
538548
mixedWitnessTable->Flags.getSpecialProtocol());
549+
EXPECT_EQ(nullptr,
550+
mixedWitnessTable->getSuperclassConstraint());
539551
return mixedWitnessTable;
540552
});
541553

@@ -561,6 +573,8 @@ TEST(MetadataTest, getExistentialMetadata) {
561573
special->Flags.getSpecialProtocol());
562574
EXPECT_EQ(ExpectedErrorValueWitnesses,
563575
special->getValueWitnesses());
576+
EXPECT_EQ(nullptr,
577+
special->getSuperclassConstraint());
564578
return special;
565579
});
566580

@@ -582,6 +596,8 @@ TEST(MetadataTest, getExistentialMetadata) {
582596
special->Flags.getSpecialProtocol());
583597
EXPECT_NE(ExpectedErrorValueWitnesses,
584598
special->getValueWitnesses());
599+
EXPECT_EQ(nullptr,
600+
special->getSuperclassConstraint());
585601
return special;
586602
});
587603
}
@@ -710,6 +726,8 @@ TEST(MetadataTest, getExistentialTypeMetadata_opaque) {
710726
EXPECT_EQ(alignof(void*), ex1->getValueWitnesses()->getAlignment());
711727
EXPECT_FALSE(ex1->getValueWitnesses()->isPOD());
712728
EXPECT_FALSE(ex1->getValueWitnesses()->isBitwiseTakable());
729+
EXPECT_EQ(nullptr,
730+
ex1->getSuperclassConstraint());
713731
return ex1;
714732
});
715733

@@ -726,6 +744,8 @@ TEST(MetadataTest, getExistentialTypeMetadata_opaque) {
726744
EXPECT_EQ(alignof(void*), ex2->getValueWitnesses()->getAlignment());
727745
EXPECT_FALSE(ex2->getValueWitnesses()->isPOD());
728746
EXPECT_FALSE(ex2->getValueWitnesses()->isBitwiseTakable());
747+
EXPECT_EQ(nullptr,
748+
ex2->getSuperclassConstraint());
729749
return ex2;
730750
});
731751

@@ -742,6 +762,8 @@ TEST(MetadataTest, getExistentialTypeMetadata_opaque) {
742762
EXPECT_EQ(alignof(void*), ex3->getValueWitnesses()->getAlignment());
743763
EXPECT_FALSE(ex3->getValueWitnesses()->isPOD());
744764
EXPECT_FALSE(ex3->getValueWitnesses()->isBitwiseTakable());
765+
EXPECT_EQ(nullptr,
766+
ex3->getSuperclassConstraint());
745767
return ex3;
746768
});
747769
}
@@ -760,6 +782,8 @@ TEST(MetadataTest, getExistentialTypeMetadata_class) {
760782
EXPECT_EQ(alignof(void*), ex1->getValueWitnesses()->getAlignment());
761783
EXPECT_FALSE(ex1->getValueWitnesses()->isPOD());
762784
EXPECT_TRUE(ex1->getValueWitnesses()->isBitwiseTakable());
785+
EXPECT_EQ(nullptr,
786+
ex1->getSuperclassConstraint());
763787
return ex1;
764788
});
765789

@@ -776,6 +800,8 @@ TEST(MetadataTest, getExistentialTypeMetadata_class) {
776800
EXPECT_EQ(alignof(void*), ex2->getValueWitnesses()->getAlignment());
777801
EXPECT_FALSE(ex2->getValueWitnesses()->isPOD());
778802
EXPECT_TRUE(ex2->getValueWitnesses()->isBitwiseTakable());
803+
EXPECT_EQ(nullptr,
804+
ex2->getSuperclassConstraint());
779805
return ex2;
780806
});
781807

@@ -792,10 +818,61 @@ TEST(MetadataTest, getExistentialTypeMetadata_class) {
792818
EXPECT_EQ(alignof(void*), ex3->getValueWitnesses()->getAlignment());
793819
EXPECT_FALSE(ex3->getValueWitnesses()->isPOD());
794820
EXPECT_TRUE(ex3->getValueWitnesses()->isBitwiseTakable());
821+
EXPECT_EQ(nullptr,
822+
ex3->getSuperclassConstraint());
795823
return ex3;
796824
});
797825
}
798826

827+
TEST(MetadataTest, getExistentialTypeMetadata_subclass) {
828+
RaceTest_ExpectEqual<const ExistentialTypeMetadata *>(
829+
[&]() -> const ExistentialTypeMetadata * {
830+
const ProtocolDescriptor *protoList1[] = {
831+
&OpaqueProto1
832+
};
833+
auto ex1 = swift_getExistentialTypeMetadata(ProtocolClassConstraint::Class,
834+
/*superclass=*/&MetadataTest2,
835+
1, protoList1);
836+
EXPECT_EQ(MetadataKind::Existential, ex1->getKind());
837+
EXPECT_EQ(2 * sizeof(void*), ex1->getValueWitnesses()->getSize());
838+
EXPECT_EQ(alignof(void*), ex1->getValueWitnesses()->getAlignment());
839+
EXPECT_FALSE(ex1->getValueWitnesses()->isPOD());
840+
EXPECT_TRUE(ex1->getValueWitnesses()->isBitwiseTakable());
841+
EXPECT_EQ(ProtocolClassConstraint::Class,
842+
ex1->Flags.getClassConstraint());
843+
EXPECT_EQ(1U, ex1->Protocols.NumProtocols);
844+
EXPECT_EQ(&OpaqueProto1, ex1->Protocols[0]);
845+
EXPECT_EQ(&MetadataTest2, ex1->getSuperclassConstraint());
846+
return ex1;
847+
});
848+
849+
850+
RaceTest_ExpectEqual<const ExistentialTypeMetadata *>(
851+
[&]() -> const ExistentialTypeMetadata * {
852+
const ProtocolDescriptor *protoList2[] = {
853+
&OpaqueProto1,
854+
&ClassProto1
855+
};
856+
auto ex2 = swift_getExistentialTypeMetadata(ProtocolClassConstraint::Class,
857+
/*superclass=*/&MetadataTest2,
858+
2, protoList2);
859+
EXPECT_EQ(MetadataKind::Existential, ex2->getKind());
860+
EXPECT_EQ(3 * sizeof(void*), ex2->getValueWitnesses()->getSize());
861+
EXPECT_EQ(alignof(void*), ex2->getValueWitnesses()->getAlignment());
862+
EXPECT_FALSE(ex2->getValueWitnesses()->isPOD());
863+
EXPECT_TRUE(ex2->getValueWitnesses()->isBitwiseTakable());
864+
EXPECT_EQ(ProtocolClassConstraint::Class,
865+
ex2->Flags.getClassConstraint());
866+
EXPECT_EQ(2U, ex2->Protocols.NumProtocols);
867+
EXPECT_TRUE((ex2->Protocols[0] == &OpaqueProto1 &&
868+
ex2->Protocols[1] == &ClassProto1) ||
869+
(ex2->Protocols[0] == &ClassProto1 &&
870+
ex2->Protocols[1] == &OpaqueProto1));
871+
EXPECT_EQ(&MetadataTest2, ex2->getSuperclassConstraint());
872+
return ex2;
873+
});
874+
}
875+
799876
static const void *AllocatedBuffer = nullptr;
800877
static const void *DeallocatedBuffer = nullptr;
801878

0 commit comments

Comments
 (0)