Skip to content

Commit f79b621

Browse files
committed
SILOptimizer: Fancier 'too complex' check to prevent runaway specialization
We weren't looking at the length of an opaque archetype's type parameter, which could lead to unbounded growth in the number of emitted specializations. Fixes rdar://problem/121867690.
1 parent 3a5ee89 commit f79b621

File tree

2 files changed

+68
-120
lines changed

2 files changed

+68
-120
lines changed

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 46 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -82,133 +82,59 @@ static const unsigned TypeDepthThreshold = 50;
8282
/// Set the width threshold rather high, because some projects uses very wide
8383
/// tuples to model fixed size arrays.
8484
static const unsigned TypeWidthThreshold = 2000;
85+
/// Max length of an opaque archetype's type parameter.
86+
static const unsigned TypeLengthThreshold = 10;
8587

8688
/// Compute the width and the depth of a type.
8789
/// We compute both, because some pathological test-cases result in very
8890
/// wide types and some others result in very deep types. It is important
8991
/// to bail as soon as we hit the threshold on any of both dimensions to
9092
/// prevent compiler hangs and crashes.
91-
static std::pair<unsigned, unsigned> getTypeDepthAndWidth(Type t) {
92-
unsigned Depth = 0;
93-
unsigned Width = 0;
94-
if (auto *BGT = t->getAs<BoundGenericType>()) {
95-
auto *NTD = BGT->getNominalOrBoundGenericNominal();
96-
if (NTD) {
97-
auto StoredProperties = NTD->getStoredProperties();
98-
Width += StoredProperties.size();
99-
}
100-
++Depth;
101-
unsigned MaxTypeDepth = 0;
102-
auto GenericArgs = BGT->getGenericArgs();
103-
for (auto Ty : GenericArgs) {
104-
unsigned TypeWidth;
105-
unsigned TypeDepth;
106-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Ty);
107-
if (TypeDepth > MaxTypeDepth)
108-
MaxTypeDepth = TypeDepth;
109-
Width += TypeWidth;
110-
}
111-
Depth += MaxTypeDepth;
112-
return std::make_pair(Depth, Width);
113-
}
114-
115-
if (auto *TupleTy = t->getAs<TupleType>()) {
116-
Width += TupleTy->getNumElements();
117-
++Depth;
118-
unsigned MaxTypeDepth = 0;
119-
auto ElementTypes = TupleTy->getElementTypes();
120-
for (auto Ty : ElementTypes) {
121-
unsigned TypeWidth;
122-
unsigned TypeDepth;
123-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Ty);
124-
if (TypeDepth > MaxTypeDepth)
125-
MaxTypeDepth = TypeDepth;
126-
Width += TypeWidth;
127-
}
128-
Depth += MaxTypeDepth;
129-
return std::make_pair(Depth, Width);
130-
}
131-
132-
if (auto *FnTy = t->getAs<SILFunctionType>()) {
133-
++Depth;
134-
unsigned MaxTypeDepth = 0;
135-
auto Params = FnTy->getParameters();
136-
Width += Params.size();
137-
for (auto Param : Params) {
138-
unsigned TypeWidth;
139-
unsigned TypeDepth;
140-
std::tie(TypeDepth, TypeWidth) =
141-
getTypeDepthAndWidth(Param.getInterfaceType());
142-
if (TypeDepth > MaxTypeDepth)
143-
MaxTypeDepth = TypeDepth;
144-
Width += TypeWidth;
145-
}
146-
auto Results = FnTy->getResults();
147-
Width += Results.size();
148-
for (auto Result : Results) {
149-
unsigned TypeWidth;
150-
unsigned TypeDepth;
151-
std::tie(TypeDepth, TypeWidth) =
152-
getTypeDepthAndWidth(Result.getInterfaceType());
153-
if (TypeDepth > MaxTypeDepth)
154-
MaxTypeDepth = TypeDepth;
155-
Width += TypeWidth;
156-
}
157-
if (FnTy->hasErrorResult()) {
158-
Width += 1;
159-
unsigned TypeWidth;
160-
unsigned TypeDepth;
161-
std::tie(TypeDepth, TypeWidth) =
162-
getTypeDepthAndWidth(FnTy->getErrorResult().getInterfaceType());
163-
if (TypeDepth > MaxTypeDepth)
164-
MaxTypeDepth = TypeDepth;
165-
Width += TypeWidth;
166-
}
167-
Depth += MaxTypeDepth;
168-
return std::make_pair(Depth, Width);
169-
}
170-
171-
if (auto *FnTy = t->getAs<FunctionType>()) {
172-
++Depth;
173-
unsigned MaxTypeDepth = 0;
174-
auto Params = FnTy->getParams();
175-
Width += Params.size();
176-
for (auto &Param : Params) {
177-
unsigned TypeWidth;
178-
unsigned TypeDepth;
179-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(Param.getParameterType());
180-
if (TypeDepth > MaxTypeDepth)
181-
MaxTypeDepth = TypeDepth;
182-
Width += TypeWidth;
183-
}
184-
unsigned TypeWidth;
185-
unsigned TypeDepth;
186-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(FnTy->getResult());
187-
if (TypeDepth > MaxTypeDepth)
188-
MaxTypeDepth = TypeDepth;
189-
Width += TypeWidth;
190-
Depth += MaxTypeDepth;
191-
return std::make_pair(Depth, Width);
192-
}
193-
194-
if (auto *MT = t->getAs<MetatypeType>()) {
195-
Depth += 1;
196-
unsigned TypeWidth;
197-
unsigned TypeDepth;
198-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(MT->getInstanceType());
199-
Width += TypeWidth;
200-
Depth += TypeDepth;
201-
return std::make_pair(Depth, Width);
202-
}
203-
204-
return std::make_pair(Depth, Width);
205-
}
206-
20793
static bool isTypeTooComplex(Type t) {
208-
unsigned TypeWidth;
209-
unsigned TypeDepth;
210-
std::tie(TypeDepth, TypeWidth) = getTypeDepthAndWidth(t);
211-
return TypeWidth >= TypeWidthThreshold || TypeDepth >= TypeDepthThreshold;
94+
struct Walker : TypeWalker {
95+
unsigned Depth = 0;
96+
unsigned MaxDepth = 0;
97+
unsigned MaxWidth = 0;
98+
unsigned MaxLength = 0;
99+
100+
Action walkToTypePre(Type ty) override {
101+
// The TypeWalker won't visit the interface type encapsulated by the
102+
// archetype, so we do it directly to measure its length.
103+
if (auto *opaqueArchetypeTy = ty->getAs<OpaqueTypeArchetypeType>()) {
104+
auto interfaceTy = opaqueArchetypeTy->getInterfaceType();
105+
106+
unsigned length = 0;
107+
while (auto memberTy = interfaceTy->getAs<DependentMemberType>()) {
108+
++length;
109+
interfaceTy = memberTy->getBase();
110+
}
111+
assert(interfaceTy->is<GenericTypeParamType>());
112+
113+
if (length > MaxLength)
114+
MaxLength = length;
115+
}
116+
117+
++Depth;
118+
MaxDepth = std::max(Depth, MaxDepth);
119+
120+
++MaxWidth;
121+
122+
return Action::Continue;
123+
}
124+
125+
Action walkToTypePost(Type ty) override {
126+
--Depth;
127+
128+
return Action::Continue;
129+
}
130+
};
131+
132+
Walker walker;
133+
t.walk(walker);
134+
135+
return (walker.MaxWidth >= TypeWidthThreshold ||
136+
walker.MaxDepth >= TypeDepthThreshold ||
137+
walker.MaxLength >= TypeLengthThreshold);
212138
}
213139

214140
namespace {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-swift-frontend -emit-sil -O %s -disable-availability-checking
2+
3+
// This should not hang forever.
4+
5+
public func foo() -> some P {
6+
return S()
7+
}
8+
9+
public protocol P {
10+
associatedtype A: P
11+
func p() -> A
12+
}
13+
14+
public struct S: P {
15+
public func p() -> some P { return self }
16+
}
17+
18+
public func bar<T: P>(_ t: T, _ n: Int) {
19+
if n > 0 { bar(t.p(), n - 1) }
20+
}
21+
22+
bar(foo(), 1000)

0 commit comments

Comments
 (0)