• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
SymbolDataSymbolData33   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 
Symbol(int v)45 Symbol::Symbol(int v) : v_(v) {}
46 
PeekGlobalVar() const47 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 
GetGlobalVar() const54 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 
SetGlobalVar(Var * v,bool is_override,bool * readonly) const66 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 
ScopedGlobalVar(Symbol name,Var * var)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 
~ScopedGlobalVar()102 ScopedGlobalVar::~ScopedGlobalVar() {
103   g_symbol_data[name_.val()].gv = orig_;
104 }
105 
106 class Symtab {
107  public:
Symtab()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 
~Symtab()132   ~Symtab() {
133     LOG_STAT("%zu symbols", symbols_.size());
134     for (string* s : symbols_)
135       delete s;
136   }
137 
InternImpl(StringPiece s)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 
Intern(StringPiece s)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 
InitSymtab()172 void InitSymtab() {
173   g_symtab = new Symtab;
174 }
175 
QuitSymtab()176 void QuitSymtab() {
177   delete g_symtab;
178 }
179 
Intern(StringPiece s)180 Symbol Intern(StringPiece s) {
181   return g_symtab->Intern(s);
182 }
183 
JoinSymbols(const vector<Symbol> & syms,const char * sep)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