gfx/angle/src/compiler/DetectCallDepth.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/angle/src/compiler/DetectCallDepth.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,185 @@
     1.4 +//
     1.5 +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
     1.6 +// Use of this source code is governed by a BSD-style license that can be
     1.7 +// found in the LICENSE file.
     1.8 +//
     1.9 +
    1.10 +#include "compiler/DetectCallDepth.h"
    1.11 +#include "compiler/InfoSink.h"
    1.12 +
    1.13 +DetectCallDepth::FunctionNode::FunctionNode(const TString& fname)
    1.14 +    : name(fname),
    1.15 +      visit(PreVisit)
    1.16 +{
    1.17 +}
    1.18 +
    1.19 +const TString& DetectCallDepth::FunctionNode::getName() const
    1.20 +{
    1.21 +    return name;
    1.22 +}
    1.23 +
    1.24 +void DetectCallDepth::FunctionNode::addCallee(
    1.25 +    DetectCallDepth::FunctionNode* callee)
    1.26 +{
    1.27 +    for (size_t i = 0; i < callees.size(); ++i) {
    1.28 +        if (callees[i] == callee)
    1.29 +            return;
    1.30 +    }
    1.31 +    callees.push_back(callee);
    1.32 +}
    1.33 +
    1.34 +int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDepth, int depth)
    1.35 +{
    1.36 +    ASSERT(visit == PreVisit);
    1.37 +    ASSERT(detectCallDepth);
    1.38 +
    1.39 +    int maxDepth = depth;
    1.40 +    visit = InVisit;
    1.41 +    for (size_t i = 0; i < callees.size(); ++i) {
    1.42 +        switch (callees[i]->visit) {
    1.43 +            case InVisit:
    1.44 +                // cycle detected, i.e., recursion detected.
    1.45 +                return kInfiniteCallDepth;
    1.46 +            case PostVisit:
    1.47 +                break;
    1.48 +            case PreVisit: {
    1.49 +                // Check before we recurse so we don't go too depth
    1.50 +                if (detectCallDepth->checkExceedsMaxDepth(depth))
    1.51 +                    return depth;
    1.52 +                int callDepth = callees[i]->detectCallDepth(detectCallDepth, depth + 1);
    1.53 +                // Check after we recurse so we can exit immediately and provide info.
    1.54 +                if (detectCallDepth->checkExceedsMaxDepth(callDepth)) {
    1.55 +                    detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName();
    1.56 +                    return callDepth;
    1.57 +                }
    1.58 +                maxDepth = std::max(callDepth, maxDepth);
    1.59 +                break;
    1.60 +            }
    1.61 +            default:
    1.62 +                UNREACHABLE();
    1.63 +                break;
    1.64 +        }
    1.65 +    }
    1.66 +    visit = PostVisit;
    1.67 +    return maxDepth;
    1.68 +}
    1.69 +
    1.70 +void DetectCallDepth::FunctionNode::reset()
    1.71 +{
    1.72 +    visit = PreVisit;
    1.73 +}
    1.74 +
    1.75 +DetectCallDepth::DetectCallDepth(TInfoSink& infoSink, bool limitCallStackDepth, int maxCallStackDepth)
    1.76 +    : TIntermTraverser(true, false, true, false),
    1.77 +      currentFunction(NULL),
    1.78 +      infoSink(infoSink),
    1.79 +      maxDepth(limitCallStackDepth ? maxCallStackDepth : FunctionNode::kInfiniteCallDepth)
    1.80 +{
    1.81 +}
    1.82 +
    1.83 +DetectCallDepth::~DetectCallDepth()
    1.84 +{
    1.85 +    for (size_t i = 0; i < functions.size(); ++i)
    1.86 +        delete functions[i];
    1.87 +}
    1.88 +
    1.89 +bool DetectCallDepth::visitAggregate(Visit visit, TIntermAggregate* node)
    1.90 +{
    1.91 +    switch (node->getOp())
    1.92 +    {
    1.93 +        case EOpPrototype:
    1.94 +            // Function declaration.
    1.95 +            // Don't add FunctionNode here because node->getName() is the
    1.96 +            // unmangled function name.
    1.97 +            break;
    1.98 +        case EOpFunction: {
    1.99 +            // Function definition.
   1.100 +            if (visit == PreVisit) {
   1.101 +                currentFunction = findFunctionByName(node->getName());
   1.102 +                if (currentFunction == NULL) {
   1.103 +                    currentFunction = new FunctionNode(node->getName());
   1.104 +                    functions.push_back(currentFunction);
   1.105 +                }
   1.106 +            } else if (visit == PostVisit) {
   1.107 +                currentFunction = NULL;
   1.108 +            }
   1.109 +            break;
   1.110 +        }
   1.111 +        case EOpFunctionCall: {
   1.112 +            // Function call.
   1.113 +            if (visit == PreVisit) {
   1.114 +                FunctionNode* func = findFunctionByName(node->getName());
   1.115 +                if (func == NULL) {
   1.116 +                    func = new FunctionNode(node->getName());
   1.117 +                    functions.push_back(func);
   1.118 +                }
   1.119 +                if (currentFunction)
   1.120 +                    currentFunction->addCallee(func);
   1.121 +            }
   1.122 +            break;
   1.123 +        }
   1.124 +        default:
   1.125 +            break;
   1.126 +    }
   1.127 +    return true;
   1.128 +}
   1.129 +
   1.130 +bool DetectCallDepth::checkExceedsMaxDepth(int depth)
   1.131 +{
   1.132 +    return depth >= maxDepth;
   1.133 +}
   1.134 +
   1.135 +void DetectCallDepth::resetFunctionNodes()
   1.136 +{
   1.137 +    for (size_t i = 0; i < functions.size(); ++i) {
   1.138 +        functions[i]->reset();
   1.139 +    }
   1.140 +}
   1.141 +
   1.142 +DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepthForFunction(FunctionNode* func)
   1.143 +{
   1.144 +    currentFunction = NULL;
   1.145 +    resetFunctionNodes();
   1.146 +
   1.147 +    int maxCallDepth = func->detectCallDepth(this, 1);
   1.148 +
   1.149 +    if (maxCallDepth == FunctionNode::kInfiniteCallDepth)
   1.150 +        return kErrorRecursion;
   1.151 +
   1.152 +    if (maxCallDepth >= maxDepth)
   1.153 +        return kErrorMaxDepthExceeded;
   1.154 +
   1.155 +    return kErrorNone;
   1.156 +}
   1.157 +
   1.158 +DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepth()
   1.159 +{
   1.160 +    if (maxDepth != FunctionNode::kInfiniteCallDepth) {
   1.161 +        // Check all functions because the driver may fail on them
   1.162 +        // TODO: Before detectingRecursion, strip unused functions.
   1.163 +        for (size_t i = 0; i < functions.size(); ++i) {
   1.164 +            ErrorCode error = detectCallDepthForFunction(functions[i]);
   1.165 +            if (error != kErrorNone)
   1.166 +                return error;
   1.167 +        }
   1.168 +    } else {
   1.169 +        FunctionNode* main = findFunctionByName("main(");
   1.170 +        if (main == NULL)
   1.171 +            return kErrorMissingMain;
   1.172 +
   1.173 +        return detectCallDepthForFunction(main);
   1.174 +    }
   1.175 +
   1.176 +    return kErrorNone;
   1.177 +}
   1.178 +
   1.179 +DetectCallDepth::FunctionNode* DetectCallDepth::findFunctionByName(
   1.180 +    const TString& name)
   1.181 +{
   1.182 +    for (size_t i = 0; i < functions.size(); ++i) {
   1.183 +        if (functions[i]->getName() == name)
   1.184 +            return functions[i];
   1.185 +    }
   1.186 +    return NULL;
   1.187 +}
   1.188 +

mercurial