Allow unused functions to be semantically checked, but do not bytecode compile them.
Allow unused functions to be semantically checked, but do not bytecode compile them.
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 }