Skip to content

Commit

Permalink
More arcana about MPEs carrying class existentials
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tbkka committed Oct 16, 2024
1 parent a105cf5 commit 502941c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
22 changes: 16 additions & 6 deletions stdlib/public/RemoteInspection/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,14 +437,24 @@ BitMask RecordTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const
// Mask the rest of the fields as usual...
break;
}
case RecordKind::ClassExistential:
// Class existential is a bunch of pointers that expose spare bits
// ... so we can fall through ...
case RecordKind::ClassExistential: {
// First pointer in a Class Existential is the class pointer
// itself, which can be tagged or have other mysteries on 64-bit, so
// it exposes no spare bits from the first word there...
auto pointerBytes = TC.targetPointerSize();
if (pointerBytes == 8) {
auto zeroPointerSizedMask = BitMask::zeroMask(pointerBytes);
mask.andMask(zeroPointerSizedMask, 0);
}
// Otherwise, it's the same as an Existential Metatype
DISPATCH_FALLTHROUGH;
}
case RecordKind::ExistentialMetatype: {
// A bunch of pointers that expose spare bits
// All the pointers in an Existential Metatype expose spare bits...
auto pointerBytes = TC.targetPointerSize();
auto mpePointerSpareBits = TC.getBuilder().getMultiPayloadEnumPointerMask();
auto mpePointerSpareBitMask = BitMask(TC.targetPointerSize(), mpePointerSpareBits);
for (int offset = 0; offset < (int)getSize(); offset += TC.targetPointerSize()) {
auto mpePointerSpareBitMask = BitMask(pointerBytes, mpePointerSpareBits);
for (int offset = 0; offset < (int)getSize(); offset += pointerBytes) {
mask.andMask(mpePointerSpareBitMask, offset);
}
return mask;
Expand Down
24 changes: 24 additions & 0 deletions validation-test/Reflection/reflect_Enum_values10.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,30 @@ reflect(enumValue: Q2.e(C()))
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q2)
// CHECKALL-NEXT: Value: .e(_)

reflect(enumValue: Optional<Q2>.some(.a(C())))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q2))
// CHECKALL-NEXT: Value: .some(.a(_))

reflect(enumValue: Optional<Q2>.some(.e(C())))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q2))
// CHECKALL-NEXT: Value: .some(.e(_))

reflect(enumValue: Optional<Q2>.none)

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q2))
// CHECKALL-NEXT: Value: .none

doneReflecting()

// CHECKALL: Done.
Expand Down

0 comments on commit 502941c

Please sign in to comment.