@@ -251,7 +251,7 @@ BuiltinTypeInfo::BuiltinTypeInfo(unsigned Size, unsigned Alignment,
251
251
252
252
// Builtin.Int<N> is mangled as 'Bi' N '_'
253
253
// Returns 0 if this isn't an Int
254
- static unsigned isIntType (std::string name) {
254
+ static unsigned intTypeBitSize (std::string name) {
255
255
llvm::StringRef nameRef (name);
256
256
if (nameRef.starts_with (" Bi" ) && nameRef.ends_with (" _" )) {
257
257
llvm::StringRef naturalRef = nameRef.drop_front (2 ).drop_back ();
@@ -272,23 +272,36 @@ bool BuiltinTypeInfo::readExtraInhabitantIndex(
272
272
*extraInhabitantIndex = -1 ;
273
273
return true ;
274
274
}
275
- unsigned intSize = isIntType (Name);
276
- if (intSize > 0 && intSize < 64 && getSize () <= 8 && intSize < getSize () * 8 ) {
275
+ // If it has extra inhabitants, it could be an integer type with extra
276
+ // inhabitants (such as a bool) or a pointer.
277
+ unsigned intSize = intTypeBitSize (Name);
278
+ if (intSize > 0 ) {
279
+ // This is an integer type
280
+
281
+ // If extra inhabitants are impossible, return early...
282
+ // (assert in debug builds)
283
+ assert (intSize < getSize () * 8
284
+ && " Standard-sized int cannot have extra inhabitants" );
285
+ if (intSize > 64 || getSize () > 8 || intSize >= getSize () * 8 ) {
286
+ *extraInhabitantIndex = -1 ;
287
+ return true ;
288
+ }
289
+
290
+ // Compute range of extra inhabitants
277
291
uint64_t maxValidValue = (((uint64_t )1 ) << intSize) - 1 ;
278
292
uint64_t maxAvailableValue = (((uint64_t )1 ) << (getSize () * 8 )) - 1 ;
279
293
uint64_t computedExtraInhabitants = maxAvailableValue - maxValidValue;
280
294
if (computedExtraInhabitants > ValueWitnessFlags::MaxNumExtraInhabitants) {
281
295
computedExtraInhabitants = ValueWitnessFlags::MaxNumExtraInhabitants;
282
296
}
283
297
assert (getNumExtraInhabitants () == computedExtraInhabitants &&
284
- " Unexpected number of extra inhabitants in an odd-sized integer" );
298
+ " Unexpected number of extra inhabitants in an odd-sized integer" );
285
299
300
+ // Example: maxValidValue is 1 for a 1-bit bool, so any larger value
301
+ // is an extra inhabitant.
286
302
uint64_t rawValue;
287
303
if (!reader.readInteger (address, getSize (), &rawValue))
288
304
return false ;
289
-
290
- // Example: maxValidValue is 1 for a 1-bit bool, so any larger value
291
- // is an extra inhabitant.
292
305
if (maxValidValue < rawValue) {
293
306
*extraInhabitantIndex = rawValue - maxValidValue - 1 ;
294
307
} else {
@@ -307,14 +320,15 @@ bool BuiltinTypeInfo::readExtraInhabitantIndex(
307
320
}
308
321
309
322
BitMask BuiltinTypeInfo::getSpareBits (TypeConverter &TC, bool &hasAddrOnly) const {
310
- unsigned intSize = isIntType (Name);
323
+ unsigned intSize = intTypeBitSize (Name);
311
324
if (intSize > 0 ) {
312
325
// Odd-sized integers export spare bits
313
326
// In particular: bool fields are Int1 and export 7 spare bits
314
327
auto mask = BitMask::oneMask (getSize ());
315
328
mask.keepOnlyMostSignificantBits (getSize () * 8 - intSize);
316
329
return mask;
317
330
} else if (
331
+ Name == " ypXp" || // Any.Type
318
332
Name == " yyXf" // 'yyXf' = @thin () -> Void function
319
333
) {
320
334
// Builtin types that expose pointer spare bits
@@ -578,7 +592,9 @@ class NoPayloadEnumTypeInfo: public EnumTypeInfo {
578
592
}
579
593
580
594
BitMask getSpareBits (TypeConverter &TC, bool &hasAddrOnly) const override {
581
- return BitMask::zeroMask (getSize ());
595
+ auto mask = BitMask (getSize (), maskForCount (getNumCases ()));
596
+ mask.complement ();
597
+ return mask;
582
598
}
583
599
584
600
bool projectEnumValue (remote::MemoryReader &reader,
@@ -648,7 +664,17 @@ class SinglePayloadEnumTypeInfo: public EnumTypeInfo {
648
664
}
649
665
650
666
BitMask getSpareBits (TypeConverter &TC, bool &hasAddrOnly) const override {
651
- return BitMask::zeroMask (getSize ());
667
+ FieldInfo PayloadCase = getCases ()[0 ];
668
+ size_t payloadSize = PayloadCase.TI .getSize ();
669
+ if (getSize () <= payloadSize) {
670
+ return BitMask::zeroMask (getSize ());
671
+ }
672
+ size_t tagSize = getSize () - payloadSize;
673
+ auto mask = BitMask::oneMask (getSize ());
674
+ mask.keepOnlyMostSignificantBits (tagSize * 8 ); // Clear payload bits
675
+ auto tagMaskUsedBits = BitMask (getSize (), maskForCount (getNumCases ()));
676
+ mask.andNotMask (tagMaskUsedBits, payloadSize); // Clear used tag bits
677
+ return mask;
652
678
}
653
679
654
680
// Think of a single-payload enum as being encoded in "pages".
@@ -1961,6 +1987,15 @@ class EnumTypeInfoBuilder {
1961
1987
default : Kind = EnumKind::MultiPayloadEnum; break ;
1962
1988
}
1963
1989
1990
+ // Sanity: Ignore any enum that claims to have a size more than 1MiB
1991
+ // This avoids allocating lots of memory for spare bit mask calculations
1992
+ // when clients try to interpret random chunks of memory as type descriptions.
1993
+ if (Size > (1024ULL * 1024 )) {
1994
+ unsigned Stride = ((Size + Alignment - 1 ) & ~(Alignment - 1 ));
1995
+ return TC.makeTypeInfo <UnsupportedEnumTypeInfo>(
1996
+ Size , Alignment, Stride, NumExtraInhabitants, BitwiseTakable, Kind, Cases);
1997
+ }
1998
+
1964
1999
if (Cases.size () == 1 ) {
1965
2000
if (EffectivePayloadCases == 0 ) {
1966
2001
// Zero-sized enum with only one empty case
@@ -2046,11 +2081,10 @@ class EnumTypeInfoBuilder {
2046
2081
//
2047
2082
2048
2083
// Do we have a fixed layout?
2049
- // TODO: Test whether a missing FixedDescriptor is actually relevant.
2050
2084
auto FixedDescriptor = TC.getBuilder ().getBuiltinTypeDescriptor (TR);
2051
2085
if (!FixedDescriptor || GenericPayloadCases > 0 ) {
2052
2086
// This is a "dynamic multi-payload enum". For example,
2053
- // this occurs with:
2087
+ // this occurs with generics such as :
2054
2088
// ```
2055
2089
// class ClassWithEnum<T> {
2056
2090
// enum E {
@@ -2060,6 +2094,12 @@ class EnumTypeInfoBuilder {
2060
2094
// var e: E?
2061
2095
// }
2062
2096
// ```
2097
+ // and when we have a resilient inner enum, such as:
2098
+ // ```
2099
+ // enum E2 {
2100
+ // case y(E1_resilient)
2101
+ // case z(Int)
2102
+ // }
2063
2103
auto tagCounts = getEnumTagCounts (Size , EffectiveNoPayloadCases,
2064
2104
EffectivePayloadCases);
2065
2105
Size += tagCounts.numTagBytes ;
@@ -2091,7 +2131,6 @@ class EnumTypeInfoBuilder {
2091
2131
unsigned Stride = ((Size + Alignment - 1 ) & ~(Alignment - 1 ));
2092
2132
if (Stride == 0 )
2093
2133
Stride = 1 ;
2094
- auto PayloadSize = EnumTypeInfo::getPayloadSizeForCases (Cases);
2095
2134
2096
2135
// Compute the spare bit mask and determine if we have any address-only fields
2097
2136
auto localSpareBitMask = BitMask::oneMask (Size );
@@ -2103,44 +2142,11 @@ class EnumTypeInfoBuilder {
2103
2142
}
2104
2143
}
2105
2144
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
-
2142
2145
if (localSpareBitMask.isZero () || hasAddrOnly) {
2143
- // Simple case that does not use spare bits
2146
+ // Simple tag-only layout does not use spare bits.
2147
+ // Either:
2148
+ // * There are no spare bits, or
2149
+ // * We can't copy it to strip spare bits.
2144
2150
return TC.makeTypeInfo <TaggedMultiPayloadEnumTypeInfo>(
2145
2151
Size , Alignment, Stride, NumExtraInhabitants,
2146
2152
BitwiseTakable, Cases, EffectivePayloadCases);
0 commit comments