46 static constexpr size_t kExpressionCost = 1;
47 static constexpr size_t kStatementCost = 1;
48 static constexpr size_t kUnknownCost = -1;
49 static constexpr size_t kProgramSizeLimit = 100000;
50 static constexpr size_t kProgramStackDepthLimit = 50;
58 size_t functionSize()
const {
67 if (
size_t *cachedCost = fFunctionCostMap.find(decl)) {
69 if (*cachedCost == kUnknownCost) {
74 for (
auto unwind = fStack.rbegin(); unwind != fStack.rend(); ++unwind) {
75 msg =
"\n\t" + (*unwind)->description() + msg;
76 if (*unwind == decl) {
80 msg =
"potential recursion (function call cycle) not allowed:" + msg;
87 fFunctionSize = *cachedCost;
92 if (fStack.size() >= kProgramStackDepthLimit) {
93 std::string msg =
"exceeded max function call depth:";
94 for (
auto unwind = fStack.begin(); unwind != fStack.end(); ++unwind) {
95 msg +=
"\n\t" + (*unwind)->description();
100 fFunctionCostMap.set(decl, 0);
105 fFunctionCostMap.set(decl, kUnknownCost);
106 fStack.push_back(decl);
108 bool result = INHERITED::visitProgramElement(pe);
109 fFunctionCostMap.set(decl, fFunctionSize);
115 return INHERITED::visitProgramElement(pe);
118 bool visitStatement(
const Statement& stmt)
override {
119 switch (stmt.
kind()) {
120 case Statement::Kind::kFor: {
124 bool earlyExit =
false;
130 size_t originalFunctionSize = fFunctionSize;
133 if (forStmt.
next() && this->visitExpression(*forStmt.
next())) {
136 if (forStmt.
test() && this->visitExpression(*forStmt.
test())) {
139 if (this->visitStatement(*forStmt.
statement())) {
152 case Statement::Kind::kExpression:
158 case Statement::Kind::kVarDeclaration:
170 return INHERITED::visitStatement(stmt);
173 bool visitExpression(
const Expression& expr)
override {
175 bool earlyExit =
false;
176 size_t expressionCost = kExpressionCost;
183 if (decl->definition() && !decl->isIntrinsic()) {
184 size_t originalFunctionSize = fFunctionSize;
187 earlyExit = this->visitProgramElement(*decl->definition());
188 expressionCost = fFunctionSize;
190 fFunctionSize = originalFunctionSize;
195 return earlyExit || INHERITED::visitExpression(expr);
202 size_t fFunctionSize = 0;
204 std::vector<const FunctionDeclaration*> fStack;
208 ProgramSizeVisitor visitor{context};
209 for (
const std::unique_ptr<ProgramElement>& element : program.
fOwnedElements) {
213 visitor.visitProgramElement(*element);
215 if (enforceSizeLimit &&
216 visitor.functionSize() > kProgramSizeLimit &&
#define INHERITED(method,...)
void error(Position position, std::string_view msg)
std::unique_ptr< Statement > & statement()
std::unique_ptr< Expression > & next()
std::unique_ptr< Expression > & test()
std::unique_ptr< Statement > & initializer()
const LoopUnrollInfo * unrollInfo() const
std::string description() const override
const FunctionDeclaration & declaration() const
virtual bool visitProgramElement(typename T::ProgramElement &programElement)
static size_t Add(size_t x, size_t y)
static size_t Mul(size_t x, size_t y)
bool CheckProgramStructure(const Program &program, bool enforceSizeLimit)
std::vector< std::unique_ptr< ProgramElement > > fOwnedElements
std::shared_ptr< Context > fContext