Skip to content

Commit a5a40c7

Browse files
committed
Runtime/IRGen: Preliminary plumbing for subclass existentials
1 parent 5993b63 commit a5a40c7

File tree

6 files changed

+174
-51
lines changed

6 files changed

+174
-51
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2441,6 +2441,11 @@ struct TargetExistentialTypeMetadata : public TargetMetadata<Runtime> {
24412441
return Flags.getClassConstraint() == ProtocolClassConstraint::Class;
24422442
}
24432443

2444+
const Metadata *getSuperclassConstraint() const {
2445+
// FIXME
2446+
return nullptr;
2447+
}
2448+
24442449
static bool classof(const TargetMetadata<Runtime> *metadata) {
24452450
return metadata->getKind() == MetadataKind::Existential;
24462451
}
@@ -3176,7 +3181,9 @@ swift_getExistentialMetatypeMetadata(const Metadata *instanceType);
31763181
/// referenced by \c protocols will be sorted in-place.
31773182
SWIFT_RT_ENTRY_VISIBILITY
31783183
const ExistentialTypeMetadata *
3179-
swift_getExistentialTypeMetadata(size_t numProtocols,
3184+
swift_getExistentialTypeMetadata(ProtocolClassConstraint classConstraint,
3185+
const Metadata *superclassConstraint,
3186+
size_t numProtocols,
31803187
const ProtocolDescriptor **protocols)
31813188
SWIFT_CC(RegisterPreservingCC);
31823189

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -791,12 +791,17 @@ FUNCTION(GetTupleMetadata3, swift_getTupleTypeMetadata3, DefaultCC,
791791
Int8PtrTy, WitnessTablePtrTy),
792792
ATTRS(NoUnwind, ReadOnly))
793793

794-
// Metadata *swift_getExistentialTypeMetadata(size_t numProtocols,
794+
// Metadata *swift_getExistentialTypeMetadata(
795+
// ProtocolClassConstraint classConstraint,
796+
// const Metadata *superclassConstraint,
797+
// size_t numProtocols,
795798
// const protocol_descriptor_t * const *protocols);
799+
//
800+
// Note: ProtocolClassConstraint::Class is 0, ::Any is 1.
796801
FUNCTION(GetExistentialMetadata,
797802
swift_getExistentialTypeMetadata, RegisterPreservingCC,
798803
RETURNS(TypeMetadataPtrTy),
799-
ARGS(SizeTy,
804+
ARGS(Int1Ty, TypeMetadataPtrTy, SizeTy,
800805
ProtocolDescriptorPtrTy->getPointerTo()),
801806
ATTRS(NoUnwind, ReadOnly))
802807

lib/IRGen/GenMeta.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/ABI/MetadataValues.h"
1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/CanTypeVisitor.h"
20+
#include "swift/AST/ExistentialLayout.h"
2021
#include "swift/AST/Decl.h"
2122
#include "swift/AST/IRGenOptions.h"
2223
#include "swift/AST/SubstitutionMap.h"
@@ -917,9 +918,13 @@ namespace {
917918
}
918919

919920
llvm::Value *emitExistentialTypeMetadata(CanType type) {
920-
SmallVector<ProtocolDecl*, 2> protocols;
921-
type.getExistentialTypeProtocols(protocols);
922-
921+
if (auto metatype = tryGetLocal(type))
922+
return metatype;
923+
924+
auto layout = type.getExistentialLayout();
925+
926+
auto protocols = layout.getProtocols();
927+
923928
// Collect references to the protocol descriptors.
924929
auto descriptorArrayTy
925930
= llvm::ArrayType::get(IGF.IGM.ProtocolDescriptorPtrTy,
@@ -933,16 +938,30 @@ namespace {
933938
IGF.IGM.ProtocolDescriptorPtrTy->getPointerTo());
934939

935940
unsigned index = 0;
936-
for (auto *p : protocols) {
937-
llvm::Value *ref = emitProtocolDescriptorRef(IGF, p);
941+
for (auto *protoTy : protocols) {
942+
auto *protoDecl = protoTy->getDecl();
943+
llvm::Value *ref = emitProtocolDescriptorRef(IGF, protoDecl);
938944
Address slot = IGF.Builder.CreateConstArrayGEP(descriptorArray,
939945
index, IGF.IGM.getPointerSize());
940946
IGF.Builder.CreateStore(ref, slot);
941947
++index;
942948
}
943-
949+
950+
// Note: ProtocolClassConstraint::Class is 0, ::Any is 1.
951+
auto classConstraint =
952+
llvm::ConstantInt::get(IGF.IGM.Int1Ty,
953+
!layout.requiresClass);
954+
llvm::Value *superclassConstraint =
955+
llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy);
956+
if (layout.superclass) {
957+
superclassConstraint = IGF.emitTypeMetadataRef(
958+
CanType(layout.superclass));
959+
}
960+
944961
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetExistentialMetadataFn(),
945-
{IGF.IGM.getSize(Size(protocols.size())),
962+
{classConstraint,
963+
superclassConstraint,
964+
IGF.IGM.getSize(Size(protocols.size())),
946965
descriptorArray.getAddress()});
947966
call->setDoesNotThrow();
948967
IGF.Builder.CreateLifetimeEnd(descriptorArray,

stdlib/public/runtime/Metadata.cpp

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,7 +2047,9 @@ class ExistentialCacheEntry {
20472047
FullMetadata<ExistentialTypeMetadata> Data;
20482048

20492049
struct Key {
2050-
size_t NumProtocols;
2050+
const Metadata *SuperclassConstraint;
2051+
ProtocolClassConstraint ClassConstraint : 1;
2052+
size_t NumProtocols : 31;
20512053
const ProtocolDescriptor * const *Protocols;
20522054
};
20532055

@@ -2058,6 +2060,14 @@ class ExistentialCacheEntry {
20582060
}
20592061

20602062
int compareWithKey(Key key) const {
2063+
if (auto result = compareIntegers(key.ClassConstraint,
2064+
Data.Flags.getClassConstraint()))
2065+
return result;
2066+
2067+
if (auto result = comparePointers(key.SuperclassConstraint,
2068+
Data.getSuperclassConstraint()))
2069+
return result;
2070+
20612071
if (auto result = compareIntegers(key.NumProtocols,
20622072
Data.Protocols.NumProtocols))
20632073
return result;
@@ -2195,7 +2205,9 @@ ClassExistentialValueWitnessTables;
21952205
/// Instantiate a value witness table for a class-constrained existential
21962206
/// container with the given number of witness table pointers.
21972207
static const ExtraInhabitantsValueWitnessTable *
2198-
getClassExistentialValueWitnesses(unsigned numWitnessTables) {
2208+
getClassExistentialValueWitnesses(const Metadata *superclass,
2209+
unsigned numWitnessTables) {
2210+
// FIXME: If the superclass is not @objc, use native reference counting.
21992211
if (numWitnessTables == 0) {
22002212
#if SWIFT_OBJC_INTEROP
22012213
return &VALUE_WITNESS_SYM(BO);
@@ -2245,6 +2257,7 @@ ClassExistentialValueWitnessTableCacheEntry(unsigned numWitnessTables) {
22452257
/// shared specialized table for common cases.
22462258
static const ValueWitnessTable *
22472259
getExistentialValueWitnesses(ProtocolClassConstraint classConstraint,
2260+
const Metadata *superclassConstraint,
22482261
unsigned numWitnessTables,
22492262
SpecialProtocol special) {
22502263
// Use special representation for special protocols.
@@ -2266,8 +2279,10 @@ getExistentialValueWitnesses(ProtocolClassConstraint classConstraint,
22662279

22672280
switch (classConstraint) {
22682281
case ProtocolClassConstraint::Class:
2269-
return getClassExistentialValueWitnesses(numWitnessTables);
2282+
return getClassExistentialValueWitnesses(superclassConstraint,
2283+
numWitnessTables);
22702284
case ProtocolClassConstraint::Any:
2285+
assert(superclassConstraint == nullptr);
22712286
return getOpaqueExistentialValueWitnesses(numWitnessTables);
22722287
}
22732288

@@ -2472,44 +2487,66 @@ ExistentialTypeMetadata::getWitnessTable(const OpaqueValue *container,
24722487
/// \brief Fetch a uniqued metadata for an existential type. The array
24732488
/// referenced by \c protocols will be sorted in-place.
24742489
const ExistentialTypeMetadata *
2475-
swift::swift_getExistentialTypeMetadata(size_t numProtocols,
2490+
swift::swift_getExistentialTypeMetadata(ProtocolClassConstraint classConstraint,
2491+
const Metadata *superclassConstraint,
2492+
size_t numProtocols,
24762493
const ProtocolDescriptor **protocols)
24772494
SWIFT_CC(RegisterPreservingCC_IMPL) {
24782495

24792496
// Sort the protocol set.
24802497
std::sort(protocols, protocols + numProtocols);
24812498

2482-
ExistentialCacheEntry::Key key = { numProtocols, protocols };
2499+
ExistentialCacheEntry::Key key = {
2500+
superclassConstraint, classConstraint, numProtocols, protocols
2501+
};
24832502
return &ExistentialTypes.getOrInsert(key).first->Data;
24842503
}
24852504

24862505
ExistentialCacheEntry::ExistentialCacheEntry(Key key) {
24872506
// Calculate the class constraint and number of witness tables for the
24882507
// protocol set.
24892508
unsigned numWitnessTables = 0;
2490-
ProtocolClassConstraint classConstraint = ProtocolClassConstraint::Any;
24912509
for (auto p : make_range(key.Protocols, key.Protocols + key.NumProtocols)) {
2492-
if (p->Flags.needsWitnessTable()) {
2510+
if (p->Flags.needsWitnessTable())
24932511
++numWitnessTables;
2494-
}
2495-
if (p->Flags.getClassConstraint() == ProtocolClassConstraint::Class)
2512+
}
2513+
2514+
#ifndef NDEBUG
2515+
// Verify the class constraint.
2516+
{
2517+
auto classConstraint = ProtocolClassConstraint::Any;
2518+
2519+
if (key.SuperclassConstraint)
24962520
classConstraint = ProtocolClassConstraint::Class;
2521+
else {
2522+
for (auto p : make_range(key.Protocols, key.Protocols + key.NumProtocols)) {
2523+
if (p->Flags.getClassConstraint() == ProtocolClassConstraint::Class)
2524+
classConstraint = ProtocolClassConstraint::Class;
2525+
}
2526+
}
2527+
2528+
assert(classConstraint == key.ClassConstraint);
24972529
}
2530+
#endif
24982531

24992532
// Get the special protocol kind for an uncomposed protocol existential.
25002533
// Protocol compositions are currently never special.
25012534
auto special = SpecialProtocol::None;
25022535
if (key.NumProtocols == 1)
25032536
special = key.Protocols[0]->Flags.getSpecialProtocol();
2504-
2537+
25052538
Data.setKind(MetadataKind::Existential);
2506-
Data.ValueWitnesses = getExistentialValueWitnesses(classConstraint,
2539+
Data.ValueWitnesses = getExistentialValueWitnesses(key.ClassConstraint,
2540+
key.SuperclassConstraint,
25072541
numWitnessTables,
25082542
special);
25092543
Data.Flags = ExistentialTypeFlags()
25102544
.withNumWitnessTables(numWitnessTables)
2511-
.withClassConstraint(classConstraint)
2545+
.withClassConstraint(key.ClassConstraint)
25122546
.withSpecialProtocol(special);
2547+
// FIXME
2548+
//Data.Superclass = key.superclassConstraint;
2549+
assert(!key.SuperclassConstraint);
25132550
Data.Protocols.NumProtocols = key.NumProtocols;
25142551
for (size_t i = 0; i < key.NumProtocols; ++i)
25152552
Data.Protocols[i] = key.Protocols[i];

test/IRGen/protocol_metadata.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,20 @@ func protocol_types(_ a: A,
8080
abc: A & B & C,
8181
abco: A & B & C & O) {
8282
// CHECK: store %swift.protocol* @_T017protocol_metadata1AMp
83-
// CHECK: call %swift.type* @swift_rt_swift_getExistentialTypeMetadata(i64 1, %swift.protocol** {{%.*}})
83+
// CHECK: call %swift.type* @swift_rt_swift_getExistentialTypeMetadata(i1 true, %swift.type* null, i64 1, %swift.protocol** {{%.*}})
8484
reify_metadata(a)
8585
// CHECK: store %swift.protocol* @_T017protocol_metadata1AMp
8686
// CHECK: store %swift.protocol* @_T017protocol_metadata1BMp
8787
// CHECK: store %swift.protocol* @_T017protocol_metadata1CMp
88-
// CHECK: call %swift.type* @swift_rt_swift_getExistentialTypeMetadata(i64 3, %swift.protocol** {{%.*}})
88+
// CHECK: call %swift.type* @swift_rt_swift_getExistentialTypeMetadata(i1 false, %swift.type* null, i64 3, %swift.protocol** {{%.*}})
8989
reify_metadata(abc)
9090
// CHECK: store %swift.protocol* @_T017protocol_metadata1AMp
9191
// CHECK: store %swift.protocol* @_T017protocol_metadata1BMp
9292
// CHECK: store %swift.protocol* @_T017protocol_metadata1CMp
9393
// CHECK: [[O_REF:%.*]] = load i8*, i8** @"\01l_OBJC_PROTOCOL_REFERENCE_$__TtP17protocol_metadata1O_"
9494
// CHECK: [[O_REF_BITCAST:%.*]] = bitcast i8* [[O_REF]] to %swift.protocol*
9595
// CHECK: store %swift.protocol* [[O_REF_BITCAST]]
96-
// CHECK: call %swift.type* @swift_rt_swift_getExistentialTypeMetadata(i64 4, %swift.protocol** {{%.*}})
96+
// CHECK: call %swift.type* @swift_rt_swift_getExistentialTypeMetadata(i1 false, %swift.type* null, i64 4, %swift.protocol** {{%.*}})
9797
reify_metadata(abco)
9898
}
9999

0 commit comments

Comments
 (0)