summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/DetectCallDepth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/DetectCallDepth.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/DetectCallDepth.cpp185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/compiler/DetectCallDepth.cpp b/src/3rdparty/angle/src/compiler/DetectCallDepth.cpp
new file mode 100644
index 0000000000..60df52c715
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/DetectCallDepth.cpp
@@ -0,0 +1,185 @@
+//
+// Copyright (c) 2002-2011 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.
+//
+
+#include "compiler/DetectCallDepth.h"
+#include "compiler/InfoSink.h"
+
+DetectCallDepth::FunctionNode::FunctionNode(const TString& fname)
+ : name(fname),
+ visit(PreVisit)
+{
+}
+
+const TString& DetectCallDepth::FunctionNode::getName() const
+{
+ return name;
+}
+
+void DetectCallDepth::FunctionNode::addCallee(
+ DetectCallDepth::FunctionNode* callee)
+{
+ for (size_t i = 0; i < callees.size(); ++i) {
+ if (callees[i] == callee)
+ return;
+ }
+ callees.push_back(callee);
+}
+
+int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDepth, int depth)
+{
+ ASSERT(visit == PreVisit);
+ ASSERT(detectCallDepth);
+
+ int maxDepth = depth;
+ visit = InVisit;
+ for (size_t i = 0; i < callees.size(); ++i) {
+ switch (callees[i]->visit) {
+ case InVisit:
+ // cycle detected, i.e., recursion detected.
+ return kInfiniteCallDepth;
+ case PostVisit:
+ break;
+ case PreVisit: {
+ // Check before we recurse so we don't go too depth
+ if (detectCallDepth->checkExceedsMaxDepth(depth))
+ return depth;
+ int callDepth = callees[i]->detectCallDepth(detectCallDepth, depth + 1);
+ // Check after we recurse so we can exit immediately and provide info.
+ if (detectCallDepth->checkExceedsMaxDepth(callDepth)) {
+ detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName();
+ return callDepth;
+ }
+ maxDepth = std::max(callDepth, maxDepth);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ visit = PostVisit;
+ return maxDepth;
+}
+
+void DetectCallDepth::FunctionNode::reset()
+{
+ visit = PreVisit;
+}
+
+DetectCallDepth::DetectCallDepth(TInfoSink& infoSink, bool limitCallStackDepth, int maxCallStackDepth)
+ : TIntermTraverser(true, false, true, false),
+ currentFunction(NULL),
+ infoSink(infoSink),
+ maxDepth(limitCallStackDepth ? maxCallStackDepth : FunctionNode::kInfiniteCallDepth)
+{
+}
+
+DetectCallDepth::~DetectCallDepth()
+{
+ for (size_t i = 0; i < functions.size(); ++i)
+ delete functions[i];
+}
+
+bool DetectCallDepth::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ switch (node->getOp())
+ {
+ case EOpPrototype:
+ // Function declaration.
+ // Don't add FunctionNode here because node->getName() is the
+ // unmangled function name.
+ break;
+ case EOpFunction: {
+ // Function definition.
+ if (visit == PreVisit) {
+ currentFunction = findFunctionByName(node->getName());
+ if (currentFunction == NULL) {
+ currentFunction = new FunctionNode(node->getName());
+ functions.push_back(currentFunction);
+ }
+ } else if (visit == PostVisit) {
+ currentFunction = NULL;
+ }
+ break;
+ }
+ case EOpFunctionCall: {
+ // Function call.
+ if (visit == PreVisit) {
+ FunctionNode* func = findFunctionByName(node->getName());
+ if (func == NULL) {
+ func = new FunctionNode(node->getName());
+ functions.push_back(func);
+ }
+ if (currentFunction)
+ currentFunction->addCallee(func);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return true;
+}
+
+bool DetectCallDepth::checkExceedsMaxDepth(int depth)
+{
+ return depth >= maxDepth;
+}
+
+void DetectCallDepth::resetFunctionNodes()
+{
+ for (size_t i = 0; i < functions.size(); ++i) {
+ functions[i]->reset();
+ }
+}
+
+DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepthForFunction(FunctionNode* func)
+{
+ currentFunction = NULL;
+ resetFunctionNodes();
+
+ int maxCallDepth = func->detectCallDepth(this, 1);
+
+ if (maxCallDepth == FunctionNode::kInfiniteCallDepth)
+ return kErrorRecursion;
+
+ if (maxCallDepth >= maxDepth)
+ return kErrorMaxDepthExceeded;
+
+ return kErrorNone;
+}
+
+DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepth()
+{
+ if (maxDepth != FunctionNode::kInfiniteCallDepth) {
+ // Check all functions because the driver may fail on them
+ // TODO: Before detectingRecursion, strip unused functions.
+ for (size_t i = 0; i < functions.size(); ++i) {
+ ErrorCode error = detectCallDepthForFunction(functions[i]);
+ if (error != kErrorNone)
+ return error;
+ }
+ } else {
+ FunctionNode* main = findFunctionByName("main(");
+ if (main == NULL)
+ return kErrorMissingMain;
+
+ return detectCallDepthForFunction(main);
+ }
+
+ return kErrorNone;
+}
+
+DetectCallDepth::FunctionNode* DetectCallDepth::findFunctionByName(
+ const TString& name)
+{
+ for (size_t i = 0; i < functions.size(); ++i) {
+ if (functions[i]->getName() == name)
+ return functions[i];
+ }
+ return NULL;
+}
+