Allow unused functions to be semantically checked, but do not bytecode compile them.
authorDavid Anderson <dvander@alliedmods.net>
Mon Jul 30 00:03:46 2012 -0700 (2012-07-30)
changeset 137be919b22085b
parent 136 7b32fc1bf153
child 138 85196d4d4181
Allow unused functions to be semantically checked, but do not bytecode compile them.
src/BytecodeCompiler.cpp
src/NameBinding.cpp
src/NameBinding.h
src/Parser.cpp
src/Scopes.cpp
src/SemanticAnalysis.cpp
src/SemanticAnalysis.h
src/Vector.h
     1.1 --- a/src/BytecodeCompiler.cpp	Sun Jul 29 19:47:31 2012 -0700
     1.2 +++ b/src/BytecodeCompiler.cpp	Mon Jul 30 00:03:46 2012 -0700
     1.3 @@ -869,6 +869,9 @@
     1.4  void
     1.5  BytecodeCompiler::visit(FunctionStatement *node)
     1.6  {
     1.7 +    if (!node->fun()->used())
     1.8 +        return;
     1.9 +
    1.10      if (node->fun()->isNative()) {
    1.11          assert(!moduleData_->natives->at(node->fun()->slot()));
    1.12  
     2.1 --- a/src/NameBinding.cpp	Sun Jul 29 19:47:31 2012 -0700
     2.2 +++ b/src/NameBinding.cpp	Mon Jul 30 00:03:46 2012 -0700
     2.3 @@ -1,19 +1,20 @@
     2.4 -/*
     2.5 +/* vim: set ts=4 sw=4 tw=99 et:
     2.6 + *
     2.7   * Copyright (C) 2012 David Anderson
     2.8   *
     2.9 - * This file is part of JITCraft.
    2.10 + * This file is part of SourcePawn.
    2.11   *
    2.12 - * JITCraft is free software: you can redistribute it and/or modify it under
    2.13 + * SourcePawn is free software: you can redistribute it and/or modify it under
    2.14   * the terms of the GNU General Public License as published by the Free
    2.15   * Software Foundation, either version 3 of the License, or (at your option)
    2.16   * any later version.
    2.17   * 
    2.18 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    2.19 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    2.20   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    2.21   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    2.22   *
    2.23   * You should have received a copy of the GNU General Public License along with
    2.24 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    2.25 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    2.26   */
    2.27  #include "NameBinding.h"
    2.28  #include "Strings.h"
    2.29 @@ -28,6 +29,7 @@
    2.30    : scope_(scope),
    2.31      name_(name),
    2.32      type_(NULL),
    2.33 +    used_(false),
    2.34      pos_(pos)
    2.35  {
    2.36  }
     3.1 --- a/src/NameBinding.h	Sun Jul 29 19:47:31 2012 -0700
     3.2 +++ b/src/NameBinding.h	Mon Jul 30 00:03:46 2012 -0700
     3.3 @@ -1,19 +1,20 @@
     3.4 -/*
     3.5 +/* vim: set ts=4 sw=4 tw=99 et:
     3.6 + *
     3.7   * Copyright (C) 2012 David Anderson
     3.8   *
     3.9 - * This file is part of JITCraft.
    3.10 + * This file is part of SourcePawn.
    3.11   *
    3.12 - * JITCraft is free software: you can redistribute it and/or modify it under
    3.13 + * SourcePawn is free software: you can redistribute it and/or modify it under
    3.14   * the terms of the GNU General Public License as published by the Free
    3.15   * Software Foundation, either version 3 of the License, or (at your option)
    3.16   * any later version.
    3.17   * 
    3.18 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    3.19 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    3.20   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.21   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    3.22   *
    3.23   * You should have received a copy of the GNU General Public License along with
    3.24 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    3.25 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    3.26   */
    3.27  #ifndef _include_name_binding_h_
    3.28  #define _include_name_binding_h_
    3.29 @@ -37,6 +38,7 @@
    3.30      Scope *scope_;
    3.31      ScopedRoot<String> name_;
    3.32      ScopedRoot<Type> type_;
    3.33 +    bool used_;
    3.34  
    3.35    protected:
    3.36      SourcePosition pos_;
    3.37 @@ -77,6 +79,12 @@
    3.38      void setType(Handle<Type> type) {
    3.39          type_ = type;
    3.40      }
    3.41 +    void setUsed() {
    3.42 +        used_ = true;
    3.43 +    }
    3.44 +    bool used() const {
    3.45 +        return used_;
    3.46 +    }
    3.47      const SourcePosition &pos() {
    3.48          return pos_;
    3.49      }
    3.50 @@ -88,6 +96,7 @@
    3.51      TokenKind token_;
    3.52      ScopedRoot<Type> forwardType_;
    3.53      bool isVariadicNative_;
    3.54 +    Vector<BoundName *, PoolAllocationPolicy> globals_;
    3.55  
    3.56    public:
    3.57      NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos, TokenKind token);
    3.58 @@ -128,6 +137,12 @@
    3.59      unsigned slot() const {
    3.60          return slot_;
    3.61      }
    3.62 +    bool addUsedGlobal(BoundName *name) {
    3.63 +        return globals_.append(name);
    3.64 +    }
    3.65 +    Vector<BoundName *, PoolAllocationPolicy> *usedGlobals() {
    3.66 +        return &globals_;
    3.67 +    }
    3.68  };
    3.69  
    3.70  class NamedEnum : public BoundName
     4.1 --- a/src/Parser.cpp	Sun Jul 29 19:47:31 2012 -0700
     4.2 +++ b/src/Parser.cpp	Mon Jul 30 00:03:46 2012 -0700
     4.3 @@ -959,6 +959,9 @@
     4.4              return NULL;
     4.5      }
     4.6  
     4.7 +    if (fun->isPublic())
     4.8 +        fun->setUsed();
     4.9 +
    4.10      Scope *scope = enterScope(Scope::FUNCTION);
    4.11      if (!scope)
    4.12          return NULL;
     5.1 --- a/src/Scopes.cpp	Sun Jul 29 19:47:31 2012 -0700
     5.2 +++ b/src/Scopes.cpp	Mon Jul 30 00:03:46 2012 -0700
     5.3 @@ -158,9 +158,12 @@
     5.4      Local<Type> type(ZONE());
     5.5      for (size_t i = 0; i < names_.length(); i++) {
     5.6          BoundName *name = names_[i];
     5.7 -        
     5.8 +
     5.9          if (name->kind() == BoundName::FUNCTION) {
    5.10              NamedFunction *fun = name->toNamedFunction();
    5.11 +            if (!fun->used())
    5.12 +                continue;
    5.13 +
    5.14              if (fun->isNative())
    5.15                  fun->allocate(numNatives_++);
    5.16              else
    5.17 @@ -235,6 +238,8 @@
    5.18          }
    5.19  
    5.20          proxy->bind(binding);
    5.21 +
    5.22 +        // Find the function the proxy is defined in.
    5.23      }
    5.24      return true;
    5.25  }
     6.1 --- a/src/SemanticAnalysis.cpp	Sun Jul 29 19:47:31 2012 -0700
     6.2 +++ b/src/SemanticAnalysis.cpp	Mon Jul 30 00:03:46 2012 -0700
     6.3 @@ -129,9 +129,61 @@
     6.4          statement->accept(this);
     6.5      }
     6.6  
     6.7 +    if (!determineLiveFunctions())
     6.8 +        return false;
     6.9 +
    6.10      return !cc_.failures();
    6.11  }
    6.12  
    6.13 +bool
    6.14 +SemanticAnalysis::determineLiveFunctions()
    6.15 +{
    6.16 +    Vector<NamedFunction *> worklist;
    6.17 +
    6.18 +    // Add the root set.
    6.19 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
    6.20 +        Statement *statement = tree_->statements()->at(i);
    6.21 +        if (!statement->isFunctionStatement())
    6.22 +            continue;
    6.23 +
    6.24 +        FunctionStatement *stmt = statement->toFunctionStatement();
    6.25 +        NamedFunction  *fun = stmt->fun();
    6.26 +        if (!fun->used())
    6.27 +            continue;
    6.28 +
    6.29 +        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
    6.30 +            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
    6.31 +
    6.32 +            // Names in these lists are always unused, however, we mark them
    6.33 +            // as used while inserting into the work queue, to avoid double-
    6.34 +            // insertion.
    6.35 +            if (name->used())
    6.36 +                continue;
    6.37 +
    6.38 +            if (!worklist.append(name))
    6.39 +                return false;
    6.40 +
    6.41 +            name->setUsed();
    6.42 +        }
    6.43 +    }
    6.44 +
    6.45 +    while (!worklist.empty()) {
    6.46 +        NamedFunction *fun = worklist.popCopy();
    6.47 +
    6.48 +        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
    6.49 +            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
    6.50 +            if (name->used())
    6.51 +                continue;
    6.52 +            if (!worklist.append(name))
    6.53 +                return false;
    6.54 +            name->setUsed();
    6.55 +        }
    6.56 +    }
    6.57 +
    6.58 +    return true;
    6.59 +}
    6.60 +
    6.61 +
    6.62  Type *
    6.63  SemanticAnalysis::visitAndApplyType(Expression *expression)
    6.64  {
    6.65 @@ -301,7 +353,27 @@
    6.66  void
    6.67  SemanticAnalysis::visit(NameProxy *name)
    6.68  {
    6.69 -    name->setType(name->binding()->type());
    6.70 +    BoundName *binding = name->binding();
    6.71 +
    6.72 +    if (binding->scope()->kind() == Scope::GLOBAL) {
    6.73 +        if (!function_ || function_->isPublic()) {
    6.74 +            // Whatever we're referencing must be kept alive no matter what.
    6.75 +            // As such, we simply mark it used, and don't do anything special.
    6.76 +            binding->setUsed();
    6.77 +        } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
    6.78 +            // Otherwise, we're inside a normal stock or function. Since we
    6.79 +            // don't really know if we've been used yet, we shouldn't
    6.80 +            // prematurely references as alive. Instead, we keep a list of
    6.81 +            // which names have been used, so we can mark them later if needed.
    6.82 +            //
    6.83 +            // Note that we skip this step if the binding is already in the
    6.84 +            // root set.
    6.85 +            if (!function_->addUsedGlobal(binding))
    6.86 +                return;
    6.87 +        }
    6.88 +    }
    6.89 +
    6.90 +    name->setType(binding->type());
    6.91  }
    6.92  
    6.93  void
    6.94 @@ -423,7 +495,7 @@
    6.95      control_->returns(Returns_Always);
    6.96  
    6.97      if (!node->expression()) {
    6.98 -        if (!function_->returnType()->isVoid())
    6.99 +        if (!function_->type()->returnType()->isVoid())
   6.100              cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
   6.101          return;
   6.102      }
   6.103 @@ -432,7 +504,7 @@
   6.104      if (!type)
   6.105          return;
   6.106  
   6.107 -    Local<Type> returnType(zone_, function_->returnType());
   6.108 +    Local<Type> returnType(zone_, function_->type()->returnType());
   6.109      if (!typeCheckAssignment(node, type, returnType, true))
   6.110          return;
   6.111  }
   6.112 @@ -755,7 +827,7 @@
   6.113  void
   6.114  SemanticAnalysis::visit(FunctionStatement *node)
   6.115  {
   6.116 -    function_ = node->fun()->type();
   6.117 +    function_ = node->fun();
   6.118      scope_ = node->scope();
   6.119  
   6.120      ControlScope control(&control_);
   6.121 @@ -766,7 +838,7 @@
   6.122          if (status.returns() == Returns_Sometimes) {
   6.123              cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
   6.124          } else if (status.returns() == Returns_Never) {
   6.125 -            if (!function_->returnType()->isVoid())
   6.126 +            if (!function_->type()->returnType()->isVoid())
   6.127                  cc_.reportError(node->pos(), Message_MissingReturnValue);
   6.128          }
   6.129      }
     7.1 --- a/src/SemanticAnalysis.h	Sun Jul 29 19:47:31 2012 -0700
     7.2 +++ b/src/SemanticAnalysis.h	Mon Jul 30 00:03:46 2012 -0700
     7.3 @@ -30,7 +30,7 @@
     7.4      CompileContext &cc_;
     7.5      ParseTree *tree_;
     7.6      Scope *scope_;
     7.7 -    ScopedRoot<Type> function_;
     7.8 +    NamedFunction *function_;
     7.9  
    7.10      enum ReturnStatus
    7.11      {
    7.12 @@ -170,6 +170,8 @@
    7.13  
    7.14      void markCallResultUsed(CallExpression *call);
    7.15  
    7.16 +    bool determineLiveFunctions();
    7.17 +
    7.18    public:
    7.19      SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
    7.20      bool analyze();
     8.1 --- a/src/Vector.h	Sun Jul 29 19:47:31 2012 -0700
     8.2 +++ b/src/Vector.h	Mon Jul 30 00:03:46 2012 -0700
     8.3 @@ -47,11 +47,19 @@
     8.4          nitems++;
     8.5          return true;
     8.6      }
     8.7 +    T popCopy() {
     8.8 +        T t = at(length() - 1);
     8.9 +        pop();
    8.10 +        return t;
    8.11 +    }
    8.12      void pop() {
    8.13          assert(nitems);
    8.14          data[nitems - 1].~T();
    8.15          nitems--;
    8.16      }
    8.17 +    bool empty() const {
    8.18 +        return length() == 0;
    8.19 +    }
    8.20      size_t length() const {
    8.21          return nitems;
    8.22      }