Skip to content

Commit 645e3bb

Browse files
tbkkapull[bot]
authored andcommitted
More arcana about MPEs carrying class existentials
The first word in a class existential is the class pointer itself. This pointer exposes spare bits differently depending on the platform, which becomes apparent when you try to reflect an Optional carrying such an MPE. Add new test cases and some logic to zero out the first word of spare bit information only on platforms with 8-byte pointers.
1 parent 6120e07 commit 645e3bb

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

stdlib/public/RemoteInspection/TypeLowering.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -437,14 +437,24 @@ BitMask RecordTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const
437437
// Mask the rest of the fields as usual...
438438
break;
439439
}
440-
case RecordKind::ClassExistential:
441-
// Class existential is a bunch of pointers that expose spare bits
442-
// ... so we can fall through ...
440+
case RecordKind::ClassExistential: {
441+
// First pointer in a Class Existential is the class pointer
442+
// itself, which can be tagged or have other mysteries on 64-bit, so
443+
// it exposes no spare bits from the first word there...
444+
auto pointerBytes = TC.targetPointerSize();
445+
if (pointerBytes == 8) {
446+
auto zeroPointerSizedMask = BitMask::zeroMask(pointerBytes);
447+
mask.andMask(zeroPointerSizedMask, 0);
448+
}
449+
// Otherwise, it's the same as an Existential Metatype
450+
DISPATCH_FALLTHROUGH;
451+
}
443452
case RecordKind::ExistentialMetatype: {
444-
// A bunch of pointers that expose spare bits
453+
// All the pointers in an Existential Metatype expose spare bits...
454+
auto pointerBytes = TC.targetPointerSize();
445455
auto mpePointerSpareBits = TC.getBuilder().getMultiPayloadEnumPointerMask();
446-
auto mpePointerSpareBitMask = BitMask(TC.targetPointerSize(), mpePointerSpareBits);
447-
for (int offset = 0; offset < (int)getSize(); offset += TC.targetPointerSize()) {
456+
auto mpePointerSpareBitMask = BitMask(pointerBytes, mpePointerSpareBits);
457+
for (int offset = 0; offset < (int)getSize(); offset += pointerBytes) {
448458
mask.andMask(mpePointerSpareBitMask, offset);
449459
}
450460
return mask;

validation-test/Reflection/reflect_Enum_values10.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,30 @@ reflect(enumValue: Q2.e(C()))
147147
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q2)
148148
// CHECKALL-NEXT: Value: .e(_)
149149

150+
reflect(enumValue: Optional<Q2>.some(.a(C())))
151+
152+
// CHECKALL: Reflecting an enum value.
153+
// CHECKALL-NEXT: Type reference:
154+
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
155+
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q2))
156+
// CHECKALL-NEXT: Value: .some(.a(_))
157+
158+
reflect(enumValue: Optional<Q2>.some(.e(C())))
159+
160+
// CHECKALL: Reflecting an enum value.
161+
// CHECKALL-NEXT: Type reference:
162+
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
163+
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q2))
164+
// CHECKALL-NEXT: Value: .some(.e(_))
165+
166+
reflect(enumValue: Optional<Q2>.none)
167+
168+
// CHECKALL: Reflecting an enum value.
169+
// CHECKALL-NEXT: Type reference:
170+
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
171+
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q2))
172+
// CHECKALL-NEXT: Value: .none
173+
150174
doneReflecting()
151175

152176
// CHECKALL: Done.

0 commit comments

Comments
 (0)