Home | History | Annotate | Download | only in kati
      1 // Copyright 2015 Google Inc. All rights reserved
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // +build ignore
     16 
     17 //#define ENABLE_TID_CHECK
     18 
     19 #include "symtab.h"
     20 
     21 #ifdef ENABLE_TID_CHECK
     22 #include <pthread.h>
     23 #endif
     24 #include <string.h>
     25 
     26 #include <unordered_map>
     27 
     28 #include "log.h"
     29 #include "strutil.h"
     30 #include "var.h"
     31 
     32 struct SymbolData {
     33   SymbolData() : gv(Var::Undefined()) {}
     34 
     35   Var* gv;
     36 };
     37 
     38 vector<string*>* g_symbols;
     39 static vector<SymbolData> g_symbol_data;
     40 
     41 Symbol kEmptySym;
     42 Symbol kShellSym;
     43 Symbol kKatiReadonlySym;
     44 
     45 Symbol::Symbol(int v) : v_(v) {}
     46 
     47 Var* Symbol::PeekGlobalVar() const {
     48   if (static_cast<size_t>(v_) >= g_symbol_data.size()) {
     49     return Var::Undefined();
     50   }
     51   return g_symbol_data[v_].gv;
     52 }
     53 
     54 Var* Symbol::GetGlobalVar() const {
     55   if (static_cast<size_t>(v_) >= g_symbol_data.size()) {
     56     g_symbol_data.resize(v_ + 1);
     57   }
     58   Var* v = g_symbol_data[v_].gv;
     59   if (v->Origin() == VarOrigin::ENVIRONMENT ||
     60       v->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE) {
     61     Vars::add_used_env_vars(*this);
     62   }
     63   return v;
     64 }
     65 
     66 void Symbol::SetGlobalVar(Var* v, bool is_override, bool* readonly) const {
     67   if (static_cast<size_t>(v_) >= g_symbol_data.size()) {
     68     g_symbol_data.resize(v_ + 1);
     69   }
     70   Var* orig = g_symbol_data[v_].gv;
     71   if (orig->ReadOnly()) {
     72     if (readonly != nullptr)
     73       *readonly = true;
     74     else
     75       ERROR("*** cannot assign to readonly variable: %s", c_str());
     76     return;
     77   } else if (readonly != nullptr) {
     78     *readonly = false;
     79   }
     80   if (!is_override && (orig->Origin() == VarOrigin::OVERRIDE ||
     81                        orig->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE)) {
     82     return;
     83   }
     84   if (orig->Origin() == VarOrigin::COMMAND_LINE &&
     85       v->Origin() == VarOrigin::FILE) {
     86     return;
     87   }
     88   if (orig->Origin() == VarOrigin::AUTOMATIC) {
     89     ERROR("overriding automatic variable is not implemented yet");
     90   }
     91   if (orig->IsDefined())
     92     delete orig;
     93   g_symbol_data[v_].gv = v;
     94 }
     95 
     96 ScopedGlobalVar::ScopedGlobalVar(Symbol name, Var* var)
     97     : name_(name), orig_(NULL) {
     98   orig_ = name.GetGlobalVar();
     99   g_symbol_data[name_.val()].gv = var;
    100 }
    101 
    102 ScopedGlobalVar::~ScopedGlobalVar() {
    103   g_symbol_data[name_.val()].gv = orig_;
    104 }
    105 
    106 class Symtab {
    107  public:
    108   Symtab() {
    109 #ifdef ENABLE_TID_CHECK
    110     tid_ = pthread_self();
    111 #endif
    112 
    113     CHECK(g_symbols == NULL);
    114     g_symbols = &symbols_;
    115 
    116     Symbol s = InternImpl("");
    117     CHECK(s.v_ == 0);
    118     CHECK(Intern("") == s);
    119     char b[2];
    120     b[1] = 0;
    121     for (int i = 1; i < 256; i++) {
    122       b[0] = i;
    123       s = InternImpl(b);
    124       CHECK(s.val() == i);
    125     }
    126 
    127     kEmptySym = Intern("");
    128     kShellSym = Intern("SHELL");
    129     kKatiReadonlySym = Intern(".KATI_READONLY");
    130   }
    131 
    132   ~Symtab() {
    133     LOG_STAT("%zu symbols", symbols_.size());
    134     for (string* s : symbols_)
    135       delete s;
    136   }
    137 
    138   Symbol InternImpl(StringPiece s) {
    139     auto found = symtab_.find(s);
    140     if (found != symtab_.end()) {
    141       return found->second;
    142     }
    143     symbols_.push_back(new string(s.data(), s.size()));
    144     Symbol sym = Symbol(symtab_.size());
    145     bool ok = symtab_.emplace(*symbols_.back(), sym).second;
    146     CHECK(ok);
    147     return sym;
    148   }
    149 
    150   Symbol Intern(StringPiece s) {
    151 #ifdef ENABLE_TID_CHECK
    152     if (tid_ != pthread_self())
    153       abort();
    154 #endif
    155 
    156     if (s.size() <= 1) {
    157       return Symbol(s.empty() ? 0 : (unsigned char)s[0]);
    158     }
    159     return InternImpl(s);
    160   }
    161 
    162  private:
    163   unordered_map<StringPiece, Symbol> symtab_;
    164   vector<string*> symbols_;
    165 #ifdef ENABLE_TID_CHECK
    166   pthread_t tid_;
    167 #endif
    168 };
    169 
    170 static Symtab* g_symtab;
    171 
    172 void InitSymtab() {
    173   g_symtab = new Symtab;
    174 }
    175 
    176 void QuitSymtab() {
    177   delete g_symtab;
    178 }
    179 
    180 Symbol Intern(StringPiece s) {
    181   return g_symtab->Intern(s);
    182 }
    183 
    184 string JoinSymbols(const vector<Symbol>& syms, const char* sep) {
    185   vector<string> strs;
    186   for (Symbol s : syms) {
    187     strs.push_back(s.str());
    188   }
    189   return JoinStrings(strs, sep);
    190 }
    191