Skip to content

Commit 40eb3c0

Browse files
committed
Expand the work from swiftlang#73491 to support more MPE layouts. This also switches the
MPE layout code to exclusively use the new code. The key observation: existing reflection metadata seems to already provide enough information in all cases, so we can abandon an earlier effort to add spare bitmask data. Resolves rdar://129281368
1 parent 51318b7 commit 40eb3c0

File tree

4 files changed

+120
-43
lines changed

4 files changed

+120
-43
lines changed

include/swift/RemoteInspection/BitMask.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,16 @@ class BitMask {
7474

7575
BitMask(unsigned sizeInBytes, uint64_t sourceMask): size(sizeInBytes) {
7676
mask = (uint8_t *)calloc(1, sizeInBytes);
77-
memcpy(mask, &sourceMask, sizeInBytes);
77+
if (!mask) {
78+
assert(false && "Failed to allocate Bitmask");
79+
size = 0;
80+
return;
81+
}
82+
size_t toCopy = sizeInBytes;
83+
if (toCopy > sizeof(sourceMask)) {
84+
toCopy = sizeof(sourceMask);
85+
}
86+
memcpy(mask, &sourceMask, toCopy);
7887
}
7988

8089
// Construct a bitmask of the appropriate number of bytes

stdlib/public/RemoteInspection/TypeLowering.cpp

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ BitMask BuiltinTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) cons
315315
mask.keepOnlyMostSignificantBits(getSize() * 8 - intSize);
316316
return mask;
317317
} else if (
318+
Name == "ypXp" || // Any.Type
318319
Name == "yyXf" // 'yyXf' = @thin () -> Void function
319320
) {
320321
// Builtin types that expose pointer spare bits
@@ -578,7 +579,9 @@ class NoPayloadEnumTypeInfo: public EnumTypeInfo {
578579
}
579580

580581
BitMask getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const override {
581-
return BitMask::zeroMask(getSize());
582+
auto mask = BitMask(getSize(), maskForCount(getNumCases()));
583+
mask.complement();
584+
return mask;
582585
}
583586

584587
bool projectEnumValue(remote::MemoryReader &reader,
@@ -648,7 +651,17 @@ class SinglePayloadEnumTypeInfo: public EnumTypeInfo {
648651
}
649652

650653
BitMask getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const override {
651-
return BitMask::zeroMask(getSize());
654+
FieldInfo PayloadCase = getCases()[0];
655+
size_t payloadSize = PayloadCase.TI.getSize();
656+
if (getSize() <= payloadSize) {
657+
return BitMask::zeroMask(getSize());
658+
}
659+
size_t tagSize = getSize() - payloadSize;
660+
auto mask = BitMask::oneMask(getSize());
661+
mask.keepOnlyMostSignificantBits(tagSize * 8); // Clear payload bits
662+
auto tagMaskUsedBits = BitMask(getSize(), maskForCount(getNumCases()));
663+
mask.andNotMask(tagMaskUsedBits, payloadSize); // Clear used tag bits
664+
return mask;
652665
}
653666

654667
// Think of a single-payload enum as being encoded in "pages".
@@ -2046,11 +2059,10 @@ class EnumTypeInfoBuilder {
20462059
//
20472060

20482061
// Do we have a fixed layout?
2049-
// TODO: Test whether a missing FixedDescriptor is actually relevant.
20502062
auto FixedDescriptor = TC.getBuilder().getBuiltinTypeDescriptor(TR);
20512063
if (!FixedDescriptor || GenericPayloadCases > 0) {
20522064
// This is a "dynamic multi-payload enum". For example,
2053-
// this occurs with:
2065+
// this occurs with generics such as:
20542066
// ```
20552067
// class ClassWithEnum<T> {
20562068
// enum E {
@@ -2060,6 +2072,12 @@ class EnumTypeInfoBuilder {
20602072
// var e: E?
20612073
// }
20622074
// ```
2075+
// and when we have a resilient inner enum, such as:
2076+
// ```
2077+
// enum E2 {
2078+
// case y(E1_resilient)
2079+
// case z(Int)
2080+
// }
20632081
auto tagCounts = getEnumTagCounts(Size, EffectiveNoPayloadCases,
20642082
EffectivePayloadCases);
20652083
Size += tagCounts.numTagBytes;
@@ -2091,7 +2109,6 @@ class EnumTypeInfoBuilder {
20912109
unsigned Stride = ((Size + Alignment - 1) & ~(Alignment - 1));
20922110
if (Stride == 0)
20932111
Stride = 1;
2094-
auto PayloadSize = EnumTypeInfo::getPayloadSizeForCases(Cases);
20952112

20962113
// Compute the spare bit mask and determine if we have any address-only fields
20972114
auto localSpareBitMask = BitMask::oneMask(Size);
@@ -2103,44 +2120,11 @@ class EnumTypeInfoBuilder {
21032120
}
21042121
}
21052122

2106-
// See if we have MPE bit mask information from the compiler...
2107-
// TODO: drop this?
2108-
2109-
// Uncomment the following line to dump the MPE section every time we come through here...
2110-
//TC.getBuilder().dumpMultiPayloadEnumSection(std::cerr); // DEBUG helper
2111-
2112-
auto MPEDescriptor = TC.getBuilder().getMultiPayloadEnumDescriptor(TR);
2113-
if (MPEDescriptor && MPEDescriptor->usesPayloadSpareBits()) {
2114-
// We found compiler-provided spare bit data...
2115-
auto PayloadSpareBitMaskByteCount = MPEDescriptor->getPayloadSpareBitMaskByteCount();
2116-
auto PayloadSpareBitMaskByteOffset = MPEDescriptor->getPayloadSpareBitMaskByteOffset();
2117-
auto SpareBitMask = MPEDescriptor->getPayloadSpareBits();
2118-
BitMask compilerSpareBitMask(PayloadSize, SpareBitMask,
2119-
PayloadSpareBitMaskByteCount, PayloadSpareBitMaskByteOffset);
2120-
2121-
if (compilerSpareBitMask.isZero() || hasAddrOnly) {
2122-
// If there are no spare bits, use the "simple" tag-only implementation.
2123-
return TC.makeTypeInfo<TaggedMultiPayloadEnumTypeInfo>(
2124-
Size, Alignment, Stride, NumExtraInhabitants,
2125-
BitwiseTakable, Cases, EffectivePayloadCases);
2126-
}
2127-
2128-
#if 0 // TODO: This should be !defined(NDEBUG)
2129-
// Verify that compiler provided and local spare bit info agree...
2130-
// TODO: If we could make this actually work, then we wouldn't need the
2131-
// bulky compiler-provided info, would we?
2132-
assert(localSpareBitMask == compilerSpareBitMask);
2133-
#endif
2134-
2135-
// Use compiler-provided spare bit information
2136-
return TC.makeTypeInfo<MultiPayloadEnumTypeInfo>(
2137-
Size, Alignment, Stride, NumExtraInhabitants,
2138-
BitwiseTakable, Cases, compilerSpareBitMask,
2139-
EffectivePayloadCases);
2140-
}
2141-
21422123
if (localSpareBitMask.isZero() || hasAddrOnly) {
2143-
// Simple case that does not use spare bits
2124+
// Simple tag-only layout does not use spare bits.
2125+
// Either:
2126+
// * There are no spare bits, or
2127+
// * We can't copy it to strip spare bits.
21442128
return TC.makeTypeInfo<TaggedMultiPayloadEnumTypeInfo>(
21452129
Size, Alignment, Stride, NumExtraInhabitants,
21462130
BitwiseTakable, Cases, EffectivePayloadCases);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
public enum E1_resilient {
3+
case a
4+
case b
5+
}
6+
7+
public enum E2_resilient {
8+
case c(E1_resilient)
9+
case d(E1_resilient)
10+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-build-swift-dylib(%t/%target-library-name(resilient_enums)) -enable-library-evolution %S/Inputs/reflect_Enum_values_resilient_enums.swift -emit-module -emit-module-path %t/resilient_enums.swiftmodule -module-name resilient_enums
4+
// RUN: %target-codesign %t/%target-library-name(resilient_enums)
5+
6+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -L %t -I %t -lresilient_enums -o %t/reflect_Enum_values_resilient %target-rpath(%t)
7+
// RUN: %target-codesign %t/reflect_Enum_values_resilient
8+
9+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values_resilient | tee /dev/stderr | %FileCheck %s --dump-input=fail
10+
11+
// REQUIRES: executable_test
12+
// UNSUPPORTED: use_os_stdlib
13+
14+
import SwiftReflectionTest
15+
16+
import resilient_enums
17+
18+
// Non-resilient enum wrapping a resilient enum
19+
// This doesn't use spare bits of the inner enum
20+
enum E2 {
21+
case y(E1_resilient)
22+
case z(E1_resilient)
23+
}
24+
25+
// Contrast:
26+
// E2_resilient is a resilient enum wrapping a resilient enum
27+
// This does use spare bits of the inner enum
28+
29+
30+
// CHECK: Reflecting an enum value.
31+
// CHECK-NEXT: Type reference:
32+
// CHECK-NEXT: (enum reflect_Enum_values_resilient.E2)
33+
// CHECK-NEXT: Value: .y(.a)
34+
35+
reflect(enumValue: E2.y(.a))
36+
37+
// CHECK: Reflecting an enum value.
38+
// CHECK-NEXT: Type reference:
39+
// CHECK-NEXT: (enum reflect_Enum_values_resilient.E2)
40+
// CHECK-NEXT: Value: .z(.b)
41+
42+
reflect(enumValue: E2.z(.b))
43+
44+
// CHECK: Reflecting an enum value.
45+
// CHECK-NEXT: Type reference:
46+
// CHECK-NEXT: (enum resilient_enums.E1_resilient)
47+
// CHECK-NEXT: Value: .a
48+
49+
reflect(enumValue: E1_resilient.a)
50+
51+
// CHECK: Reflecting an enum value.
52+
// CHECK-NEXT: Type reference:
53+
// CHECK-NEXT: (enum resilient_enums.E1_resilient)
54+
// CHECK-NEXT: Value: .b
55+
56+
reflect(enumValue: E1_resilient.b)
57+
58+
// CHECK: Reflecting an enum value.
59+
// CHECK-NEXT: Type reference:
60+
// CHECK-NEXT: (enum resilient_enums.E2_resilient)
61+
// CHECK-NEXT: Value: .c(.a)
62+
63+
reflect(enumValue: E2_resilient.c(.a))
64+
65+
// CHECK: Reflecting an enum value.
66+
// CHECK-NEXT: Type reference:
67+
// CHECK-NEXT: (enum resilient_enums.E2_resilient)
68+
// CHECK-NEXT: Value: .d(.b)
69+
70+
reflect(enumValue: E2_resilient.d(.b))
71+
72+
doneReflecting()
73+
74+
// CHECK: Done.

0 commit comments

Comments
 (0)