[C++] Associate global variables with Symbols directly
diff --git a/command.cc b/command.cc
index ac7fadd..f75a8a0 100644
--- a/command.cc
+++ b/command.cc
@@ -171,12 +171,11 @@
 
 CommandEvaluator::CommandEvaluator(Evaluator* ev)
     : ev_(ev) {
-  Vars* vars = ev_->mutable_vars();
 #define INSERT_AUTO_VAR(name, sym) do {                                 \
     Var* v = new name(this, sym);                                       \
-    (*vars)[Intern(sym)] = v;                                           \
-    (*vars)[Intern(sym"D")] = new AutoSuffixDVar(this, sym"D", v);      \
-    (*vars)[Intern(sym"F")] = new AutoSuffixFVar(this, sym"F", v);      \
+    Intern(sym).SetGlobalVar(v);                                        \
+    Intern(sym"D").SetGlobalVar(new AutoSuffixDVar(this, sym"D", v));   \
+    Intern(sym"F").SetGlobalVar(new AutoSuffixFVar(this, sym"F", v));   \
   } while (0)
   INSERT_AUTO_VAR(AutoAtVar, "@");
   INSERT_AUTO_VAR(AutoLessVar, "<");
diff --git a/dep.cc b/dep.cc
index 57b322c..da209c7 100644
--- a/dep.cc
+++ b/dep.cc
@@ -244,7 +244,8 @@
         depfile_var_name_(Intern(".KATI_DEPFILE")) {
     ScopedTimeReporter tr("make dep (populate)");
     PopulateRules(rules);
-    LOG_STAT("%zu variables", ev->mutable_vars()->size());
+    // TODO?
+    //LOG_STAT("%zu variables", ev->mutable_vars()->size());
     LOG_STAT("%zu explicit rules", rules_.size());
     LOG_STAT("%zu implicit rules", implicit_rules_->size());
     LOG_STAT("%zu suffix rules", suffix_rules_.size());
diff --git a/eval.cc b/eval.cc
index be4bb34..6322fc1 100644
--- a/eval.cc
+++ b/eval.cc
@@ -30,9 +30,8 @@
 #include "symtab.h"
 #include "var.h"
 
-Evaluator::Evaluator(const Vars* vars)
-    : vars_(new Vars(*vars)),
-      last_rule_(NULL),
+Evaluator::Evaluator()
+    : last_rule_(NULL),
       current_scope_(NULL),
       avoid_io_(false),
       eval_depth_(0) {
@@ -102,7 +101,7 @@
   Var* rhs = EvalRHS(lhs, stmt->rhs, stmt->orig_rhs, stmt->op,
                      stmt->directive == AssignDirective::OVERRIDE);
   if (rhs)
-    vars_->Assign(lhs, rhs);
+    lhs.SetGlobalVar(rhs);
 }
 
 void Evaluator::EvalRule(const RuleStmt* stmt) {
@@ -284,7 +283,7 @@
 }
 
 Var* Evaluator::LookupVarGlobal(Symbol name) {
-  Var* v = vars_->Lookup(name);
+  Var* v = name.GetGlobalVar();
   if (v->IsDefined())
     return v;
   used_undefined_vars_.insert(name);
diff --git a/eval.h b/eval.h
index cb03d5d..3eede2b 100644
--- a/eval.h
+++ b/eval.h
@@ -33,7 +33,7 @@
 
 class Evaluator {
  public:
-  Evaluator(const Vars* vars);
+  Evaluator();
   ~Evaluator();
 
   void EvalAssign(const AssignStmt* stmt);
@@ -56,7 +56,6 @@
   const unordered_map<Symbol, Vars*>& rule_vars() const {
     return rule_vars_;
   }
-  Vars* mutable_vars() { return vars_; }
   const unordered_map<Symbol, bool>& exports() const { return exports_; }
 
   void Error(const string& msg);
@@ -97,7 +96,6 @@
 
   Var* LookupVarGlobal(Symbol name);
 
-  Vars* vars_;
   unordered_map<Symbol, Vars*> rule_vars_;
   vector<const Rule*> rules_;
   unordered_map<Symbol, bool> exports_;
diff --git a/func.cc b/func.cc
index 2ea8afa..876b274 100644
--- a/func.cc
+++ b/func.cc
@@ -595,7 +595,7 @@
         new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
     av.push_back(move(s));
   }
-  vector<unique_ptr<ScopedVar>> sv;
+  vector<unique_ptr<ScopedGlobalVar>> sv;
   for (size_t i = 1; ; i++) {
     string s;
     Symbol tmpvar_name_sym(Symbol::IsUninitialized{});
@@ -606,8 +606,7 @@
       tmpvar_name_sym = Intern(s);
     }
     if (i < args.size()) {
-      sv.emplace_back(new ScopedVar(ev->mutable_vars(),
-                                    tmpvar_name_sym, av[i-1].get()));
+      sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i-1].get()));
     } else {
       // We need to blank further automatic vars
       Var *v = ev->LookupVar(tmpvar_name_sym);
@@ -615,8 +614,7 @@
       if (v->Origin() != VarOrigin::AUTOMATIC) break;
 
       av.emplace_back(new SimpleVar("", VarOrigin::AUTOMATIC));
-      sv.emplace_back(new ScopedVar(ev->mutable_vars(),
-                                    tmpvar_name_sym, av[i-1].get()));
+      sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i-1].get()));
     }
   }
 
@@ -633,7 +631,7 @@
   for (StringPiece tok : WordScanner(list)) {
     unique_ptr<SimpleVar> v(new SimpleVar(
         tok.as_string(), VarOrigin::AUTOMATIC));
-    ScopedVar sv(ev->mutable_vars(), Intern(varname), v.get());
+    ScopedGlobalVar sv(Intern(varname), v.get());
     ww.MaybeAddWhitespace();
     args[2]->Eval(ev, s);
   }
diff --git a/main.cc b/main.cc
index c732dda..2627bfd 100644
--- a/main.cc
+++ b/main.cc
@@ -105,13 +105,13 @@
   Parse(Intern(bootstrap).str(), Loc("*bootstrap*", 0), stmts);
 }
 
-static void SetVar(StringPiece l, VarOrigin origin, Vars* vars) {
+static void SetVar(StringPiece l, VarOrigin origin) {
   size_t found = l.find('=');
   CHECK(found != string::npos);
   Symbol lhs = Intern(l.substr(0, found));
   StringPiece rhs = l.substr(found + 1);
-  vars->Assign(lhs,
-               new RecursiveVar(NewLiteral(rhs.data()), origin, rhs.data()));
+  lhs.SetGlobalVar(
+      new RecursiveVar(NewLiteral(rhs.data()), origin, rhs.data()));
 }
 
 extern "C" char** environ;
@@ -138,14 +138,12 @@
 
   MakefileCacheManager* cache_mgr = NewMakefileCacheManager();
 
-  Vars* vars = new Vars();
-  vars->Assign(Intern("MAKEFILE_LIST"),
-               new SimpleVar(StringPrintf(" %s", g_flags.makefile),
-                             VarOrigin::FILE));
+  Intern("MAKEFILE_LIST").SetGlobalVar(
+      new SimpleVar(StringPrintf(" %s", g_flags.makefile), VarOrigin::FILE));
   for (char** p = environ; *p; p++) {
-    SetVar(*p, VarOrigin::ENVIRONMENT, vars);
+    SetVar(*p, VarOrigin::ENVIRONMENT);
   }
-  Evaluator* ev = new Evaluator(vars);
+  Evaluator* ev = new Evaluator();
 
   vector<Stmt*> bootstrap_asts;
   ReadBootstrapMakefile(targets, &bootstrap_asts);
@@ -157,7 +155,7 @@
   ev->set_is_bootstrap(false);
 
   for (StringPiece l : cl_vars) {
-    SetVar(l, VarOrigin::COMMAND_LINE, ev->mutable_vars());
+    SetVar(l, VarOrigin::COMMAND_LINE);
   }
 
   {
@@ -210,9 +208,6 @@
   for (Stmt* stmt : bootstrap_asts)
     delete stmt;
   delete ev;
-  // Each Var will be deleted by |ev|.
-  vars->clear();
-  delete vars;
   delete cache_mgr;
 
   return 0;
diff --git a/symtab.cc b/symtab.cc
index af0b620..fb81bfe 100644
--- a/symtab.cc
+++ b/symtab.cc
@@ -27,8 +27,18 @@
 
 #include "log.h"
 #include "strutil.h"
+#include "var.h"
+
+struct SymbolData {
+  SymbolData()
+      : gv(kUndefined) {
+  }
+
+  Var* gv;
+};
 
 vector<string*>* g_symbols;
+static vector<SymbolData> g_symbol_data;
 
 Symbol kEmptySym = Symbol(Symbol::IsUninitialized());
 Symbol kShellSym = Symbol(Symbol::IsUninitialized());
@@ -37,6 +47,45 @@
     : v_(v) {
 }
 
+Var* Symbol::GetGlobalVar() const {
+  if (static_cast<size_t>(v_) >= g_symbol_data.size()) {
+    g_symbol_data.resize(v_ + 1);
+  }
+  Var* v = g_symbol_data[v_].gv;
+  if (v->Origin() == VarOrigin::ENVIRONMENT ||
+      v->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE) {
+    Vars::add_used_env_vars(*this);
+  }
+  return v;
+}
+
+void Symbol::SetGlobalVar(Var* v) const {
+  if (static_cast<size_t>(v_) >= g_symbol_data.size()) {
+    g_symbol_data.resize(v_ + 1);
+  }
+  Var* orig = g_symbol_data[v_].gv;
+  if (orig->Origin() == VarOrigin::OVERRIDE ||
+      orig->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE) {
+    return;
+  }
+  if (orig->Origin() == VarOrigin::AUTOMATIC) {
+    ERROR("overriding automatic variable is not implemented yet");
+  }
+  if (orig->IsDefined())
+    delete orig;
+  g_symbol_data[v_].gv = v;
+}
+
+ScopedGlobalVar::ScopedGlobalVar(Symbol name, Var* var)
+    : name_(name), orig_(NULL) {
+  orig_ = name.GetGlobalVar();
+  g_symbol_data[name_.val()].gv = var;
+}
+
+ScopedGlobalVar::~ScopedGlobalVar() {
+  g_symbol_data[name_.val()].gv = orig_;
+}
+
 class Symtab {
  public:
   Symtab() {
diff --git a/symtab.h b/symtab.h
index 9d8a120..d1de4e1 100644
--- a/symtab.h
+++ b/symtab.h
@@ -25,6 +25,7 @@
 extern vector<string*>* g_symbols;
 
 class Symtab;
+class Var;
 
 class Symbol {
  public:
@@ -54,6 +55,9 @@
 
   bool IsValid() const { return v_ >= 0; }
 
+  Var* GetGlobalVar() const;
+  void SetGlobalVar(Var* v) const;
+
  private:
   explicit Symbol(int v);
 
@@ -62,6 +66,16 @@
   friend class Symtab;
 };
 
+class ScopedGlobalVar {
+ public:
+  ScopedGlobalVar(Symbol name, Var* var);
+  ~ScopedGlobalVar();
+
+ private:
+  Symbol name_;
+  Var* orig_;
+};
+
 inline bool operator==(const Symbol& x, const Symbol& y) {
   return x.val() == y.val();
 }
diff --git a/var.cc b/var.cc
index a5cde3e..73f542c 100644
--- a/var.cc
+++ b/var.cc
@@ -112,6 +112,10 @@
   }
 }
 
+void Vars::add_used_env_vars(Symbol v) {
+  used_env_vars_.insert(v);
+}
+
 Var* Vars::Lookup(Symbol name) const {
   auto found = find(name);
   if (found == end())
diff --git a/var.h b/var.h
index 5ba5fcb..5fc09fa 100644
--- a/var.h
+++ b/var.h
@@ -179,6 +179,8 @@
 
   void Assign(Symbol name, Var* v);
 
+  static void add_used_env_vars(Symbol v);
+
   static const unordered_set<Symbol>& used_env_vars() {
     return used_env_vars_;
   }