Skip to content

Commit 487c784

Browse files
shen3qing1Qing Shen
andauthored
[NFC]Do not use recursion for CounterMappingContext::evaluate (#66961)
This causes stack overflows for real-world coverage reports. Ran $ build/bin/llvm-lit -a llvm/test/tools/llvm-cov locally and passed. Co-authored-by: Qing Shen <[email protected]>
1 parent 8466eb7 commit 487c784

File tree

1 file changed

+54
-20
lines changed

1 file changed

+54
-20
lines changed

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -167,27 +167,61 @@ void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const {
167167
}
168168

169169
Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
170-
switch (C.getKind()) {
171-
case Counter::Zero:
172-
return 0;
173-
case Counter::CounterValueReference:
174-
if (C.getCounterID() >= CounterValues.size())
175-
return errorCodeToError(errc::argument_out_of_domain);
176-
return CounterValues[C.getCounterID()];
177-
case Counter::Expression: {
178-
if (C.getExpressionID() >= Expressions.size())
179-
return errorCodeToError(errc::argument_out_of_domain);
180-
const auto &E = Expressions[C.getExpressionID()];
181-
Expected<int64_t> LHS = evaluate(E.LHS);
182-
if (!LHS)
183-
return LHS;
184-
Expected<int64_t> RHS = evaluate(E.RHS);
185-
if (!RHS)
186-
return RHS;
187-
return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS;
188-
}
170+
struct StackElem {
171+
Counter ICounter;
172+
int64_t LHS = 0;
173+
enum {
174+
KNeverVisited = 0,
175+
KVisitedOnce = 1,
176+
KVisitedTwice = 2,
177+
} VisitCount = KNeverVisited;
178+
};
179+
180+
std::stack<StackElem> CounterStack;
181+
CounterStack.push({C});
182+
183+
int64_t LastPoppedValue;
184+
185+
while (!CounterStack.empty()) {
186+
StackElem &Current = CounterStack.top();
187+
188+
switch (Current.ICounter.getKind()) {
189+
case Counter::Zero:
190+
LastPoppedValue = 0;
191+
CounterStack.pop();
192+
break;
193+
case Counter::CounterValueReference:
194+
if (Current.ICounter.getCounterID() >= CounterValues.size())
195+
return errorCodeToError(errc::argument_out_of_domain);
196+
LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
197+
CounterStack.pop();
198+
break;
199+
case Counter::Expression: {
200+
if (Current.ICounter.getExpressionID() >= Expressions.size())
201+
return errorCodeToError(errc::argument_out_of_domain);
202+
const auto &E = Expressions[Current.ICounter.getExpressionID()];
203+
if (Current.VisitCount == StackElem::KNeverVisited) {
204+
CounterStack.push(StackElem{E.LHS});
205+
Current.VisitCount = StackElem::KVisitedOnce;
206+
} else if (Current.VisitCount == StackElem::KVisitedOnce) {
207+
Current.LHS = LastPoppedValue;
208+
CounterStack.push(StackElem{E.RHS});
209+
Current.VisitCount = StackElem::KVisitedTwice;
210+
} else {
211+
int64_t LHS = Current.LHS;
212+
int64_t RHS = LastPoppedValue;
213+
LastPoppedValue =
214+
E.Kind == CounterExpression::Subtract ? LHS - RHS : LHS + RHS;
215+
CounterStack.pop();
216+
}
217+
break;
218+
}
219+
default:
220+
llvm_unreachable("Unhandled CounterKind");
221+
}
189222
}
190-
llvm_unreachable("Unhandled CounterKind");
223+
224+
return LastPoppedValue;
191225
}
192226

193227
unsigned CounterMappingContext::getMaxCounterID(const Counter &C) const {

0 commit comments

Comments
 (0)