@@ -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,77 @@ 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 == nullptr ) {
2055
+ // We don't have typeinfo; assume it's not
2056
+ // zero-sized to match earlier behavior.
2057
+ // TODO: Maybe this should prompt us to fall
2058
+ // back to UnsupportedEnumTypeInfo??
2059
+ PayloadCases.push_back (Case);
2060
+ } else if (CaseTI->getSize () == 0 ) {
2061
+ // Zero-sized payloads get special treatment
2062
+ ++EmptyPayloadCases;
2063
+ } else {
2064
+ PayloadCases.push_back (Case);
2065
+ }
2052
2066
addCase (Case.Name , CaseTR, CaseTI);
2053
2067
}
2054
2068
}
2069
+ // For layout purposes, cases w/ empty payload are
2070
+ // treated the same as cases with no payload.
2071
+ unsigned EffectiveNoPayloadCases = TrueNoPayloadCases + EmptyPayloadCases;
2055
2072
2056
2073
if (Cases.empty ()) {
2057
2074
return TC.makeTypeInfo <EmptyEnumTypeInfo>(Cases);
2058
2075
}
2059
2076
2077
+ // `Kind` is used when dumping data, so it reflects how the enum was
2078
+ // declared in source; the various *TypeInfo classes mentioned below reflect
2079
+ // the in-memory layout, which may be different because cases whose
2080
+ // payload is zero-sized get treated (for layout purposes) as non-payload
2081
+ // cases.
2082
+ EnumKind Kind;
2083
+ switch (PayloadCases.size () + EmptyPayloadCases) {
2084
+ case 0 : Kind = EnumKind::NoPayloadEnum; break ;
2085
+ case 1 : Kind = EnumKind::SinglePayloadEnum; break ;
2086
+ default : Kind = EnumKind::MultiPayloadEnum; break ;
2087
+ }
2088
+
2060
2089
if (PayloadCases.empty ()) {
2061
2090
// 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);
2091
+ if (EffectiveNoPayloadCases == 1 ) {
2092
+ return TC.makeTypeInfo <TrivialEnumTypeInfo>(Kind, Cases);
2072
2093
} else {
2073
- auto extraInhabitants = std::numeric_limits<uint32_t >::max () - NoPayloadCases + 1 ;
2074
- if (extraInhabitants > ValueWitnessFlags::MaxNumExtraInhabitants) {
2075
- extraInhabitants = ValueWitnessFlags::MaxNumExtraInhabitants;
2094
+ unsigned Size, NumExtraInhabitants;
2095
+ if (EffectiveNoPayloadCases < 256 ) {
2096
+ Size = 1 ;
2097
+ NumExtraInhabitants = 256 - EffectiveNoPayloadCases;
2098
+ } else if (EffectiveNoPayloadCases < 65536 ) {
2099
+ Size = 2 ;
2100
+ NumExtraInhabitants = 65536 - EffectiveNoPayloadCases;
2101
+ } else {
2102
+ Size = 4 ;
2103
+ NumExtraInhabitants = std::numeric_limits<uint32_t >::max () - EffectiveNoPayloadCases + 1 ;
2104
+ }
2105
+ if (EmptyPayloadCases > 0 ) {
2106
+ // This enum uses no-payload layout, but the source actually does
2107
+ // have payloads (they're just all zero-sized).
2108
+ // If this is really a single-payload enum, we take extra inhabitants
2109
+ // from the first payload, which is zero sized in this case.
2110
+ // If this is really a multi-payload enum, ...
2111
+ NumExtraInhabitants = 0 ;
2112
+ }
2113
+ if (NumExtraInhabitants > ValueWitnessFlags::MaxNumExtraInhabitants) {
2114
+ NumExtraInhabitants = ValueWitnessFlags::MaxNumExtraInhabitants;
2076
2115
}
2077
2116
return TC.makeTypeInfo <NoPayloadEnumTypeInfo>(
2078
- /* Size */ 4 , /* Alignment */ 4 , /* Stride */ 4 ,
2079
- /* NumExtraInhabitants */ extraInhabitants , Cases);
2117
+ /* Size */ Size , /* Alignment */ Size , /* Stride */ Size ,
2118
+ NumExtraInhabitants, Kind , Cases);
2080
2119
}
2081
2120
} else if (PayloadCases.size () == 1 ) {
2082
2121
// SinglePayloadEnumImplStrategy
@@ -2087,26 +2126,26 @@ class EnumTypeInfoBuilder {
2087
2126
}
2088
2127
// An enum consisting of a single payload case and nothing else
2089
2128
// is lowered as the payload type.
2090
- if (NoPayloadCases == 0 )
2129
+ if (EffectiveNoPayloadCases == 0 )
2091
2130
return CaseTI;
2092
2131
// Below logic should match the runtime function
2093
2132
// swift_initEnumMetadataSinglePayload().
2094
2133
auto PayloadExtraInhabitants = CaseTI->getNumExtraInhabitants ();
2095
- if (PayloadExtraInhabitants >= NoPayloadCases ) {
2134
+ if (PayloadExtraInhabitants >= EffectiveNoPayloadCases ) {
2096
2135
// Extra inhabitants can encode all no-payload cases.
2097
- NumExtraInhabitants = PayloadExtraInhabitants - NoPayloadCases ;
2136
+ NumExtraInhabitants = PayloadExtraInhabitants - EffectiveNoPayloadCases ;
2098
2137
} else {
2099
2138
// Not enough extra inhabitants for all cases. We have to add an
2100
2139
// extra tag field.
2101
2140
NumExtraInhabitants = 0 ;
2102
- auto tagCounts = getEnumTagCounts (Size, NoPayloadCases ,
2141
+ auto tagCounts = getEnumTagCounts (Size, EffectiveNoPayloadCases ,
2103
2142
/* payloadCases=*/ 1 );
2104
2143
Size += tagCounts.numTagBytes ;
2105
2144
Alignment = std::max (Alignment, tagCounts.numTagBytes );
2106
2145
}
2107
2146
unsigned Stride = ((Size + Alignment - 1 ) & ~(Alignment - 1 ));
2108
2147
return TC.makeTypeInfo <SinglePayloadEnumTypeInfo>(
2109
- Size, Alignment, Stride, NumExtraInhabitants, BitwiseTakable, Cases);
2148
+ Size, Alignment, Stride, NumExtraInhabitants, BitwiseTakable, Kind, Cases);
2110
2149
} else {
2111
2150
// MultiPayloadEnumImplStrategy
2112
2151
@@ -2207,7 +2246,7 @@ class EnumTypeInfoBuilder {
2207
2246
} else {
2208
2247
// Dynamic multi-payload enums cannot use spare bits, so they
2209
2248
// always use a separate tag value:
2210
- auto tagCounts = getEnumTagCounts (Size, NoPayloadCases ,
2249
+ auto tagCounts = getEnumTagCounts (Size, EffectiveNoPayloadCases ,
2211
2250
PayloadCases.size ());
2212
2251
Size += tagCounts.numTagBytes ;
2213
2252
// Dynamic multi-payload enums use the tag representations not assigned
0 commit comments