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, bool is_override, bool* readonly) 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->ReadOnly()) {
     68     if (readonly != nullptr)
     69       *readonly = true;
     70     else
     71       ERROR("*** cannot assign to readonly variable: %s", c_str());
     72     return;
     73   } else if (readonly != nullptr) {
     74     *readonly = false;
     75   }
     76   if (!is_override &&
     77       (orig->Origin() == VarOrigin::OVERRIDE ||
     78        orig->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE)) {
     79     return;
     80   }
     81   if (orig->Origin() == VarOrigin::COMMAND_LINE &&
     82          v->Origin() == VarOrigin::FILE) {
     83     return;
     84   }
     85   if (orig->Origin() == VarOrigin::AUTOMATIC) {
     86     ERROR("overriding automatic variable is not implemented yet");
     87   }
     88   if (orig->IsDefined())
     89     delete orig;
     90   g_symbol_data[v_].gv = v;
     91 }
     92 
     93 ScopedGlobalVar::ScopedGlobalVar(Symbol name, Var* var)
     94     : name_(name), orig_(NULL) {
     95   orig_ = name.GetGlobalVar();
     96   g_symbol_data[name_.val()].gv = var;
     97 }
     98 
     99 ScopedGlobalVar::~ScopedGlobalVar() {
    100   g_symbol_data[name_.val()].gv = orig_;
    101 }
    102 
    103 class Symtab {
    104  public:
    105   Symtab() {
    106 #ifdef ENABLE_TID_CHECK
    107     tid_ = pthread_self();
    108 #endif
    109 
    110     CHECK(g_symbols == NULL);
    111     g_symbols = &symbols_;
    112 
    113     Symbol s = InternImpl("");
    114     CHECK(s.v_ == 0);
    115     CHECK(Intern("") == s);
    116     char b[2];
    117     b[1] = 0;
    118     for (int i = 1; i < 256; i++) {
    119       b[0] = i;
    120       s = InternImpl(b);
    121       CHECK(s.val() == i);
    122     }
    123 
    124     kEmptySym = Intern("");
    125     kShellSym = Intern("SHELL");
    126   }
    127 
    128   ~Symtab() {
    129     LOG_STAT("%zu symbols", symbols_.size());
    130     for (string* s : symbols_)
    131       delete s;
    132   }
    133 
    134   Symbol InternImpl(StringPiece s) {
    135     auto found = symtab_.find(s);
    136     if (found != symtab_.end()) {
    137       return found->second;
    138     }
    139     symbols_.push_back(new string(s.data(), s.size()));
    140     Symbol sym = Symbol(symtab_.size());
    141     bool ok = symtab_.emplace(*symbols_.back(), sym).second;
    142     CHECK(ok);
    143     return sym;
    144   }
    145 
    146   Symbol Intern(StringPiece s) {
    147 #ifdef ENABLE_TID_CHECK
    148     if (tid_ != pthread_self())
    149       abort();
    150 #endif
    151 
    152     if (s.size() <= 1) {
    153       return Symbol(s.empty() ? 0 : (unsigned char)s[0]);
    154     }
    155     return InternImpl(s);
    156   }
    157 
    158  private:
    159   unordered_map<StringPiece, Symbol> symtab_;
    160   vector<string*> symbols_;
    161 #ifdef ENABLE_TID_CHECK
    162   pthread_t tid_;
    163 #endif
    164 };
    165 
    166 static Symtab* g_symtab;
    167 
    168 void InitSymtab() {
    169   g_symtab = new Symtab;
    170 }
    171 
    172 void QuitSymtab() {
    173   delete g_symtab;
    174 }
    175 
    176 Symbol Intern(StringPiece s) {
    177   return g_symtab->Intern(s);
    178 }
    179 
    180 string JoinSymbols(const vector<Symbol>& syms, const char* sep) {
    181   vector<string> strs;
    182   for (Symbol s : syms) {
    183     strs.push_back(s.str());
    184   }
    185   return JoinStrings(strs, sep);
    186 }
    187