dvander@0: /* dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@0: * This file is part of JITCraft. dvander@0: * dvander@0: * JITCraft is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@0: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@0: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@0: #include "Scopes.h" dvander@12: #include "Zone.h" dvander@1: #include "Types.h" dvander@12: #include "TypeManager.h" dvander@0: dvander@0: using namespace jc; dvander@0: dvander@0: Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing) dvander@0: : pool_(pool), dvander@0: locals_(0), dvander@0: maxContainedLocals_(0), dvander@12: numFunctions_(0), dvander@28: lifoSlot_(NULL), dvander@28: kind_(kind), dvander@28: enclosing_(enclosing) dvander@0: { dvander@0: } dvander@0: dvander@0: bool dvander@0: Scope::initialize() dvander@0: { dvander@0: if (enclosing_) dvander@0: enclosing_->children_.push_back(this); dvander@0: return true; dvander@0: } dvander@0: dvander@0: void dvander@0: Scope::unlink() dvander@0: { dvander@0: assert(empty()); dvander@0: dvander@0: assert(enclosing_->children_[enclosing_->children_.size() - 1] == this); dvander@0: enclosing_->children_.pop_back(); dvander@0: dvander@0: for (size_t i = 0; i < children_.size(); i++) dvander@0: enclosing_->children_.push_back(children_[i]); dvander@0: } dvander@0: dvander@0: Scope * dvander@0: Scope::unlinkIfEmpty() dvander@0: { dvander@0: if (empty()) { dvander@0: unlink(); dvander@0: return NULL; dvander@0: } dvander@0: return this; dvander@0: } dvander@0: dvander@0: BoundName * dvander@0: Scope::localLookup(Name *name) dvander@0: { dvander@0: for (size_t i = 0; i < names_.size(); i++) { dvander@0: if (names_[i]->name() == name) dvander@0: return names_[i]; dvander@0: } dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: BoundName * dvander@0: Scope::lookup(Name *name) dvander@0: { dvander@0: for (Scope *scope = this; scope; scope = scope->enclosing()) { dvander@0: if (BoundName *bound = scope->localLookup(name)) dvander@0: return bound; dvander@0: } dvander@0: return NULL; dvander@0: } dvander@0: dvander@0: Variable * dvander@25: Scope::declareVariable(Name *name, const SourcePosition &pos) dvander@0: { dvander@0: assert(!localLookup(name)); dvander@0: dvander@25: Variable *var = new (pool_) Variable(this, name, pos); dvander@0: names_.push_back(var); dvander@0: return var; dvander@0: } dvander@0: dvander@0: Variable * dvander@25: Scope::declareArgument(Name *name, const SourcePosition &pos) dvander@0: { dvander@0: assert(kind() == FUNCTION); dvander@25: Variable *var = declareVariable(name, pos); dvander@0: names_.push_back(var); dvander@0: parameters_.push_back(var); dvander@0: return var; dvander@0: } dvander@0: dvander@0: NamedFunction * dvander@25: Scope::declareFunction(Name *name, const SourcePosition &pos) dvander@0: { dvander@0: assert(!localLookup(name)); dvander@2: assert(kind() == GLOBAL); dvander@0: dvander@25: NamedFunction *fun = new (pool_) NamedFunction(this, name, pos); dvander@0: names_.push_back(fun); dvander@0: return fun; dvander@0: } dvander@0: dvander@2: NamedEnum * dvander@25: Scope::declareEnum(Name *name, const SourcePosition &pos) dvander@2: { dvander@25: NamedEnum *e = new (pool_) NamedEnum(this, name, pos); dvander@2: names_.push_back(e); dvander@2: return e; dvander@2: } dvander@2: dvander@2: NamedConstant * dvander@25: Scope::declareConstant(Name *name, const SourcePosition &pos) dvander@2: { dvander@25: NamedConstant *constant = new (pool_) NamedConstant(this, name, pos); dvander@2: names_.push_back(constant); dvander@2: return constant; dvander@2: } dvander@2: dvander@0: void dvander@0: Scope::allocateGlobals() dvander@0: { dvander@0: assert(kind() == GLOBAL); dvander@0: dvander@0: for (size_t i = 0; i < children_.size(); i++) { dvander@0: assert(children_[i]->kind() == FUNCTION); dvander@0: children_[i]->allocate(); dvander@0: } dvander@0: dvander@0: for (size_t i = 0; i < names_.size(); i++) { dvander@0: BoundName *name = names_[i]; dvander@0: dvander@28: if (name->kind() == BoundName::FUNCTION) { dvander@2: NamedFunction *fun = name->toNamedFunction(); dvander@2: fun->allocate(numFunctions_++); dvander@2: } dvander@0: } dvander@0: } dvander@0: dvander@0: void dvander@12: Scope::allocate(Variable *var) dvander@12: { dvander@12: if (!var->unallocated()) dvander@12: return; dvander@12: dvander@12: var->allocate(Variable::STACK, maxContainedLocals_ + locals_); dvander@12: locals_++; dvander@12: } dvander@12: dvander@12: void dvander@0: Scope::allocate() dvander@0: { dvander@0: maxContainedLocals_ = 0; dvander@0: for (size_t i = 0; i < children_.size(); i++) { dvander@0: Scope *scope = children_[i]; dvander@0: scope->allocate(); dvander@0: if (scope->maxContainedLocals() > maxContainedLocals_) dvander@0: maxContainedLocals_ = scope->maxContainedLocals(); dvander@0: } dvander@0: dvander@0: for (size_t i = 0; i < parameters_.size(); i++) dvander@0: parameters_[i]->allocate(Variable::PARAMETER, i); dvander@0: dvander@12: if (lifoSlot_) dvander@12: allocate(lifoSlot_); dvander@0: for (size_t i = 0; i < names_.size(); i++) { dvander@2: if (names_[i]->kind() != BoundName::VARIABLE) dvander@2: continue; dvander@0: dvander@12: allocate(names_[i]->toVariable()); dvander@0: } dvander@0: dvander@0: maxContainedLocals_ += locals_; dvander@0: } dvander@0: dvander@0: bool dvander@12: Scope::Bind(ParseTree *tree) dvander@0: { dvander@0: for (size_t i = 0; i < tree->unbound()->size(); i++) { dvander@0: NameProxy *proxy = tree->unbound()->at(i); dvander@0: BoundName *name = tree->scope()->lookup(proxy->name()); dvander@2: if (!name) { dvander@2: assert(false); dvander@0: return false; dvander@2: } dvander@0: dvander@0: proxy->bind(name); dvander@0: } dvander@0: return true; dvander@0: } dvander@1: dvander@12: void dvander@12: Scope::Allocate(ParseTree *tree) dvander@12: { dvander@12: tree->scope()->allocateGlobals(); dvander@12: } dvander@12: dvander@12: void dvander@12: Scope::setUsesLifoHeap() dvander@1: { dvander@12: // Only one lifo slot is needed per scope. dvander@12: if (lifoSlot_) dvander@12: return; dvander@12: dvander@12: // If the parent of this scope is the function scope, then this is the dvander@12: // function's block scope, and the lifo slot is part of the Frame instead. dvander@16: // Note we can get a function scope here if we're making a temporary in a dvander@16: // function with no local variables. dvander@16: if (kind() == FUNCTION || enclosing()->kind() == FUNCTION) dvander@12: return; dvander@12: dvander@25: lifoSlot_ = new (pool_) Variable(this, NULL, SourcePosition()); dvander@12: lifoSlot_->setType(ZONE()->types()->getPrimitive(PrimitiveType_Native)); dvander@1: }