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