Skip to content

Commit a59e2a3

Browse files
committed
Unique extended existential shapes using the generalized AST type.
I wrote out this whole analysis of why different existential types might have the same logical content, and then I turned around and immediately uniqued existential shapes purely by logical content rather than the (generalized) formal type. Oh well. At least it's not too late to make ABI changes like this. We now store a reference to a mangling of the generalized formal type directly in the shape. This type alone is sufficient to unique the shape: - By the nature of the generalization algorithm, every type parameter in the generalization signature should be mentioned in the generalized formal type in a deterministic order. - By the nature of the generalization algorithm, every other requirement in the generalization signature should be implied by the positions in which generalization type parameters appear (e.g. because the formal type is C<T> & P, where C constrains its type parameter for well-formedness). - The requirement signature and type expression are extracted from the existential type. As a result, we no longer rely on computing a unique hash at compile time. Storing this separately from the requirement signature potentially allows runtimes with general shape support to work with future extensions to existential types even if they cannot demangle the generalized formal type. Storing the generalized formal type also allows us to easily and reliably extract the formal type of the existential. Otherwise, it's quite a heroic endeavor to match requirements back up with primary associated types. Doing so would also only allows us to extract *some* matching formal type, not necessarily the *right* formal type. So there's some good synergy here.
1 parent 8f6f198 commit a59e2a3

File tree

18 files changed

+191
-233
lines changed

18 files changed

+191
-233
lines changed

docs/ABI/Mangling.rst

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ Types
637637
type ::= protocol-list 'p' // existential type
638638
type ::= protocol-list superclass 'Xc' // existential type with superclass
639639
type ::= protocol-list 'Xl' // existential type with AnyObject
640-
type ::= protocol-list 'y' (type* '_')* type* retroactive-conformance* 'Xp' // parameterized protocol type
640+
type ::= protocol-list 'y' (type* '_')* type* retroactive-conformance* 'XP' // parameterized protocol type
641641
type ::= type-list 't' // tuple
642642
type ::= type generic-signature 'u' // generic type
643643
type ::= 'x' // generic param, depth=0, idx=0
@@ -918,21 +918,9 @@ root protocol conformance, and the suffix 'g'.
918918

919919
::
920920

921-
// No generalization signature, no type expression.
922-
extended-existential-shape ::= generic-signature 'Xg' extended-existential-value-storage
923-
924-
// Generalization signature (the second one), no type expression.
925-
extended-existential-shape ::= generic-signature generic-signature 'XG' extended-existential-value-storage
926-
927-
// No generalization signature, type expression.
928-
extended-existential-shape ::= generic-signature type 'Xh' extended-existential-value-storage
929-
930-
// Generalization signature (the second one), type expression.
931-
extended-existential-shape ::= generic-signature generic-signature type 'Xh' extended-existential-value-storage
932-
933-
extended-existential-value-storage ::= 'o' // opaque
934-
extended-existential-value-storage ::= 'c' // class
935-
extended-existential-value-storage ::= 'm' // metatype
921+
// No generalization signature.
922+
extended-existential-shape ::= type 'Xg' // no generalization signature
923+
extended-existential-shape ::= generic-signature type 'XG'
936924

937925
Identifiers
938926
~~~~~~~~~~~

include/swift/ABI/Metadata.h

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,32 @@ struct TargetExtendedExistentialTypeShape
18551855
/// Flags for the existential shape.
18561856
ExtendedExistentialTypeShapeFlags Flags;
18571857

1858+
/// The mangling of the generalized existential type, expressed
1859+
/// (if necessary) in terms of the type parameters of the
1860+
/// generalization signature.
1861+
///
1862+
/// If this shape is non-unique, this is always a flat string, not a
1863+
/// "symbolic" mangling which can contain relative references. This
1864+
/// allows uniquing to simply compare the string content.
1865+
///
1866+
/// In principle, the content of the requirement signature and type
1867+
/// expression are derivable from this type. We store them separately
1868+
/// so that code which only needs to work with the logical content of
1869+
/// the type doesn't have to break down the existential type string.
1870+
/// This both (1) allows those operations to work substantially more
1871+
/// efficiently (and without needing code to produce a requirement
1872+
/// signature from an existential type to exist in the runtime) and
1873+
/// (2) potentially allows old runtimes to support new existential
1874+
/// types without as much invasive code.
1875+
///
1876+
/// The content of this string is *not* necessarily derivable from
1877+
/// the requirement signature. This is because there may be multiple
1878+
/// existential types that have equivalent logical content but which
1879+
/// we nonetheless distinguish at compile time. Storing this also
1880+
/// allows us to far more easily produce a formal type from this
1881+
/// shape reflectively.
1882+
RelativeStringPointer ExistentialType;
1883+
18581884
/// The header describing the requirement signature of the existential.
18591885
TargetGenericContextDescriptorHeader<Runtime> ReqSigHeader;
18601886

@@ -2024,6 +2050,9 @@ struct UniqueHash {
20242050

20252051
/// A descriptor for an extended existential type descriptor which
20262052
/// needs to be uniqued at runtime.
2053+
///
2054+
/// Uniquing is performed by comparing the existential type strings
2055+
/// of the shapes.
20272056
template <typename Runtime>
20282057
struct TargetNonUniqueExtendedExistentialTypeShape {
20292058
/// A reference to memory that can be used to cache a globally-unique
@@ -2032,10 +2061,12 @@ struct TargetNonUniqueExtendedExistentialTypeShape {
20322061
std::atomic<ConstTargetMetadataPointer<Runtime,
20332062
TargetExtendedExistentialTypeShape>>> UniqueCache;
20342063

2035-
/// A hash of the mangling of the existential shape.
2036-
///
2037-
/// TODO: describe that mangling here
2038-
UniqueHash Hash;
2064+
llvm::StringRef getExistentialTypeStringForUniquing() const {
2065+
// When we have a non-unique shape, we're guaranteed that
2066+
// ExistentialType contains no symbolic references, so we can just
2067+
// recover it this way rather than having to parse it.
2068+
return LocalCopy.ExistentialType.get();
2069+
}
20392070

20402071
/// The local copy of the existential shape descriptor.
20412072
TargetExtendedExistentialTypeShape<Runtime> LocalCopy;

include/swift/Demangling/DemangleNodes.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,6 @@ NODE(OpaqueReturnTypeIndexed)
336336
NODE(BackDeploymentThunk)
337337
NODE(BackDeploymentFallback)
338338
NODE(ExtendedExistentialTypeShape)
339-
NODE(ExtendedExistentialValueStorage)
340339
NODE(Uniquable)
341340

342341
#undef CONTEXT_NODE

include/swift/IRGen/Linking.h

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,6 @@ class LinkEntity {
125125
ExtendedExistentialIsUniqueMask = 0x100,
126126
ExtendedExistentialIsSharedShift = 9,
127127
ExtendedExistentialIsSharedMask = 0x200,
128-
ExtendedExistentialMetatypeDepthShift = 10,
129-
ExtendedExistentialMetatypeDepthMask =
130-
~(KindMask | ExtendedExistentialIsUniqueMask |
131-
ExtendedExistentialIsSharedMask),
132128
};
133129
#define LINKENTITY_SET_FIELD(field, value) (value << field##Shift)
134130
#define LINKENTITY_GET_FIELD(value, field) ((value & field##Mask) >> field##Shift)
@@ -1368,9 +1364,7 @@ class LinkEntity {
13681364
}
13691365

13701366
static LinkEntity forExtendedExistentialTypeShape(CanGenericSignature genSig,
1371-
CanExistentialType
1372-
existentialType,
1373-
unsigned metatypeDepth,
1367+
CanType existentialType,
13741368
bool isUnique,
13751369
bool isShared) {
13761370
LinkEntity entity;
@@ -1380,8 +1374,7 @@ class LinkEntity {
13801374
entity.Data =
13811375
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::ExtendedExistentialTypeShape))
13821376
| LINKENTITY_SET_FIELD(ExtendedExistentialIsUnique, unsigned(isUnique))
1383-
| LINKENTITY_SET_FIELD(ExtendedExistentialIsShared, unsigned(isShared))
1384-
| LINKENTITY_SET_FIELD(ExtendedExistentialMetatypeDepth, metatypeDepth);
1377+
| LINKENTITY_SET_FIELD(ExtendedExistentialIsShared, unsigned(isShared));
13851378
return entity;
13861379
}
13871380

@@ -1484,9 +1477,9 @@ class LinkEntity {
14841477
reinterpret_cast<const GenericSignatureImpl*>(SecondaryPointer));
14851478
}
14861479

1487-
CanExistentialType getExtendedExistentialTypeShapeType() const {
1480+
CanType getExtendedExistentialTypeShapeType() const {
14881481
assert(getKind() == Kind::ExtendedExistentialTypeShape);
1489-
return cast<ExistentialType>(CanType(reinterpret_cast<TypeBase*>(Pointer)));
1482+
return CanType(reinterpret_cast<TypeBase*>(Pointer));
14901483
}
14911484

14921485
bool isExtendedExistentialTypeShapeUnique() const {
@@ -1499,11 +1492,6 @@ class LinkEntity {
14991492
return LINKENTITY_GET_FIELD(Data, ExtendedExistentialIsShared);
15001493
}
15011494

1502-
unsigned getExtendedExistentialTypeShapeMetatypeDepth() const {
1503-
assert(getKind() == Kind::ExtendedExistentialTypeShape);
1504-
return LINKENTITY_GET_FIELD(Data, ExtendedExistentialMetatypeDepth);
1505-
}
1506-
15071495
bool isDynamicallyReplaceable() const {
15081496
assert(getKind() == Kind::SILFunction);
15091497
return LINKENTITY_GET_FIELD(Data, IsDynamicallyReplaceableImpl);

lib/Demangling/Demangler.cpp

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3231,8 +3231,6 @@ NodePointer Demangler::demangleSpecialType() {
32313231
return popFunctionType(Node::Kind::CFunctionPointer);
32323232
case 'g':
32333233
case 'G':
3234-
case 'h':
3235-
case 'H':
32363234
return demangleExtendedExistentialShape(specialChar);
32373235
case 'z':
32383236
switch (auto cchar = nextChar()) {
@@ -3382,47 +3380,19 @@ NodePointer Demangler::demangleSpecialType() {
33823380
}
33833381

33843382
NodePointer Demangler::demangleExtendedExistentialShape(char nodeKind) {
3385-
assert(nodeKind == 'g' || nodeKind == 'G' ||
3386-
nodeKind == 'h' || nodeKind == 'H');
3383+
assert(nodeKind == 'g' || nodeKind == 'G');
33873384

3388-
NodePointer type = nullptr;
3389-
if (nodeKind == 'h' || nodeKind == 'H')
3390-
type = popNode(Node::Kind::Type);
3385+
NodePointer type = popNode(Node::Kind::Type);
33913386

33923387
NodePointer genSig = nullptr;
3393-
if (nodeKind == 'G' || nodeKind == 'H')
3388+
if (nodeKind == 'G')
33943389
genSig = popNode(Node::Kind::DependentGenericSignature);
33953390

3396-
NodePointer reqSig = popNode(Node::Kind::DependentGenericSignature);
3397-
3398-
NodePointer valueStorage = [&]() -> NodePointer {
3399-
switch (nextChar()) {
3400-
case 'o':
3401-
return createNode(Node::Kind::ExtendedExistentialValueStorage,
3402-
"opaque");
3403-
case 'c':
3404-
return createNode(Node::Kind::ExtendedExistentialValueStorage,
3405-
"class");
3406-
case 'm':
3407-
return createNode(Node::Kind::ExtendedExistentialValueStorage,
3408-
"metatype");
3409-
default:
3410-
return nullptr;
3411-
}
3412-
}();
3413-
if (!valueStorage) return nullptr;
3414-
3415-
// Make a default type expression if one wasn't given.
3416-
if (!type) {
3417-
type = createType(getDependentGenericParamType(genSig ? 1 : 0, 0));
3418-
}
3419-
34203391
if (genSig) {
34213392
return createWithChildren(Node::Kind::ExtendedExistentialTypeShape,
3422-
reqSig, genSig, type, valueStorage);
3393+
genSig, type);
34233394
} else {
3424-
return createWithChildren(Node::Kind::ExtendedExistentialTypeShape,
3425-
reqSig, type, valueStorage);
3395+
return createWithChild(Node::Kind::ExtendedExistentialTypeShape, type);
34263396
}
34273397
}
34283398

lib/Demangling/NodePrinter.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,6 @@ class NodePrinter {
595595
case Node::Kind::BackDeploymentThunk:
596596
case Node::Kind::BackDeploymentFallback:
597597
case Node::Kind::ExtendedExistentialTypeShape:
598-
case Node::Kind::ExtendedExistentialValueStorage:
599598
case Node::Kind::Uniquable:
600599
return false;
601600
}
@@ -2975,9 +2974,8 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
29752974
auto savedDisplayWhereClauses = Options.DisplayWhereClauses;
29762975
Options.DisplayWhereClauses = true;
29772976

2978-
NodePointer reqSig = Node->getChild(0);
29792977
NodePointer genSig = nullptr, type = nullptr;
2980-
if (Node->getNumChildren() == 4) {
2978+
if (Node->getNumChildren() == 2) {
29812979
genSig = Node->getChild(1);
29822980
type = Node->getChild(2);
29832981
} else {
@@ -2989,17 +2987,12 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
29892987
print(genSig, depth + 1);
29902988
Printer << " ";
29912989
}
2992-
Printer << "any";
2993-
print(reqSig, depth + 1);
2994-
Printer << " ";
2990+
Printer << "any ";
29952991
print(type, depth + 1);
29962992

29972993
Options.DisplayWhereClauses = savedDisplayWhereClauses;
29982994
return nullptr;
29992995
}
3000-
case Node::Kind::ExtendedExistentialValueStorage:
3001-
Printer << Node->getText();
3002-
return nullptr;
30032996
}
30042997

30052998
printer_unreachable("bad node kind!");

lib/Demangling/OldRemangler.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,10 +2725,6 @@ ManglingError Remangler::mangleExtendedExistentialTypeShape(Node *node,
27252725
unsigned int depth) {
27262726
return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node);
27272727
}
2728-
ManglingError Remangler::mangleExtendedExistentialValueStorage(Node *node,
2729-
unsigned int depth) {
2730-
return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node);
2731-
}
27322728
ManglingError
27332729
Remangler::mangleCanonicalSpecializedGenericMetaclass(Node *node,
27342730
unsigned depth) {

lib/Demangling/Remangler.cpp

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3445,65 +3445,25 @@ ManglingError Remangler::mangleUniquable(Node *node, unsigned depth) {
34453445

34463446
ManglingError Remangler::mangleExtendedExistentialTypeShape(Node *node,
34473447
unsigned depth) {
3448-
NodePointer reqSig, genSig, type, storage;
3449-
reqSig = node->getChild(0);
3450-
if (node->getNumChildren() == 3) {
3448+
NodePointer genSig, type;
3449+
if (node->getNumChildren() == 1) {
34513450
genSig = nullptr;
3452-
type = node->getChild(1);
3453-
storage = node->getChild(2);
3451+
type = node->getChild(0);
34543452
} else {
3455-
genSig = node->getChild(1);
3456-
type = node->getChild(2);
3457-
storage = node->getChild(3);
3453+
genSig = node->getChild(0);
3454+
type = node->getChild(1);
34583455
}
34593456

3460-
RETURN_IF_ERROR(mangle(reqSig, depth + 1));
34613457
if (genSig) {
34623458
RETURN_IF_ERROR(mangle(genSig, depth + 1));
34633459
}
3460+
RETURN_IF_ERROR(mangle(type, depth + 1));
34643461

3465-
// Recognize the special case of a type expression that's just the
3466-
// unique requirement type parameter.
3467-
{
3468-
if (type->getKind() != Node::Kind::Type)
3469-
return MANGLING_ERROR(ManglingError::WrongNodeType, type);
3470-
auto typeNode = type->getChild(0);
3471-
3472-
if (typeNode->getKind() == Node::Kind::DependentGenericParamType) {
3473-
auto paramDepth = typeNode->getChild(0)->getIndex();
3474-
auto index = typeNode->getChild(1)->getIndex();
3475-
if (paramDepth == (genSig ? 1 : 0) && index == 0)
3476-
type = nullptr;
3477-
}
3478-
}
3479-
if (type)
3480-
RETURN_IF_ERROR(mangle(type, depth + 1));
3481-
3482-
if (genSig && type)
3483-
Buffer << "XH";
3484-
else if (type)
3485-
Buffer << "Xh";
3486-
else if (genSig)
3462+
if (genSig)
34873463
Buffer << "XG";
34883464
else
34893465
Buffer << "Xg";
34903466

3491-
RETURN_IF_ERROR(mangle(storage, depth + 1));
3492-
3493-
return ManglingError::Success;
3494-
}
3495-
3496-
ManglingError Remangler::mangleExtendedExistentialValueStorage(Node *node,
3497-
unsigned depth) {
3498-
if (node->getText() == "opaque")
3499-
Buffer << "o";
3500-
else if (node->getText() == "class")
3501-
Buffer << "c";
3502-
else if (node->getText() == "metatype")
3503-
Buffer << "m";
3504-
else
3505-
return MANGLING_ERROR(ManglingError::UnknownEncoding, node);
3506-
35073467
return ManglingError::Success;
35083468
}
35093469

0 commit comments

Comments
 (0)