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(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 
Symbol(int v)44 Symbol::Symbol(int v) : v_(v) {}
45 
PeekGlobalVar() const46 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 
GetGlobalVar() const53 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 
SetGlobalVar(Var * v,bool is_override,bool * readonly) const65 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 
ScopedGlobalVar(Symbol name,Var * var)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 
~ScopedGlobalVar()101 ScopedGlobalVar::~ScopedGlobalVar() {
102   g_symbol_data[name_.val()].gv = orig_;
103 }
104 
105 class Symtab {
106  public:
Symtab()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 
~Symtab()130   ~Symtab() {
131     LOG_STAT("%zu symbols", symbols_.size());
132     for (string* s : symbols_)
133       delete s;
134   }
135 
InternImpl(StringPiece s)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 
Intern(StringPiece s)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 
InitSymtab()170 void InitSymtab() {
171   g_symtab = new Symtab;
172 }
173 
QuitSymtab()174 void QuitSymtab() {
175   delete g_symtab;
176 }
177 
Intern(StringPiece s)178 Symbol Intern(StringPiece s) {
179   return g_symtab->Intern(s);
180 }
181 
JoinSymbols(const vector<Symbol> & syms,const char * sep)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