@@ -2707,6 +2707,7 @@ namespace {
2707
2707
2708
2708
CopyDestroyStrategy CopyDestroyKind;
2709
2709
ReferenceCounting Refcounting;
2710
+ bool AllowFixedLayoutOptimizations;
2710
2711
2711
2712
static EnumPayloadSchema getPayloadSchema (ArrayRef<Element> payloads) {
2712
2713
// TODO: We might be able to form a nicer schema if the payload elements
@@ -2726,6 +2727,7 @@ namespace {
2726
2727
MultiPayloadEnumImplStrategy (IRGenModule &IGM,
2727
2728
TypeInfoKind tik,
2728
2729
IsFixedSize_t alwaysFixedSize,
2730
+ bool allowFixedLayoutOptimizations,
2729
2731
unsigned NumElements,
2730
2732
std::vector<Element> &&WithPayload,
2731
2733
std::vector<Element> &&WithNoPayload)
@@ -2734,7 +2736,8 @@ namespace {
2734
2736
std::move (WithPayload),
2735
2737
std::move(WithNoPayload),
2736
2738
getPayloadSchema(WithPayload)),
2737
- CopyDestroyKind(Normal)
2739
+ CopyDestroyKind(Normal),
2740
+ AllowFixedLayoutOptimizations(allowFixedLayoutOptimizations)
2738
2741
{
2739
2742
assert (ElementsWithPayload.size () > 1 );
2740
2743
@@ -2794,7 +2797,7 @@ namespace {
2794
2797
// we might need the payload size if from another module the enum has
2795
2798
// a dynamic size, which can happen if the enum contains a resilient
2796
2799
// payload.
2797
- return !AlwaysFixedSize ;
2800
+ return !AllowFixedLayoutOptimizations ;
2798
2801
}
2799
2802
2800
2803
unsigned getPayloadSizeForMetadata () const override {
@@ -4595,20 +4598,26 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC,
4595
4598
unsigned numElements = 0 ;
4596
4599
TypeInfoKind tik = Loadable;
4597
4600
IsFixedSize_t alwaysFixedSize = IsFixedSize;
4601
+ bool allowFixedLayoutOptimizations = true ;
4598
4602
std::vector<Element> elementsWithPayload;
4599
4603
std::vector<Element> elementsWithNoPayload;
4600
4604
4601
- // The most general resilience scope that can have knowledge of this
4602
- // enum's layout. If all payload types have a fixed size in this
4603
- // resilience scope, we can make further assumptions to optimize
4604
- // layout.
4605
- ResilienceScope scope = ResilienceScope::Universal;
4605
+ // Resilient enums are manipulated as opaque values, except we still
4606
+ // make the following assumptions:
4607
+ // 1) Physical case indices won't change
4608
+ // 2) The indirect-ness of cases won't change
4609
+ // 3) Payload types won't change in a non-resilient way
4610
+ bool isResilient = TC.IGM .isResilient (theEnum, ResilienceScope::Component);
4611
+
4612
+ // The most general resilience scope where the enum type is visible.
4613
+ // Case numbering must not depend on any information that is not static
4614
+ // in this resilience scope.
4615
+ ResilienceScope accessScope = TC.IGM .getResilienceScopeForAccess (theEnum);
4606
4616
4607
- // TODO: Replace this with 'public or internal with @availability' check
4608
- // once that is in place
4609
- if (theEnum->getFormalAccess () != Accessibility::Public ||
4610
- TC.IGM .isResilient (theEnum, ResilienceScope::Universal))
4611
- scope = ResilienceScope::Component;
4617
+ // The most general resilience scope where the enum's layout is known.
4618
+ // Fixed-size optimizations can be applied if all payload types are
4619
+ // fixed-size from this resilience scope.
4620
+ ResilienceScope layoutScope = TC.IGM .getResilienceScopeForLayout (theEnum);
4612
4621
4613
4622
for (auto elt : theEnum->getAllElements ()) {
4614
4623
numElements++;
@@ -4638,14 +4647,20 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC,
4638
4647
= TC.tryGetCompleteTypeInfo (origArgLoweredTy.getSwiftRValueType ());
4639
4648
assert (origArgTI && " didn't complete type info?!" );
4640
4649
4641
- // If the unsubstituted argument contains a generic parameter type, or if
4642
- // the substituted argument is not universally fixed-size, we need to
4643
- // constrain our layout optimizations to what the runtime can reproduce.
4644
- if (!origArgTI->isFixedSize (scope))
4645
- alwaysFixedSize = IsNotFixedSize;
4646
-
4647
- auto loadableOrigArgTI = dyn_cast<LoadableTypeInfo>(origArgTI);
4648
- if (loadableOrigArgTI && loadableOrigArgTI->isKnownEmpty ()) {
4650
+ // If the unsubstituted argument contains a generic parameter type, or
4651
+ // is not fixed-size in all resilience domains that have knowledge of
4652
+ // this enum's layout, we need to constrain our layout optimizations to
4653
+ // what the runtime can reproduce.
4654
+ if (!isResilient &&
4655
+ !origArgTI->isFixedSize (layoutScope))
4656
+ allowFixedLayoutOptimizations = false ;
4657
+
4658
+ // If the payload is empty, turn the case into a no-payload case, but
4659
+ // only if case numbering remains unchanged from all resilience domains
4660
+ // that can see the enum.
4661
+ if (origArgTI->isFixedSize (accessScope) &&
4662
+ isa<LoadableTypeInfo>(origArgTI) &&
4663
+ cast<LoadableTypeInfo>(origArgTI)->isKnownEmpty ()) {
4649
4664
elementsWithNoPayload.push_back ({elt, nullptr , nullptr });
4650
4665
} else {
4651
4666
// *Now* apply the substitutions and get the type info for the instance's
@@ -4655,16 +4670,22 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC,
4655
4670
auto *substArgTI = &TC.IGM .getTypeInfo (fieldTy);
4656
4671
4657
4672
elementsWithPayload.push_back ({elt, substArgTI, origArgTI});
4658
- if (!substArgTI->isFixedSize ())
4659
- tik = Opaque;
4660
- else if (!substArgTI->isLoadable () && tik > Fixed)
4661
- tik = Fixed;
4662
4673
4663
- // If the substituted argument contains a type that is not universally
4664
- // fixed-size, we need to constrain our layout optimizations to what
4665
- // the runtime can reproduce.
4666
- if (!substArgTI->isFixedSize (scope))
4667
- alwaysFixedSize = IsNotFixedSize;
4674
+ if (!isResilient) {
4675
+ if (!substArgTI->isFixedSize (ResilienceScope::Component))
4676
+ tik = Opaque;
4677
+ else if (!substArgTI->isLoadable () && tik > Fixed)
4678
+ tik = Fixed;
4679
+
4680
+ // If the substituted argument contains a type that is not fixed-size
4681
+ // in all resilience domains that have knowledge of this enum's layout,
4682
+ // we need to constrain our layout optimizations to what the runtime
4683
+ // can reproduce.
4684
+ if (!substArgTI->isFixedSize (layoutScope)) {
4685
+ alwaysFixedSize = IsNotFixedSize;
4686
+ allowFixedLayoutOptimizations = false ;
4687
+ }
4688
+ }
4668
4689
}
4669
4690
}
4670
4691
@@ -4673,12 +4694,7 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC,
4673
4694
+ elementsWithNoPayload.size ()
4674
4695
&& " not all elements accounted for" );
4675
4696
4676
- // Resilient enums are manipulated as opaque values, except we still
4677
- // make the following assumptions:
4678
- // 1) Physical case indices won't change
4679
- // 2) The indirect-ness of cases won't change
4680
- // 3) Payload types won't change in a non-resilient way
4681
- if (TC.IGM .isResilient (theEnum, ResilienceScope::Component)) {
4697
+ if (isResilient) {
4682
4698
return new ResilientEnumImplStrategy (TC.IGM ,
4683
4699
numElements,
4684
4700
std::move (elementsWithPayload),
@@ -4702,6 +4718,7 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC,
4702
4718
std::move (elementsWithNoPayload));
4703
4719
if (elementsWithPayload.size () > 1 )
4704
4720
return new MultiPayloadEnumImplStrategy (TC.IGM , tik, alwaysFixedSize,
4721
+ allowFixedLayoutOptimizations,
4705
4722
numElements,
4706
4723
std::move (elementsWithPayload),
4707
4724
std::move (elementsWithNoPayload));
@@ -5216,7 +5233,7 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC,
5216
5233
// The runtime currently does not track spare bits, so we can't use them
5217
5234
// if the type is layout-dependent. (Even when the runtime does, it will
5218
5235
// likely only track a subset of the spare bits.)
5219
- if (!AlwaysFixedSize || TIK < Loadable) {
5236
+ if (!AllowFixedLayoutOptimizations || TIK < Loadable) {
5220
5237
if (CommonSpareBits.size () < payloadBits)
5221
5238
CommonSpareBits.extendWithClearBits (payloadBits);
5222
5239
continue ;
0 commit comments