Reset symbol unique id counter between compilations

This guarantees identical compilation results on different
compilations using the same compiler instance, guards against
overflow, and is useful as a building block for tracking more symbol
information in the symbol table.

BUG=angleproject:2267
TEST=angle_unittests

Change-Id: Ib5a7cec2fff6712ead969d935d238d28a87fd4a7
Reviewed-on: https://chromium-review.googlesource.com/796795
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index e0fd0cb..f0df223 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -734,6 +734,8 @@
 
     IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
 
+    symbolTable.markBuiltInInitializationFinished();
+
     return true;
 }
 
@@ -868,6 +870,8 @@
     nameMap.clear();
 
     mSourcePath     = nullptr;
+
+    symbolTable.clearCompilationResults();
 }
 
 bool TCompiler::initCallDag(TIntermNode *root)
diff --git a/src/compiler/translator/SymbolTable.cpp b/src/compiler/translator/SymbolTable.cpp
index 3cfa8b7..9e7270d 100644
--- a/src/compiler/translator/SymbolTable.cpp
+++ b/src/compiler/translator/SymbolTable.cpp
@@ -291,7 +291,8 @@
                                                                const TString *name)
 {
     TInterfaceBlockName *blockNameSymbol = new TInterfaceBlockName(this, name);
-    if (insert(level, ext, blockNameSymbol))
+    blockNameSymbol->relateToExtension(ext);
+    if (insert(level, blockNameSymbol))
     {
         return blockNameSymbol;
     }
@@ -324,7 +325,8 @@
                                            const TType &type)
 {
     TVariable *var = new TVariable(this, NewPoolTString(name), type);
-    if (insert(level, ext, var))
+    var->relateToExtension(ext);
+    if (insert(level, var))
     {
         if (var->getType().getBasicType() == EbtStruct)
         {
@@ -583,6 +585,7 @@
 void TSymbolTable::insertUnmangledBuiltInName(const char *name, ESymbolLevel level)
 {
     ASSERT(level >= 0 && level < static_cast<ESymbolLevel>(table.size()));
+    ASSERT(mUserDefinedUniqueIdsStart == -1);
     table[level]->insertUnmangledBuiltInName(std::string(name));
 }
 
@@ -619,4 +622,23 @@
     return false;
 }
 
+void TSymbolTable::markBuiltInInitializationFinished()
+{
+    mUserDefinedUniqueIdsStart = mUniqueIdCounter;
+}
+
+void TSymbolTable::clearCompilationResults()
+{
+    mUniqueIdCounter = mUserDefinedUniqueIdsStart;
+
+    // User-defined scopes should have already been cleared when the compilation finished.
+    ASSERT(table.size() == LAST_BUILTIN_LEVEL + 1u);
+}
+
+int TSymbolTable::nextUniqueIdValue()
+{
+    ASSERT(mUniqueIdCounter < std::numeric_limits<int>::max());
+    return ++mUniqueIdCounter;
+}
+
 }  // namespace sh
diff --git a/src/compiler/translator/SymbolTable.h b/src/compiler/translator/SymbolTable.h
index b09f643..e92ac8f 100644
--- a/src/compiler/translator/SymbolTable.h
+++ b/src/compiler/translator/SymbolTable.h
@@ -287,7 +287,7 @@
 class TSymbolTable : angle::NonCopyable
 {
   public:
-    TSymbolTable() : mUniqueIdCounter(0), mEmptySymbolId(this)
+    TSymbolTable() : mUniqueIdCounter(0), mUserDefinedUniqueIdsStart(-1), mEmptySymbolId(this)
     {
         // The symbol table cannot be used until push() is called, but
         // the lack of an initial call to push() can be used to detect
@@ -358,7 +358,8 @@
         TConstantUnion *unionArray = new TConstantUnion[1];
         unionArray[0].setIConst(value);
         constant->shareConstPointer(unionArray);
-        return insert(level, ext, constant);
+        constant->relateToExtension(ext);
+        return insert(level, constant);
     }
 
     bool insertConstIvec3(ESymbolLevel level,
@@ -509,19 +510,20 @@
     // Checks whether there is a built-in accessible by a shader with the specified version.
     bool hasUnmangledBuiltInForShaderVersion(const char *name, int shaderVersion);
 
+    void markBuiltInInitializationFinished();
+    void clearCompilationResults();
+
   private:
     friend class TSymbolUniqueId;
-    int nextUniqueIdValue() { return ++mUniqueIdCounter; }
+    int nextUniqueIdValue();
 
     ESymbolLevel currentLevel() const { return static_cast<ESymbolLevel>(table.size() - 1); }
 
     TVariable *insertVariable(ESymbolLevel level, const TString *name, const TType &type);
 
-    bool insert(ESymbolLevel level, TSymbol *symbol) { return table[level]->insert(symbol); }
-
-    bool insert(ESymbolLevel level, TExtension ext, TSymbol *symbol)
+    bool insert(ESymbolLevel level, TSymbol *symbol)
     {
-        symbol->relateToExtension(ext);
+        ASSERT(level > LAST_BUILTIN_LEVEL || mUserDefinedUniqueIdsStart == -1);
         return table[level]->insert(symbol);
     }
 
@@ -537,6 +539,11 @@
 
     int mUniqueIdCounter;
 
+    // -1 before built-in init has finished, one past the last built-in id afterwards.
+    // TODO(oetuaho): Make this a compile-time constant once the symbol table is initialized at
+    // compile time. http://anglebug.com/1432
+    int mUserDefinedUniqueIdsStart;
+
     const TSymbolUniqueId mEmptySymbolId;
 };