Skip to content

Commit

Permalink
Merge pull request #77027 from tbkka/tbkka-remotemirror-classexistential
Browse files Browse the repository at this point in the history
Fix multi-payload enums with Class Existential payloads on 32-bit targets
  • Loading branch information
tbkka authored Oct 17, 2024
2 parents ce83bf7 + cfc7b2e commit 5bd2c4b
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 12 deletions.
24 changes: 18 additions & 6 deletions stdlib/public/RemoteInspection/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,14 +437,26 @@ BitMask RecordTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const
// Mask the rest of the fields as usual...
break;
}
case RecordKind::ClassExistential:
// Class existential is a data pointer that does 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
SWIFT_FALLTHROUGH;
}
case RecordKind::ExistentialMetatype: {
// Initial metadata pointer has spare bits
// All the pointers in an Existential Metatype expose spare bits...
auto pointerBytes = TC.targetPointerSize();
auto mpePointerSpareBits = TC.getBuilder().getMultiPayloadEnumPointerMask();
mask.andMask(mpePointerSpareBits, 0);
mask.keepOnlyLeastSignificantBytes(TC.targetPointerSize());
auto mpePointerSpareBitMask = BitMask(pointerBytes, mpePointerSpareBits);
for (int offset = 0; offset < (int)getSize(); offset += pointerBytes) {
mask.andMask(mpePointerSpareBitMask, offset);
}
return mask;
}
case RecordKind::ErrorExistential:
Expand Down
118 changes: 112 additions & 6 deletions validation-test/Reflection/reflect_Enum_values10.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: asan

// This is broken on ARM64_32, disable it temporarily until we can fix it. rdar://137351613
// UNSUPPORTED: CPU=arm64_32

import SwiftReflectionTest

protocol P : AnyObject {
Expand All @@ -24,7 +21,8 @@ class C : P {
init() { a = 0; b = 0; }
}

// MemoryLayout<B>.size == 8
// On 64-bit: MemoryLayout<B>.size == 8
// On 32-bit: MemoryLayout<B>.size == 4
enum B {
case a(C)
case b(C)
Expand All @@ -44,8 +42,8 @@ reflect(enumValue: B.b(C()))
// CHECKALL-NEXT: (enum reflect_Enum_values10.B)
// CHECKALL-NEXT: Value: .b(_)

// MemoryLayout<Q>.size == 16
// MemoryLayout<P>.size == 16
// On 64-bit: MemoryLayout<Q>.size == MemoryLayout<P>.size == 16
// On 32-bit: MemoryLayout<Q>.size == MemoryLayout<P>.size == 8
enum Q {
case a(P)
case b(P)
Expand All @@ -65,6 +63,114 @@ reflect(enumValue: Q.b(C()))
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q)
// CHECKALL-NEXT: Value: .b(_)

enum B1 {
case a(C)
case b
}

reflect(enumValue: B1.a(C()))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values10.B1)
// CHECKALL-NEXT: Value: .a(_)

reflect(enumValue: B1.b)

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values10.B1)
// CHECKALL-NEXT: Value: .b

enum Q1 {
case a(P)
case b
}

reflect(enumValue: Q1.a(C()))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q1)
// CHECKALL-NEXT: Value: .a(_)

reflect(enumValue: Q1.b)

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values10.Q1)
// CHECKALL-NEXT: Value: .b

enum B2 {
case a(C)
case b(C)
case c(C)
case d(C)
case e(C)
}

reflect(enumValue: B2.a(C()))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values10.B2)
// CHECKALL-NEXT: Value: .a(_)

reflect(enumValue: B2.e(C()))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values10.B2)
// CHECKALL-NEXT: Value: .e(_)

// On 64-bit: MemoryLayout<Q>.size == MemoryLayout<P>.size == 16
// On 32-bit: MemoryLayout<Q>.size == MemoryLayout<P>.size == 8
enum Q2 {
case a(P)
case b(P)
case c(P)
case d(P)
case e(P)
}

reflect(enumValue: Q2.a(C()))

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

reflect(enumValue: Q2.e(C()))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// 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 5bd2c4b

Please sign in to comment.