Skip to content

Commit a897fcb

Browse files
committed
Correctly project enums with zero-sized payloads
I earlier overhauled the enum layout logic to correctly consider enums with generic cases and cases that have zero size. This updates the enum projection logic to use that information as well. In particular, this fixes a bug where an MPE with zero-sized cases would be incorrectly projected by RemoteMirror (with consequences for the `leaks` tool and lldb). Resolves rdar://111705059
1 parent f53be47 commit a897fcb

File tree

3 files changed

+186
-16
lines changed

3 files changed

+186
-16
lines changed

stdlib/public/RemoteInspection/TypeLowering.cpp

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -653,13 +653,16 @@ class SinglePayloadEnumTypeInfo: public EnumTypeInfo {
653653
// }
654654
// ```
655655
class TaggedMultiPayloadEnumTypeInfo: public EnumTypeInfo {
656+
unsigned NumEffectivePayloadCases;
656657
public:
657658
TaggedMultiPayloadEnumTypeInfo(unsigned Size, unsigned Alignment,
658659
unsigned Stride, unsigned NumExtraInhabitants,
659660
bool BitwiseTakable,
660-
const std::vector<FieldInfo> &Cases)
661+
const std::vector<FieldInfo> &Cases,
662+
unsigned NumEffectivePayloadCases)
661663
: EnumTypeInfo(Size, Alignment, Stride, NumExtraInhabitants,
662-
BitwiseTakable, EnumKind::MultiPayloadEnum, Cases) {
664+
BitwiseTakable, EnumKind::MultiPayloadEnum, Cases),
665+
NumEffectivePayloadCases(NumEffectivePayloadCases) {
663666
// Definition of "multi-payload enum"
664667
assert(getCases().size() > 1); // At least 2 cases
665668
assert(Cases[0].TR != 0); // At least 2 payloads
@@ -698,7 +701,7 @@ class TaggedMultiPayloadEnumTypeInfo: public EnumTypeInfo {
698701
remote::RemoteAddress address,
699702
int *CaseIndex) const override {
700703
unsigned long PayloadSize = getPayloadSize();
701-
unsigned PayloadCount = getNumPayloadCases();
704+
unsigned PayloadCount = NumEffectivePayloadCases;
702705
unsigned NumCases = getNumCases();
703706
unsigned TagSize = getSize() - PayloadSize;
704707
unsigned tag = 0;
@@ -1030,15 +1033,24 @@ class BitMask {
10301033
// bits in the payload.
10311034
class MultiPayloadEnumTypeInfo: public EnumTypeInfo {
10321035
BitMask spareBitsMask;
1036+
// "Effective" payload cases includes those with
1037+
// generic payload and non-generic cases that are
1038+
// statically known to have non-zero size.
1039+
// It does not include cases with payloads that are
1040+
// non-generic and zero-sized (these are treated as
1041+
// non-payload cases for many purposes).
1042+
unsigned NumEffectivePayloadCases;
10331043
public:
10341044
MultiPayloadEnumTypeInfo(unsigned Size, unsigned Alignment,
10351045
unsigned Stride, unsigned NumExtraInhabitants,
10361046
bool BitwiseTakable,
10371047
const std::vector<FieldInfo> &Cases,
1038-
BitMask spareBitsMask)
1048+
BitMask spareBitsMask,
1049+
unsigned NumEffectivePayloadCases)
10391050
: EnumTypeInfo(Size, Alignment, Stride, NumExtraInhabitants,
10401051
BitwiseTakable, EnumKind::MultiPayloadEnum, Cases),
1041-
spareBitsMask(spareBitsMask) {
1052+
spareBitsMask(spareBitsMask),
1053+
NumEffectivePayloadCases(NumEffectivePayloadCases) {
10421054
assert(Cases[0].TR != 0);
10431055
assert(Cases[1].TR != 0);
10441056
assert(getNumNonEmptyPayloadCases() > 1);
@@ -1125,7 +1137,6 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo {
11251137
remote::RemoteAddress address,
11261138
int *CaseIndex) const override {
11271139
unsigned long payloadSize = getPayloadSize();
1128-
unsigned NumPayloadCases = getNumPayloadCases();
11291140

11301141
// Extra Tag (if any) holds upper bits of case value
11311142
auto extraTagSize = getSize() - payloadSize;
@@ -1156,7 +1167,7 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo {
11561167
}
11571168

11581169
// If the above identifies a payload case, we're done
1159-
if (static_cast<unsigned>(tagValue) < NumPayloadCases) {
1170+
if (static_cast<unsigned>(tagValue) < NumEffectivePayloadCases) {
11601171
*CaseIndex = tagValue;
11611172
return true;
11621173
}
@@ -1173,9 +1184,9 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo {
11731184

11741185
int ComputedCase = 0;
11751186
if (occupiedBitCount >= 32) {
1176-
ComputedCase = payloadValue + NumPayloadCases;
1187+
ComputedCase = payloadValue + NumEffectivePayloadCases;
11771188
} else {
1178-
ComputedCase = (((tagValue - NumPayloadCases) << occupiedBitCount) | payloadValue) + NumPayloadCases;
1189+
ComputedCase = (((tagValue - NumEffectivePayloadCases) << occupiedBitCount) | payloadValue) + NumEffectivePayloadCases;
11791190
}
11801191

11811192
if (static_cast<unsigned>(ComputedCase) < getNumCases()) {
@@ -1193,8 +1204,8 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo {
11931204
// * The remainder of the payload bits (for non-payload cases)
11941205
// This computes the bits used for the payload tag.
11951206
BitMask getMultiPayloadTagBitsMask() const {
1196-
auto payloadTagValues = getNumPayloadCases() - 1;
1197-
if (getNumCases() > getNumPayloadCases()) {
1207+
auto payloadTagValues = NumEffectivePayloadCases - 1;
1208+
if (getNumCases() > NumEffectivePayloadCases) {
11981209
payloadTagValues += 1;
11991210
}
12001211
int payloadTagBits = 0;
@@ -2257,7 +2268,7 @@ class EnumTypeInfoBuilder {
22572268
Stride = 1;
22582269
return TC.makeTypeInfo<TaggedMultiPayloadEnumTypeInfo>(
22592270
Size, Alignment, Stride, NumExtraInhabitants,
2260-
BitwiseTakable, Cases);
2271+
BitwiseTakable, Cases, EffectivePayloadCases);
22612272
}
22622273

22632274
// This is a multi-payload enum that:
@@ -2291,7 +2302,7 @@ class EnumTypeInfoBuilder {
22912302
// If there are no spare bits, use the "simple" tag-only implementation.
22922303
return TC.makeTypeInfo<TaggedMultiPayloadEnumTypeInfo>(
22932304
Size, Alignment, Stride, NumExtraInhabitants,
2294-
BitwiseTakable, Cases);
2305+
BitwiseTakable, Cases, EffectivePayloadCases);
22952306
}
22962307

22972308
#if 0 // TODO: This should be !defined(NDEBUG)
@@ -2314,7 +2325,8 @@ class EnumTypeInfoBuilder {
23142325
// Use compiler-provided spare bit information
23152326
return TC.makeTypeInfo<MultiPayloadEnumTypeInfo>(
23162327
Size, Alignment, Stride, NumExtraInhabitants,
2317-
BitwiseTakable, Cases, spareBitsMask);
2328+
BitwiseTakable, Cases, spareBitsMask,
2329+
EffectivePayloadCases);
23182330
}
23192331

23202332
// Either there was no compiler data or it didn't make sense
@@ -2339,13 +2351,14 @@ class EnumTypeInfoBuilder {
23392351
// above only returns an empty mask when the mask is really empty,
23402352
return TC.makeTypeInfo<TaggedMultiPayloadEnumTypeInfo>(
23412353
Size, Alignment, Stride, NumExtraInhabitants,
2342-
BitwiseTakable, Cases);
2354+
BitwiseTakable, Cases, EffectivePayloadCases);
23432355
} else {
23442356
// General case can mix spare bits and extra discriminator
23452357
// It obviously relies on having an accurate spare bit mask.
23462358
return TC.makeTypeInfo<MultiPayloadEnumTypeInfo>(
23472359
Size, Alignment, Stride, NumExtraInhabitants,
2348-
BitwiseTakable, Cases, spareBitsMask);
2360+
BitwiseTakable, Cases, spareBitsMask,
2361+
EffectivePayloadCases);
23492362
}
23502363
}
23512364
};
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values2
3+
// RUN: %target-codesign %t/reflect_Enum_values2
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values2 | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK%target-ptrsize --check-prefix=CHECKALL --dump-input=fail %add_num_extra_inhabitants
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// UNSUPPORTED: use_os_stdlib
10+
11+
import SwiftReflectionTest
12+
13+
enum EnumB {
14+
case a
15+
case b(Int8)
16+
case c(Int8)
17+
case d(Void)
18+
case e(Void)
19+
case RIGHT(Int8)
20+
case f(Int8)
21+
case g(Void)
22+
case LEFT(Int8, Int64)
23+
}
24+
25+
class PlaceSummaryUnit {
26+
let t: EnumB
27+
init(t: EnumB) { self.t = t }
28+
}
29+
30+
reflect(object: PlaceSummaryUnit(t: .RIGHT(5)))
31+
32+
// CHECKALL: Reflecting an object.
33+
// CHECKALL-NEXT: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
34+
// CHECKALL-NEXT: Type reference:
35+
// CHECKALL-NEXT: (class reflect_Enum_values2.PlaceSummaryUnit)
36+
37+
// CHECKALL: Type info
38+
39+
// TODO: Check the type layout for 64- and 32-bit targets
40+
41+
reflect(enumValue: PlaceSummaryUnit(t: .RIGHT(5)).t)
42+
43+
// CHECKALL: Reflecting an enum value.
44+
// CHECKALL-NEXT: Type reference:
45+
// CHECKALL-NEXT: (enum reflect_Enum_values2.EnumB)
46+
// CHECKALL-NEXT: Value: .RIGHT(_)
47+
48+
reflect(enumValue: PlaceSummaryUnit(t: .a).t)
49+
50+
// CHECKALL: Reflecting an enum value.
51+
// CHECKALL-NEXT: Type reference:
52+
// CHECKALL-NEXT: (enum reflect_Enum_values2.EnumB)
53+
// CHECKALL-NEXT: Value: .a
54+
55+
reflect(enumValue: PlaceSummaryUnit(t: .LEFT(1,2)).t)
56+
57+
// CHECKALL: Reflecting an enum value.
58+
// CHECKALL-NEXT: Type reference:
59+
// CHECKALL-NEXT: (enum reflect_Enum_values2.EnumB)
60+
// CHECKALL-NEXT: Value: .LEFT(_)
61+
62+
reflect(enumValue: PlaceSummaryUnit(t: .d(())).t)
63+
64+
// CHECKALL: Reflecting an enum value.
65+
// CHECKALL-NEXT: Type reference:
66+
// CHECKALL-NEXT: (enum reflect_Enum_values2.EnumB)
67+
// CHECKALL-NEXT: Value: .d(_)
68+
69+
doneReflecting()
70+
71+
// CHECKALL: Done.
72+
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values3
3+
// RUN: %target-codesign %t/reflect_Enum_values3
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values3 | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK%target-ptrsize --check-prefix=CHECKALL --dump-input=fail %add_num_extra_inhabitants
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// UNSUPPORTED: use_os_stdlib
10+
11+
import SwiftReflectionTest
12+
13+
enum EnumB<T> {
14+
case a
15+
case b(Int8)
16+
case c(T)
17+
case d(Void)
18+
case e(Void)
19+
case RIGHT(Int8)
20+
case f(Int8)
21+
case g(Void)
22+
case LEFT(Int8, Int64)
23+
}
24+
25+
class PlaceSummaryUnit<T> {
26+
let t: EnumB<T>
27+
init(t: EnumB<T>) { self.t = t }
28+
}
29+
30+
reflect(object: PlaceSummaryUnit<Int8>(t: .RIGHT(5)))
31+
32+
// CHECKALL: Reflecting an object.
33+
// CHECKALL-NEXT: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
34+
// CHECKALL-NEXT: Type reference:
35+
// CHECKALL-NEXT: (bound_generic_class reflect_Enum_values3.PlaceSummaryUnit
36+
// CHECKALL-NEXT: (struct Swift.Int8))
37+
38+
// CHECKALL: Type info
39+
40+
// TODO: Check the type layout for 64- and 32-bit targets
41+
42+
reflect(enumValue: PlaceSummaryUnit<Int8>(t: .RIGHT(5)).t)
43+
44+
// CHECKALL: Reflecting an enum value.
45+
// CHECKALL-NEXT: Type reference:
46+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values3.EnumB
47+
// CHECKALL-NEXT: (struct Swift.Int8))
48+
// CHECKALL-NEXT: Value: .RIGHT(_)
49+
50+
reflect(enumValue: PlaceSummaryUnit<Int8>(t: .a).t)
51+
52+
// CHECKALL: Reflecting an enum value.
53+
// CHECKALL-NEXT: Type reference:
54+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values3.EnumB
55+
// CHECKALL-NEXT: (struct Swift.Int8))
56+
// CHECKALL-NEXT: Value: .a
57+
58+
reflect(enumValue: PlaceSummaryUnit<Int8>(t: .c(7)).t)
59+
60+
// CHECKALL: Reflecting an enum value.
61+
// CHECKALL-NEXT: Type reference:
62+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values3.EnumB
63+
// CHECKALL-NEXT: (struct Swift.Int8))
64+
// CHECKALL-NEXT: Value: .c(_)
65+
66+
reflect(enumValue: PlaceSummaryUnit<Int8>(t: .LEFT(1,2)).t)
67+
68+
// CHECKALL: Reflecting an enum value.
69+
// CHECKALL-NEXT: Type reference:
70+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values3.EnumB
71+
// CHECKALL-NEXT: (struct Swift.Int8))
72+
// CHECKALL-NEXT: Value: .LEFT(_)
73+
74+
reflect(enumValue: PlaceSummaryUnit<Int8>(t: .d(())).t)
75+
76+
// CHECKALL: Reflecting an enum value.
77+
// CHECKALL-NEXT: Type reference:
78+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values3.EnumB
79+
// CHECKALL-NEXT: (struct Swift.Int8))
80+
// CHECKALL-NEXT: Value: .d(_)
81+
82+
doneReflecting()
83+
84+
// CHECKALL: Done.
85+

0 commit comments

Comments
 (0)