@@ -418,13 +418,13 @@ class EmptyEnumTypeInfo: public EnumTypeInfo {
418
418
// Enum with a single non-payload case
419
419
class TrivialEnumTypeInfo : public EnumTypeInfo {
420
420
public:
421
- TrivialEnumTypeInfo (const std::vector<FieldInfo> &Cases)
421
+ TrivialEnumTypeInfo (EnumKind Kind, const std::vector<FieldInfo> &Cases)
422
422
: EnumTypeInfo(/* Size*/ 0 ,
423
423
/* Alignment*/ 1 ,
424
424
/* Stride*/ 1 ,
425
425
/* NumExtraInhabitants*/ 0 ,
426
426
/* BitwiseTakable*/ true ,
427
- EnumKind::NoPayloadEnum , Cases) {}
427
+ Kind , Cases) {}
428
428
429
429
bool readExtraInhabitantIndex (remote::MemoryReader &reader,
430
430
remote::RemoteAddress address,
@@ -446,12 +446,13 @@ class NoPayloadEnumTypeInfo: public EnumTypeInfo {
446
446
public:
447
447
NoPayloadEnumTypeInfo (unsigned Size, unsigned Alignment,
448
448
unsigned Stride, unsigned NumExtraInhabitants,
449
+ EnumKind Kind,
449
450
const std::vector<FieldInfo> &Cases)
450
451
: EnumTypeInfo(Size, Alignment, Stride, NumExtraInhabitants,
451
452
/* BitwiseTakable*/ true ,
452
- EnumKind::NoPayloadEnum , Cases) {
453
+ Kind , Cases) {
453
454
assert (Cases.size () >= 2 );
454
- assert (getNumPayloadCases () == 0 );
455
+ assert (getNumNonEmptyPayloadCases () == 0 );
455
456
}
456
457
457
458
bool readExtraInhabitantIndex (remote::MemoryReader &reader,
@@ -491,11 +492,12 @@ class SinglePayloadEnumTypeInfo: public EnumTypeInfo {
491
492
SinglePayloadEnumTypeInfo (unsigned Size, unsigned Alignment,
492
493
unsigned Stride, unsigned NumExtraInhabitants,
493
494
bool BitwiseTakable,
495
+ EnumKind Kind,
494
496
const std::vector<FieldInfo> &Cases)
495
497
: EnumTypeInfo(Size, Alignment, Stride, NumExtraInhabitants,
496
- BitwiseTakable, EnumKind::SinglePayloadEnum , Cases) {
498
+ BitwiseTakable, Kind , Cases) {
497
499
assert (Cases[0 ].TR != 0 );
498
- assert (getNumPayloadCases () == 1 );
500
+ assert (getNumNonEmptyPayloadCases () == 1 );
499
501
}
500
502
501
503
bool readExtraInhabitantIndex (remote::MemoryReader &reader,
@@ -611,7 +613,7 @@ class SimpleMultiPayloadEnumTypeInfo: public EnumTypeInfo {
611
613
BitwiseTakable, EnumKind::MultiPayloadEnum, Cases) {
612
614
assert (Cases[0 ].TR != 0 );
613
615
assert (Cases[1 ].TR != 0 );
614
- assert (getNumPayloadCases () > 1 );
616
+ assert (getNumNonEmptyPayloadCases () > 1 );
615
617
assert (getSize () > getPayloadSize ());
616
618
assert (getCases ().size () > 1 );
617
619
}
@@ -986,7 +988,7 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo {
986
988
spareBitsMask (spareBitsMask) {
987
989
assert (Cases[0 ].TR != 0 );
988
990
assert (Cases[1 ].TR != 0 );
989
- assert (getNumPayloadCases () > 1 );
991
+ assert (getNumNonEmptyPayloadCases () > 1 );
990
992
}
991
993
992
994
bool readExtraInhabitantIndex (remote::MemoryReader &reader,
@@ -1043,7 +1045,7 @@ class MultiPayloadEnumTypeInfo: public EnumTypeInfo {
1043
1045
1044
1046
// Check whether this tag is used for valid content
1045
1047
auto payloadCases = getNumPayloadCases ();
1046
- auto nonPayloadCases = getNumCases () - getNumPayloadCases () ;
1048
+ auto nonPayloadCases = getNumCases () - payloadCases ;
1047
1049
uint32_t inhabitedTags;
1048
1050
if (nonPayloadCases == 0 ) {
1049
1051
inhabitedTags = payloadCases;
@@ -2031,7 +2033,8 @@ class EnumTypeInfoBuilder {
2031
2033
const TypeInfo *build (const TypeRef *TR, RemoteRef<FieldDescriptor> FD,
2032
2034
remote::TypeInfoProvider *ExternalTypeInfo) {
2033
2035
// Sort enum into payload and no-payload cases.
2034
- unsigned NoPayloadCases = 0 ;
2036
+ unsigned TrueNoPayloadCases = 0 ;
2037
+ unsigned EmptyPayloadCases = 0 ;
2035
2038
std::vector<FieldTypeInfo> PayloadCases;
2036
2039
2037
2040
std::vector<FieldTypeInfo> Fields;
@@ -2042,41 +2045,71 @@ class EnumTypeInfoBuilder {
2042
2045
2043
2046
for (auto Case : Fields) {
2044
2047
if (Case.TR == nullptr ) {
2045
- ++NoPayloadCases ;
2048
+ ++TrueNoPayloadCases ;
2046
2049
addCase (Case.Name );
2047
2050
} else {
2048
- PayloadCases.push_back (Case);
2049
2051
auto *CaseTR = getCaseTypeRef (Case);
2050
2052
assert (CaseTR != nullptr );
2051
2053
auto *CaseTI = TC.getTypeInfo (CaseTR, ExternalTypeInfo);
2054
+ if (CaseTI->getSize () == 0 ) {
2055
+ // Zero-sized payloads get special treatment
2056
+ ++EmptyPayloadCases;
2057
+ } else {
2058
+ PayloadCases.push_back (Case);
2059
+ }
2052
2060
addCase (Case.Name , CaseTR, CaseTI);
2053
2061
}
2054
2062
}
2063
+ // For layout purposes, cases w/ empty payload are
2064
+ // treated the same as cases with no payload.
2065
+ unsigned EffectiveNoPayloadCases = TrueNoPayloadCases + EmptyPayloadCases;
2055
2066
2056
2067
if (Cases.empty ()) {
2057
2068
return TC.makeTypeInfo <EmptyEnumTypeInfo>(Cases);
2058
2069
}
2059
2070
2071
+ // `Kind` is used when dumping data, so it reflects how the enum was
2072
+ // declared in source; the various *TypeInfo classes mentioned below reflect
2073
+ // the in-memory layout, which may be different because cases whose
2074
+ // payload is zero-sized get treated (for layout purposes) as non-payload
2075
+ // cases.
2076
+ EnumKind Kind;
2077
+ switch (PayloadCases.size () + EmptyPayloadCases) {
2078
+ case 0 : Kind = EnumKind::NoPayloadEnum; break ;
2079
+ case 1 : Kind = EnumKind::SinglePayloadEnum; break ;
2080
+ default : Kind = EnumKind::MultiPayloadEnum; break ;
2081
+ }
2082
+
2060
2083
if (PayloadCases.empty ()) {
2061
2084
// NoPayloadEnumImplStrategy
2062
- if (NoPayloadCases == 1 ) {
2063
- return TC.makeTypeInfo <TrivialEnumTypeInfo>(Cases);
2064
- } else if (NoPayloadCases < 256 ) {
2065
- return TC.makeTypeInfo <NoPayloadEnumTypeInfo>(
2066
- /* Size */ 1 , /* Alignment */ 1 , /* Stride */ 1 ,
2067
- /* NumExtraInhabitants */ 256 - NoPayloadCases, Cases);
2068
- } else if (NoPayloadCases < 65536 ) {
2069
- return TC.makeTypeInfo <NoPayloadEnumTypeInfo>(
2070
- /* Size */ 2 , /* Alignment */ 2 , /* Stride */ 2 ,
2071
- /* NumExtraInhabitants */ 65536 - NoPayloadCases, Cases);
2085
+ if (EffectiveNoPayloadCases == 1 ) {
2086
+ return TC.makeTypeInfo <TrivialEnumTypeInfo>(Kind, Cases);
2072
2087
} else {
2073
- auto extraInhabitants = std::numeric_limits<uint32_t >::max () - NoPayloadCases + 1 ;
2074
- if (extraInhabitants > ValueWitnessFlags::MaxNumExtraInhabitants) {
2075
- extraInhabitants = ValueWitnessFlags::MaxNumExtraInhabitants;
2088
+ unsigned Size, NumExtraInhabitants;
2089
+ if (EffectiveNoPayloadCases < 256 ) {
2090
+ Size = 1 ;
2091
+ NumExtraInhabitants = 256 - EffectiveNoPayloadCases;
2092
+ } else if (EffectiveNoPayloadCases < 65536 ) {
2093
+ Size = 2 ;
2094
+ NumExtraInhabitants = 65536 - EffectiveNoPayloadCases;
2095
+ } else {
2096
+ Size = 4 ;
2097
+ NumExtraInhabitants = std::numeric_limits<uint32_t >::max () - EffectiveNoPayloadCases + 1 ;
2098
+ }
2099
+ if (EmptyPayloadCases > 0 ) {
2100
+ // This enum uses no-payload layout, but the source actually does
2101
+ // have payloads (they're just all zero-sized).
2102
+ // If this is really a single-payload enum, we take extra inhabitants
2103
+ // from the first payload, which is zero sized in this case.
2104
+ // If this is really a multi-payload enum, ...
2105
+ NumExtraInhabitants = 0 ;
2106
+ }
2107
+ if (NumExtraInhabitants > ValueWitnessFlags::MaxNumExtraInhabitants) {
2108
+ NumExtraInhabitants = ValueWitnessFlags::MaxNumExtraInhabitants;
2076
2109
}
2077
2110
return TC.makeTypeInfo <NoPayloadEnumTypeInfo>(
2078
- /* Size */ 4 , /* Alignment */ 4 , /* Stride */ 4 ,
2079
- /* NumExtraInhabitants */ extraInhabitants , Cases);
2111
+ /* Size */ Size , /* Alignment */ Size , /* Stride */ Size ,
2112
+ NumExtraInhabitants, Kind , Cases);
2080
2113
}
2081
2114
} else if (PayloadCases.size () == 1 ) {
2082
2115
// SinglePayloadEnumImplStrategy
@@ -2087,26 +2120,26 @@ class EnumTypeInfoBuilder {
2087
2120
}
2088
2121
// An enum consisting of a single payload case and nothing else
2089
2122
// is lowered as the payload type.
2090
- if (NoPayloadCases == 0 )
2123
+ if (EffectiveNoPayloadCases == 0 )
2091
2124
return CaseTI;
2092
2125
// Below logic should match the runtime function
2093
2126
// swift_initEnumMetadataSinglePayload().
2094
2127
auto PayloadExtraInhabitants = CaseTI->getNumExtraInhabitants ();
2095
- if (PayloadExtraInhabitants >= NoPayloadCases ) {
2128
+ if (PayloadExtraInhabitants >= EffectiveNoPayloadCases ) {
2096
2129
// Extra inhabitants can encode all no-payload cases.
2097
- NumExtraInhabitants = PayloadExtraInhabitants - NoPayloadCases ;
2130
+ NumExtraInhabitants = PayloadExtraInhabitants - EffectiveNoPayloadCases ;
2098
2131
} else {
2099
2132
// Not enough extra inhabitants for all cases. We have to add an
2100
2133
// extra tag field.
2101
2134
NumExtraInhabitants = 0 ;
2102
- auto tagCounts = getEnumTagCounts (Size, NoPayloadCases ,
2135
+ auto tagCounts = getEnumTagCounts (Size, EffectiveNoPayloadCases ,
2103
2136
/* payloadCases=*/ 1 );
2104
2137
Size += tagCounts.numTagBytes ;
2105
2138
Alignment = std::max (Alignment, tagCounts.numTagBytes );
2106
2139
}
2107
2140
unsigned Stride = ((Size + Alignment - 1 ) & ~(Alignment - 1 ));
2108
2141
return TC.makeTypeInfo <SinglePayloadEnumTypeInfo>(
2109
- Size, Alignment, Stride, NumExtraInhabitants, BitwiseTakable, Cases);
2142
+ Size, Alignment, Stride, NumExtraInhabitants, BitwiseTakable, Kind, Cases);
2110
2143
} else {
2111
2144
// MultiPayloadEnumImplStrategy
2112
2145
@@ -2207,7 +2240,7 @@ class EnumTypeInfoBuilder {
2207
2240
} else {
2208
2241
// Dynamic multi-payload enums cannot use spare bits, so they
2209
2242
// always use a separate tag value:
2210
- auto tagCounts = getEnumTagCounts (Size, NoPayloadCases ,
2243
+ auto tagCounts = getEnumTagCounts (Size, EffectiveNoPayloadCases ,
2211
2244
PayloadCases.size ());
2212
2245
Size += tagCounts.numTagBytes ;
2213
2246
// Dynamic multi-payload enums use the tag representations not assigned
0 commit comments