// // Copyright 2002 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //
// CallDAG.h: Implements a call graph DAG of functions to be re-used accross // analyses, allows to efficiently traverse the functions in topological // order.
// The CallDAGCreator does all the processing required to create the CallDAG // structure so that the latter contains only the necessary variables. class CallDAG::CallDAGCreator : public TIntermTraverser
{ public:
CallDAGCreator(TDiagnostics *diagnostics)
: TIntermTraverser(true, false, false),
mDiagnostics(diagnostics),
mCurrentFunction(nullptr),
mCurrentIndex(0)
{}
InitResult assignIndices()
{ int skipped = 0; for (auto &it : mFunctions)
{ // Skip unimplemented functions if (it.second.definitionNode)
{
InitResult result = assignIndicesInternal(&it.second); if (result != INITDAG_SUCCESS)
{ return result;
}
} else
{
skipped++;
}
}
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
{ // Create the record if need be and remember the definition node.
mCurrentFunction = &mFunctions[node->getFunction()->uniqueId().get()]; // Name will be overwritten here. If we've already traversed the prototype of this function, // it should have had the same name.
ASSERT(mCurrentFunction->name == "" ||
mCurrentFunction->name == node->getFunction()->name());
mCurrentFunction->name = node->getFunction()->name();
mCurrentFunction->definitionNode = node;
// Function declaration, create an empty record. auto &record = mFunctions[node->getFunction()->uniqueId().get()];
record.name = node->getFunction()->name();
}
// Track functions called from another function. bool visitAggregate(Visit visit, TIntermAggregate *node) override
{ if (node->getOp() == EOpCallFunctionInAST)
{ // Function call, add the callees auto it = mFunctions.find(node->getFunction()->uniqueId().get());
ASSERT(it != mFunctions.end());
// We might be traversing the initializer of a global variable. Even though function // calls in global scope are forbidden by the parser, some subsequent AST // transformations can add them to emulate particular features. if (mCurrentFunction)
{
mCurrentFunction->callees.insert(&it->second);
}
} returntrue;
}
// Recursively assigns indices to a sub DAG
InitResult assignIndicesInternal(CreatorFunctionData *root)
{ // Iterative implementation of the index assignment algorithm. A recursive version // would be prettier but since the CallDAG creation runs before the limiting of the // call depth, we might get stack overflows (computation of the call depth uses the // CallDAG).
ASSERT(root);
if (root->indexAssigned)
{ return INITDAG_SUCCESS;
}
// If we didn't have to detect recursion, functionsToProcess could be a simple queue // in which we add the function being processed's callees. However in order to detect // recursion we need to know which functions we are currently visiting. For that reason // functionsToProcess will look like a concatenation of segments of the form // [F visiting = true, subset of F callees with visiting = false] and the following // segment (if any) will be start with a callee of F. // This way we can remember when we started visiting a function, to put visiting back // to false.
TVector<CreatorFunctionData *> functionsToProcess;
functionsToProcess.push_back(root);
if (!function->definitionNode)
{
errorStream << "Undefined function '" << function->name
<< "()' used in the following call chain:";
result = INITDAG_UNDEFINED; break;
}
if (function->indexAssigned)
{
functionsToProcess.pop_back(); continue;
}
function->visiting = true;
for (auto callee : function->callees)
{
functionsToProcess.push_back(callee);
// Check if the callee is already being visited after pushing it so that it appears // in the chain printed in the info log. if (callee->visiting)
{
errorStream << "Recursive function call in the following call chain:";
result = INITDAG_RECURSION; break;
}
}
if (result != INITDAG_SUCCESS)
{ break;
}
}
// The call chain is made of the function we were visiting when the error was detected. if (result != INITDAG_SUCCESS)
{ bool first = true; for (auto function : functionsToProcess)
{ if (function->visiting)
{ if (!first)
{
errorStream << " -> ";
}
errorStream << function->name << ")";
first = false;
}
} if (mDiagnostics)
{
std::string errorStr = errorStream.str();
mDiagnostics->globalError(errorStr.c_str());
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.