jitcraft/Scopes.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jul 04 19:39:00 2012 -0400 (2012-07-04)
changeset 47 050939c6181e
parent 37 abb03d835b53
child 54 8e22792a3921
permissions -rw-r--r--
Implemented gcmaps and stack frame tracing.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include "Scopes.h"
    20 #include "Zone.h"
    21 #include "Types.h"
    22 #include "TypeManager.h"
    23 
    24 using namespace jc;
    25 
    26 Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
    27   : pool_(pool),
    28     locals_(0),
    29     maxContainedLocals_(0),
    30     numFunctions_(0),
    31     lifoSlot_(NULL),
    32     kind_(kind),
    33     enclosing_(enclosing)
    34 {
    35 }
    36 
    37 bool
    38 Scope::initialize()
    39 {
    40     if (enclosing_)
    41         enclosing_->children_.push_back(this);
    42     return true;
    43 }
    44 
    45 void
    46 Scope::unlink()
    47 {
    48     assert(empty());
    49 
    50     assert(enclosing_->children_[enclosing_->children_.size() - 1] == this);
    51     enclosing_->children_.pop_back();
    52 
    53     for (size_t i = 0; i < children_.size(); i++)
    54         enclosing_->children_.push_back(children_[i]);
    55 }
    56 
    57 Scope *
    58 Scope::unlinkIfEmpty()
    59 {
    60     if (empty()) {
    61         unlink();
    62         return NULL;
    63     }
    64     return this;
    65 }
    66 
    67 BoundName *
    68 Scope::localLookup(Name *name)
    69 {
    70     for (size_t i = 0; i < names_.size(); i++) {
    71         if (names_[i]->name() == name)
    72             return names_[i];
    73     }
    74     return NULL;
    75 }
    76 
    77 BoundName *
    78 Scope::lookup(Name *name)
    79 {
    80     for (Scope *scope = this; scope; scope = scope->enclosing()) {
    81         if (BoundName *bound = scope->localLookup(name))
    82             return bound;
    83     }
    84     return NULL;
    85 }
    86 
    87 Variable *
    88 Scope::declareVariable(Name *name, const SourcePosition &pos)
    89 {
    90     assert(!localLookup(name));
    91     
    92     Variable *var = new (pool_) Variable(this, name, pos);
    93     names_.push_back(var);
    94     return var;
    95 }
    96 
    97 Variable *
    98 Scope::declareArgument(Name *name, const SourcePosition &pos)
    99 {
   100     assert(kind() == FUNCTION);
   101     Variable *var = declareVariable(name, pos);
   102     names_.push_back(var);
   103     parameters_.push_back(var);
   104     return var;
   105 }
   106 
   107 NamedFunction *
   108 Scope::declareFunction(Name *name, const SourcePosition &pos)
   109 {
   110     assert(!localLookup(name));
   111     assert(kind() == GLOBAL);
   112 
   113     NamedFunction *fun = new (pool_) NamedFunction(this, name, pos);
   114     names_.push_back(fun);
   115     return fun;
   116 }
   117 
   118 NamedEnum *
   119 Scope::declareEnum(Name *name, const SourcePosition &pos)
   120 {
   121     NamedEnum *e = new (pool_) NamedEnum(this, name, pos);
   122     names_.push_back(e);
   123     return e;
   124 }
   125 
   126 NamedConstant *
   127 Scope::declareConstant(Name *name, const SourcePosition &pos)
   128 {
   129     NamedConstant *constant = new (pool_) NamedConstant(this, name, pos);
   130     names_.push_back(constant);
   131     return constant;
   132 }
   133 
   134 void
   135 Scope::allocateGlobals()
   136 {
   137     assert(kind() == GLOBAL);
   138 
   139     for (size_t i = 0; i < children_.size(); i++) {
   140         assert(children_[i]->kind() == FUNCTION);
   141         children_[i]->allocate();
   142     }
   143 
   144     for (size_t i = 0; i < names_.size(); i++) {
   145         BoundName *name = names_[i];
   146         
   147         if (name->kind() == BoundName::FUNCTION) {
   148             NamedFunction *fun = name->toNamedFunction();
   149             fun->allocate(numFunctions_++);
   150         }
   151     }
   152 }
   153 
   154 void
   155 Scope::allocate(Variable *var)
   156 {
   157     if (!var->unallocated())
   158         return;
   159 
   160     var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
   161     locals_++;
   162 }
   163 
   164 void
   165 Scope::allocate()
   166 {
   167     maxContainedLocals_ = 0;
   168     for (size_t i = 0; i < children_.size(); i++) {
   169         Scope *scope = children_[i];
   170         scope->allocate();
   171         if (scope->maxContainedLocals() > maxContainedLocals_)
   172             maxContainedLocals_ = scope->maxContainedLocals();
   173     }
   174 
   175     for (size_t i = 0; i < parameters_.size(); i++)
   176         parameters_[i]->allocate(Variable::PARAMETER, i);
   177 
   178     if (lifoSlot_)
   179         allocate(lifoSlot_);
   180     for (size_t i = 0; i < names_.size(); i++) {
   181         if (names_[i]->kind() != BoundName::VARIABLE)
   182             continue;
   183 
   184         allocate(names_[i]->toVariable());
   185     }
   186 
   187     maxContainedLocals_ += locals_;
   188 }
   189 
   190 bool
   191 Scope::Bind(ParseTree *tree)
   192 {
   193     for (size_t i = 0; i < tree->unbound()->size(); i++) {
   194         NameProxy *proxy = tree->unbound()->at(i);
   195         BoundName *name = tree->scope()->lookup(proxy->name());
   196         if (!name) {
   197             assert(false);
   198             return false;
   199         }
   200 
   201         proxy->bind(name);
   202     }
   203     return true;
   204 }
   205 
   206 void
   207 Scope::Allocate(ParseTree *tree)
   208 {
   209     tree->scope()->allocateGlobals();
   210 }
   211 
   212 void
   213 Scope::setUsesLifoHeap()
   214 {
   215     // Only one lifo slot is needed per scope.
   216     if (lifoSlot_)
   217         return;
   218 
   219     // If the parent of this scope is the function scope, then this is the
   220     // function's block scope, and the lifo slot is part of the Frame instead.
   221     // Note we can get a function scope here if we're making a temporary in a
   222     // function with no local variables.
   223     if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
   224         return;
   225 
   226     Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
   227     if (!type)
   228         return;
   229 
   230     lifoSlot_ = new (pool_) Variable(this, NULL, SourcePosition());
   231     lifoSlot_->setType(type);
   232 }