Improve AST cyclic detection performance (#3330)

This commit is contained in:
Paul Fultz II 2021-07-08 14:13:51 -05:00 committed by GitHub
parent 56924643be
commit 7e70a91613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 18 deletions

View File

@ -1340,30 +1340,33 @@ std::string Token::stringifyList(bool varid) const
return stringifyList(varid, false, true, true, true, nullptr, nullptr); return stringifyList(varid, false, true, true, true, nullptr, nullptr);
} }
static Token* checkAstCycle(Token* tok) void Token::astParent(Token* tok)
{ {
std::set<const Token*> visited; const Token* tok2 = tok;
visitAstNodes(tok, [&](const Token* child) { while (tok2) {
if (!visited.insert(child).second) if (this == tok2)
throw InternalError(child, "Internal error. AST cyclic dependency."); throw InternalError(this, "Internal error. AST cyclic dependency.");
return ChildrenToVisit::op1_and_op2; tok2 = tok2->astParent();
});
while (tok->astParent()) {
if (!visited.insert(tok->astParent()).second) // #6838/#6726/#8352 avoid hang on garbage code
throw InternalError(tok, "Internal error. AST cyclic dependency.");
tok = tok->astParent();
} }
return tok; // Clear children to avoid nodes referenced twice
if (this->astParent()) {
Token* parent = this->astParent();
if (parent->astOperand1() == this)
parent->mImpl->mAstOperand1 = nullptr;
if (parent->astOperand2() == this)
parent->mImpl->mAstOperand2 = nullptr;
}
mImpl->mAstParent = tok;
} }
void Token::astOperand1(Token *tok) void Token::astOperand1(Token *tok)
{ {
if (mImpl->mAstOperand1) if (mImpl->mAstOperand1)
mImpl->mAstOperand1->mImpl->mAstParent = nullptr; mImpl->mAstOperand1->astParent(nullptr);
// goto parent operator // goto parent operator
if (tok) { if (tok) {
tok = checkAstCycle(tok); tok = tok->astTop();
tok->mImpl->mAstParent = this; tok->astParent(this);
} }
mImpl->mAstOperand1 = tok; mImpl->mAstOperand1 = tok;
} }
@ -1371,11 +1374,11 @@ void Token::astOperand1(Token *tok)
void Token::astOperand2(Token *tok) void Token::astOperand2(Token *tok)
{ {
if (mImpl->mAstOperand2) if (mImpl->mAstOperand2)
mImpl->mAstOperand2->mImpl->mAstParent = nullptr; mImpl->mAstOperand2->astParent(nullptr);
// goto parent operator // goto parent operator
if (tok) { if (tok) {
tok = checkAstCycle(tok); tok = tok->astTop();
tok->mImpl->mAstParent = this; tok->astParent(this);
} }
mImpl->mAstOperand2 = tok; mImpl->mAstOperand2 = tok;
} }

View File

@ -1278,6 +1278,7 @@ private:
public: public:
void astOperand1(Token *tok); void astOperand1(Token *tok);
void astOperand2(Token *tok); void astOperand2(Token *tok);
void astParent(Token* tok);
Token * astOperand1() { Token * astOperand1() {
return mImpl->mAstOperand1; return mImpl->mAstOperand1;