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()
     34       : gv(kUndefined) {
     35   }
     36 
     37   Var* gv;
     38 };
     39 
     40 vector<string*>* g_symbols;
     41 static vector<SymbolData> g_symbol_data;
     42 
     43 Symbol kEmptySym = Symbol(Symbol::IsUninitialized());
     44 Symbol kShellSym = Symbol(Symbol::IsUninitialized());
     45 
     46 Symbol::Symbol(int v)
     47     : v_(v) {
     48 }
     49 
     50 Var* Symbol::GetGlobalVar() const {
     51   if (static_cast<size_t>(v_) >= g_symbol_data.size()) {
     52     g_symbol_data.resize(v_ + 1);
     53   }
     54   Var* v = g_symbol_data[v_].gv;
     55   if (v->Origin() == VarOrigin::ENVIRONMENT ||
     56       v->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE) {
     57     Vars::add_used_env_vars(*this);
     58   }
     59   return v;
     60 }
     61 
     62 void Symbol::SetGlobalVar(Var* v) const {
     63   if (static_cast<size_t>(v_) >= g_symbol_data.size()) {
     64     g_symbol_data.resize(v_ + 1);
     65   }
     66   Var* orig = g_symbol_data[v_].gv;
     67   if (orig->Origin() == VarOrigin::OVERRIDE ||
     68       orig->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE) {
     69     return;
     70   }
     71   if (orig->Origin() == VarOrigin::AUTOMATIC) {
     72     ERROR("overriding automatic variable is not implemented yet");
     73   }
     74   if (orig->IsDefined())
     75     delete orig;
     76   g_symbol_data[v_].gv = v;
     77 }
     78 
     79 ScopedGlobalVar::ScopedGlobalVar(Symbol name, Var* var)
     80     : name_(name), orig_(NULL) {
     81   orig_ = name.GetGlobalVar();
     82   g_symbol_data[name_.val()].gv = var;
     83 }
     84 
     85 ScopedGlobalVar::~ScopedGlobalVar() {
     86   g_symbol_data[name_.val()].gv = orig_;
     87 }
     88 
     89 class Symtab {
     90  public:
     91   Symtab() {
     92 #ifdef ENABLE_TID_CHECK
     93     tid_ = pthread_self();
     94 #endif
     95 
     96     CHECK(g_symbols == NULL);
     97     g_symbols = &symbols_;
     98 
     99     Symbol s = InternImpl("");
    100     CHECK(s.v_ == 0);
    101     CHECK(Intern("") == s);
    102     char b[2];
    103     b[1] = 0;
    104     for (int i = 1; i < 256; i++) {
    105       b[0] = i;
    106       s = InternImpl(b);
    107       CHECK(s.val() == i);
    108     }
    109 
    110     kEmptySym = Intern("");
    111     kShellSym = Intern("SHELL");
    112   }
    113 
    114   ~Symtab() {
    115     LOG_STAT("%zu symbols", symbols_.size());
    116     for (string* s : symbols_)
    117       delete s;
    118   }
    119 
    120   Symbol InternImpl(StringPiece s) {
    121     auto found = symtab_.find(s);
    122     if (found != symtab_.end()) {
    123       return found->second;
    124     }
    125     symbols_.push_back(new string(s.data(), s.size()));
    126     Symbol sym = Symbol(symtab_.size());
    127     bool ok = symtab_.emplace(*symbols_.back(), sym).second;
    128     CHECK(ok);
    129     return sym;
    130   }
    131 
    132   Symbol Intern(StringPiece s) {
    133 #ifdef ENABLE_TID_CHECK
    134     if (tid_ != pthread_self())
    135       abort();
    136 #endif
    137 
    138     if (s.size() <= 1) {
    139       return Symbol(s.empty() ? 0 : (unsigned char)s[0]);
    140     }
    141     return InternImpl(s);
    142   }
    143 
    144  private:
    145   unordered_map<StringPiece, Symbol> symtab_;
    146   vector<string*> symbols_;
    147 #ifdef ENABLE_TID_CHECK
    148   pthread_t tid_;
    149 #endif
    150 };
    151 
    152 static Symtab* g_symtab;
    153 
    154 void InitSymtab() {
    155   g_symtab = new Symtab;
    156 }
    157 
    158 void QuitSymtab() {
    159   delete g_symtab;
    160 }
    161 
    162 Symbol Intern(StringPiece s) {
    163   return g_symtab->Intern(s);
    164 }
    165 
    166 string JoinSymbols(const vector<Symbol>& syms, const char* sep) {
    167   vector<string> strs;
    168   for (Symbol s : syms) {
    169     strs.push_back(s.str());
    170   }
    171   return JoinStrings(strs, sep);
    172 }
    173