Add const qualification to symbol accesses

All accesses to built-in symbols now happen through const-qualified
pointers.

This also encapsulates TSymbolTableLevel inside TSymbolTable.

This prepares for statically allocating built-in symbols.

BUG=angleproject:2267
TEST=angle_unittests

Change-Id: I473014d978daa765b4a733d761d6c08b28288776
Reviewed-on: https://chromium-review.googlesource.com/859959
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/CollectVariables.cpp b/src/compiler/translator/CollectVariables.cpp
index 846bc64..0b7cd70 100644
--- a/src/compiler/translator/CollectVariables.cpp
+++ b/src/compiler/translator/CollectVariables.cpp
@@ -259,8 +259,8 @@
 void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
                                                               ShaderVariable *info)
 {
-    TVariable *symbolTableVar =
-        reinterpret_cast<TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
+    const TVariable *symbolTableVar =
+        reinterpret_cast<const TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
     ASSERT(symbolTableVar);
     const TType &type = symbolTableVar->getType();
 
diff --git a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
index 8748cff..837e4bc 100644
--- a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
+++ b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
@@ -147,9 +147,9 @@
                       SymbolType::AngleInternal);
 
     DeclareGlobalVariable(root, viewID);
-    ReplaceVariable(root,
-                    static_cast<TVariable *>(symbolTable->findBuiltIn("gl_ViewID_OVR", 300, true)),
-                    viewID);
+    ReplaceVariable(
+        root, static_cast<const TVariable *>(symbolTable->findBuiltIn("gl_ViewID_OVR", 300, true)),
+        viewID);
     if (shaderType == GL_VERTEX_SHADER)
     {
         // Replacing gl_InstanceID with InstanceID should happen before adding the initializers of
@@ -160,7 +160,8 @@
             symbolTable, instanceIDVariableName, instanceIDVariableType, SymbolType::AngleInternal);
         DeclareGlobalVariable(root, instanceID);
         ReplaceVariable(
-            root, static_cast<TVariable *>(symbolTable->findBuiltIn("gl_InstanceID", 300, true)),
+            root,
+            static_cast<const TVariable *>(symbolTable->findBuiltIn("gl_InstanceID", 300, true)),
             instanceID);
 
         TIntermSequence *initializers = new TIntermSequence();
diff --git a/src/compiler/translator/FlagStd140Structs.cpp b/src/compiler/translator/FlagStd140Structs.cpp
index 37f7225..886de30 100644
--- a/src/compiler/translator/FlagStd140Structs.cpp
+++ b/src/compiler/translator/FlagStd140Structs.cpp
@@ -28,13 +28,13 @@
     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
 
   private:
-    void mapBlockStructMembers(TIntermSymbol *blockDeclarator, TInterfaceBlock *block);
+    void mapBlockStructMembers(TIntermSymbol *blockDeclarator, const TInterfaceBlock *block);
 
     std::vector<MappedStruct> mMappedStructs;
 };
 
 void FlagStd140StructsTraverser::mapBlockStructMembers(TIntermSymbol *blockDeclarator,
-                                                       TInterfaceBlock *block)
+                                                       const TInterfaceBlock *block)
 {
     for (auto *field : block->fields())
     {
@@ -53,7 +53,7 @@
     TIntermTyped *declarator = node->getSequence()->back()->getAsTyped();
     if (declarator->getBasicType() == EbtInterfaceBlock)
     {
-        TInterfaceBlock *block = declarator->getType().getInterfaceBlock();
+        const TInterfaceBlock *block = declarator->getType().getInterfaceBlock();
         if (block->blockStorage() == EbsStd140)
         {
             mapBlockStructMembers(declarator->getAsSymbolNode(), block);
diff --git a/src/compiler/translator/IntermNode_util.cpp b/src/compiler/translator/IntermNode_util.cpp
index 8443767..a58b170 100644
--- a/src/compiler/translator/IntermNode_util.cpp
+++ b/src/compiler/translator/IntermNode_util.cpp
@@ -22,7 +22,7 @@
                                        int shaderVersion)
 {
     TString mangledName = TFunction::GetMangledNameFromCall(name, *arguments);
-    TSymbol *symbol     = symbolTable.findBuiltIn(mangledName, shaderVersion);
+    const TSymbol *symbol = symbolTable.findBuiltIn(mangledName, shaderVersion);
     if (symbol)
     {
         ASSERT(symbol->isFunction());
@@ -235,7 +235,7 @@
 
 TIntermSymbol *ReferenceGlobalVariable(const TString &name, const TSymbolTable &symbolTable)
 {
-    TVariable *var = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
+    const TVariable *var = reinterpret_cast<const TVariable *>(symbolTable.findGlobal(name));
     ASSERT(var);
     return new TIntermSymbol(var);
 }
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index 8c45d75..dbfc19b 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -738,10 +738,10 @@
         {
             // Find the built-in function corresponding to this op so that we can determine the
             // in/out qualifiers of its parameters.
-            TFunction *builtInFunc = nullptr;
+            const TFunction *builtInFunc = nullptr;
             if (!node->isFunctionCall() && !node->isConstructor())
             {
-                builtInFunc = static_cast<TFunction *>(
+                builtInFunc = static_cast<const TFunction *>(
                     mSymbolTable->findBuiltIn(node->getSymbolTableMangledName(), mShaderVersion));
             }
 
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index ec4a65a..b3e8476 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -260,7 +260,7 @@
     }
     if (type.getBasicType() == EbtInterfaceBlock)
     {
-        TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+        const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
         declareInterfaceBlockLayout(interfaceBlock);
     }
     if (qualifier != EvqTemporary && qualifier != EvqGlobal)
@@ -317,7 +317,7 @@
     }
     else if (type.getBasicType() == EbtInterfaceBlock)
     {
-        TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+        const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
         declareInterfaceBlock(interfaceBlock);
     }
     else
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 825bbad..55c57c9 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -349,7 +349,7 @@
 
     for (auto &mappedStruct : std140Structs)
     {
-        TInterfaceBlock *interfaceBlock =
+        const TInterfaceBlock *interfaceBlock =
             mappedStruct.blockDeclarator->getType().getInterfaceBlock();
         if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
         {
@@ -1259,7 +1259,7 @@
                 if (visit == PreVisit)
                 {
                     TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
-                    TInterfaceBlock *interfaceBlock    = leftType.getInterfaceBlock();
+                    const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
                     if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0)
                     {
                         mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] =
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index c6bb87f..4766077 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1134,7 +1134,7 @@
         else if (static_cast<int>(type->getOutermostArraySize()) ==
                  maxDrawBuffers->getConstPointer()->getIConst())
         {
-            if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
+            if (const TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
             {
                 needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->extension());
             }
@@ -2838,8 +2838,8 @@
 {
     if (mGlInVariableWithArraySize == nullptr)
     {
-        TSymbol *glPerVertex              = symbolTable.findBuiltIn("gl_PerVertex", 310);
-        TInterfaceBlock *glPerVertexBlock = static_cast<TInterfaceBlock *>(glPerVertex);
+        const TSymbol *glPerVertex              = symbolTable.findBuiltIn("gl_PerVertex", 310);
+        const TInterfaceBlock *glPerVertexBlock = static_cast<const TInterfaceBlock *>(glPerVertex);
         TType *glInType = new TType(glPerVertexBlock, EvqPerVertexIn, TLayoutQualifier::Create());
         glInType->makeArray(inputArraySize);
         mGlInVariableWithArraySize =
@@ -3213,15 +3213,16 @@
     // Note: function found from the symbol table could be the same as parsedFunction if this is the
     // first declaration. Either way the instance in the symbol table is used to track whether the
     // function is declared multiple times.
-    TFunction *function = static_cast<TFunction *>(
-        symbolTable.find(parsedFunction.getMangledName(), getShaderVersion()));
-    if (function->hasPrototypeDeclaration() && mShaderVersion == 100)
+    bool hadPrototypeDeclaration = false;
+    const TFunction *function    = symbolTable.markUserDefinedFunctionHasPrototypeDeclaration(
+        parsedFunction.getMangledName(), &hadPrototypeDeclaration);
+
+    if (hadPrototypeDeclaration && mShaderVersion == 100)
     {
         // ESSL 1.00.17 section 4.2.7.
         // Doesn't apply to ESSL 3.00.4: see section 4.2.3.
         error(location, "duplicate function prototype declarations are not allowed", "function");
     }
-    function->setHasPrototypeDeclaration();
 
     TIntermFunctionPrototype *prototype =
         createPrototypeNodeFromFunction(*function, location, false);
@@ -3263,49 +3264,33 @@
 }
 
 void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
-                                                  TFunction **function,
+                                                  const TFunction *function,
                                                   TIntermFunctionPrototype **prototypeOut)
 {
     ASSERT(function);
-    ASSERT(*function);
     const TSymbol *builtIn =
-        symbolTable.findBuiltIn((*function)->getMangledName(), getShaderVersion());
+        symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
 
     if (builtIn)
     {
-        error(location, "built-in functions cannot be redefined", (*function)->name().c_str());
+        error(location, "built-in functions cannot be redefined", function->name().c_str());
     }
     else
     {
-        TFunction *prevDec = static_cast<TFunction *>(
-            symbolTable.find((*function)->getMangledName(), getShaderVersion()));
-
-        // Note: 'prevDec' could be 'function' if this is the first time we've seen function as it
-        // would have just been put in the symbol table. Otherwise, we're looking up an earlier
-        // occurance.
-        if (*function != prevDec)
+        bool wasDefined = false;
+        function =
+            symbolTable.setUserDefinedFunctionParameterNamesFromDefinition(function, &wasDefined);
+        if (wasDefined)
         {
-            // Swap the parameters of the previous declaration to the parameters of the function
-            // definition (parameter names may differ).
-            prevDec->swapParameters(**function);
-
-            // The function definition will share the same symbol as any previous declaration.
-            *function = prevDec;
+            error(location, "function already has a body", function->name().c_str());
         }
-
-        if ((*function)->isDefined())
-        {
-            error(location, "function already has a body", (*function)->name().c_str());
-        }
-
-        (*function)->setDefined();
     }
 
     // Remember the return type for later checking for return statements.
-    mCurrentFunctionType  = &((*function)->getReturnType());
+    mCurrentFunctionType  = &(function->getReturnType());
     mFunctionReturnsValue = false;
 
-    *prototypeOut = createPrototypeNodeFromFunction(**function, location, true);
+    *prototypeOut = createPrototypeNodeFromFunction(*function, location, true);
     setLoopNestingLevel(0);
 }
 
@@ -3319,8 +3304,8 @@
     // Return types and parameter qualifiers must match in all redeclarations, so those are checked
     // here.
     //
-    TFunction *prevDec =
-        static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
+    const TFunction *prevDec = static_cast<const TFunction *>(
+        symbolTable.find(function->getMangledName(), getShaderVersion()));
 
     for (size_t i = 0u; i < function->getParamCount(); ++i)
     {
@@ -3360,26 +3345,21 @@
         }
     }
 
-    //
     // Check for previously declared variables using the same name.
-    //
-    TSymbol *prevSym = symbolTable.find(function->name(), getShaderVersion());
+    const TSymbol *prevSym   = symbolTable.find(function->name(), getShaderVersion());
+    bool insertUnmangledName = true;
     if (prevSym)
     {
         if (!prevSym->isFunction())
         {
             error(location, "redefinition of a function", function->name().c_str());
         }
+        insertUnmangledName = false;
     }
-    else
-    {
-        // Insert the unmangled name to detect potential future redefinition as a variable.
-        symbolTable.getOuterLevel()->insertUnmangled(function);
-    }
-
-    // We're at the inner scope level of the function's arguments and body statement.
-    // Add the function prototype to the surrounding scope instead.
-    symbolTable.getOuterLevel()->insert(function);
+    // Parsing is at the inner scope level of the function's arguments and body statement at this
+    // point, but declareUserDefinedFunction takes care of declaring the function at the global
+    // scope.
+    symbolTable.declareUserDefinedFunction(function, insertUnmangledName);
 
     // Raise error message if main function takes any parameters or return anything other than void
     if (function->name() == "main")
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index 354f6fe..8527a20 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -285,7 +285,7 @@
                                                      TIntermBlock *functionBody,
                                                      const TSourceLoc &location);
     void parseFunctionDefinitionHeader(const TSourceLoc &location,
-                                       TFunction **function,
+                                       const TFunction *function,
                                        TIntermFunctionPrototype **prototypeOut);
     TFunction *parseFunctionDeclarator(const TSourceLoc &location, TFunction *function);
     TFunction *parseFunctionHeader(const TPublicType &type,
diff --git a/src/compiler/translator/SymbolTable.cpp b/src/compiler/translator/SymbolTable.cpp
index 39dd6cc..7d841b6 100644
--- a/src/compiler/translator/SymbolTable.cpp
+++ b/src/compiler/translator/SymbolTable.cpp
@@ -21,16 +21,57 @@
 namespace sh
 {
 
+class TSymbolTable::TSymbolTableLevel
+{
+  public:
+    TSymbolTableLevel() : mGlobalInvariant(false) {}
+    ~TSymbolTableLevel();
+
+    bool insert(TSymbol *symbol);
+
+    // Insert a function using its unmangled name as the key.
+    bool insertUnmangled(TFunction *function);
+
+    TSymbol *find(const TString &name) const;
+
+    void addInvariantVarying(const std::string &name) { mInvariantVaryings.insert(name); }
+
+    bool isVaryingInvariant(const std::string &name)
+    {
+        return (mGlobalInvariant || mInvariantVaryings.count(name) > 0);
+    }
+
+    void setGlobalInvariant(bool invariant) { mGlobalInvariant = invariant; }
+
+    void insertUnmangledBuiltInName(const char *name);
+    bool hasUnmangledBuiltIn(const char *name) const;
+
+  private:
+    using tLevel        = TUnorderedMap<TString, TSymbol *>;
+    using tLevelPair    = const tLevel::value_type;
+    using tInsertResult = std::pair<tLevel::iterator, bool>;
+
+    tLevel level;
+    std::set<std::string> mInvariantVaryings;
+    bool mGlobalInvariant;
+
+    struct CharArrayComparator
+    {
+        bool operator()(const char *a, const char *b) const { return strcmp(a, b) < 0; }
+    };
+    std::set<const char *, CharArrayComparator> mUnmangledBuiltInNames;
+};
+
 //
 // Symbol table levels are a map of pointers to symbols that have to be deleted.
 //
-TSymbolTableLevel::~TSymbolTableLevel()
+TSymbolTable::TSymbolTableLevel::~TSymbolTableLevel()
 {
     for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
         delete (*it).second;
 }
 
-bool TSymbolTableLevel::insert(TSymbol *symbol)
+bool TSymbolTable::TSymbolTableLevel::insert(TSymbol *symbol)
 {
     // returning true means symbol was added to the table
     tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol));
@@ -38,7 +79,7 @@
     return result.second;
 }
 
-bool TSymbolTableLevel::insertUnmangled(TFunction *function)
+bool TSymbolTable::TSymbolTableLevel::insertUnmangled(TFunction *function)
 {
     // returning true means symbol was added to the table
     tInsertResult result = level.insert(tLevelPair(function->name(), function));
@@ -46,7 +87,7 @@
     return result.second;
 }
 
-TSymbol *TSymbolTableLevel::find(const TString &name) const
+TSymbol *TSymbolTable::TSymbolTableLevel::find(const TString &name) const
 {
     tLevel::const_iterator it = level.find(name);
     if (it == level.end())
@@ -55,24 +96,69 @@
         return (*it).second;
 }
 
-void TSymbolTableLevel::insertUnmangledBuiltInName(const char *name)
+void TSymbolTable::TSymbolTableLevel::insertUnmangledBuiltInName(const char *name)
 {
     mUnmangledBuiltInNames.insert(name);
 }
 
-bool TSymbolTableLevel::hasUnmangledBuiltIn(const char *name) const
+bool TSymbolTable::TSymbolTableLevel::hasUnmangledBuiltIn(const char *name) const
 {
     return mUnmangledBuiltInNames.count(name) > 0;
 }
 
-TSymbol *TSymbolTable::find(const TString &name,
-                            int shaderVersion,
-                            bool *builtIn,
-                            bool *sameScope) const
+void TSymbolTable::push()
 {
-    int level = currentLevel();
-    TSymbol *symbol;
+    table.push_back(new TSymbolTableLevel);
+    precisionStack.push_back(new PrecisionStackLevel);
+}
 
+void TSymbolTable::pop()
+{
+    delete table.back();
+    table.pop_back();
+
+    delete precisionStack.back();
+    precisionStack.pop_back();
+}
+
+const TFunction *TSymbolTable::markUserDefinedFunctionHasPrototypeDeclaration(
+    const TString &mangledName,
+    bool *hadPrototypeDeclarationOut)
+{
+    TFunction *function         = findUserDefinedFunction(mangledName);
+    *hadPrototypeDeclarationOut = function->hasPrototypeDeclaration();
+    function->setHasPrototypeDeclaration();
+    return function;
+}
+
+const TFunction *TSymbolTable::setUserDefinedFunctionParameterNamesFromDefinition(
+    const TFunction *function,
+    bool *wasDefinedOut)
+{
+    TFunction *firstDeclaration = findUserDefinedFunction(function->getMangledName());
+    ASSERT(firstDeclaration);
+    // Note: 'firstDeclaration' could be 'function' if this is the first time we've seen function as
+    // it would have just been put in the symbol table. Otherwise, we're looking up an earlier
+    // occurance.
+    if (function != firstDeclaration)
+    {
+        // Swap the parameters of the previous declaration to the parameters of the function
+        // definition (parameter names may differ).
+        firstDeclaration->swapParameters(*function);
+    }
+
+    *wasDefinedOut = firstDeclaration->isDefined();
+    firstDeclaration->setDefined();
+    return firstDeclaration;
+}
+
+const TSymbol *TSymbolTable::find(const TString &name,
+                                  int shaderVersion,
+                                  bool *builtIn,
+                                  bool *sameScope) const
+{
+    int level       = currentLevel();
+    TSymbol *symbol = nullptr;
     do
     {
         if (level == GLSL_BUILTINS)
@@ -85,7 +171,7 @@
             level--;
 
         symbol = table[level]->find(name);
-    } while (symbol == 0 && --level >= 0);
+    } while (symbol == nullptr && --level >= 0);
 
     if (builtIn)
         *builtIn = (level <= LAST_BUILTIN_LEVEL);
@@ -95,20 +181,27 @@
     return symbol;
 }
 
-TSymbol *TSymbolTable::findGlobal(const TString &name) const
+TFunction *TSymbolTable::findUserDefinedFunction(const TString &name) const
+{
+    // User-defined functions are always declared at the global level.
+    ASSERT(currentLevel() >= GLOBAL_LEVEL);
+    return static_cast<TFunction *>(table[GLOBAL_LEVEL]->find(name));
+}
+
+const TSymbol *TSymbolTable::findGlobal(const TString &name) const
 {
     ASSERT(table.size() > GLOBAL_LEVEL);
     return table[GLOBAL_LEVEL]->find(name);
 }
 
-TSymbol *TSymbolTable::findBuiltIn(const TString &name, int shaderVersion) const
+const TSymbol *TSymbolTable::findBuiltIn(const TString &name, int shaderVersion) const
 {
     return findBuiltIn(name, shaderVersion, false);
 }
 
-TSymbol *TSymbolTable::findBuiltIn(const TString &name,
-                                   int shaderVersion,
-                                   bool includeGLSLBuiltins) const
+const TSymbol *TSymbolTable::findBuiltIn(const TString &name,
+                                         int shaderVersion,
+                                         bool includeGLSLBuiltins) const
 {
     for (int level = LAST_BUILTIN_LEVEL; level >= 0; level--)
     {
@@ -232,6 +325,17 @@
     return insert(currentLevel(), interfaceBlock);
 }
 
+void TSymbolTable::declareUserDefinedFunction(TFunction *function, bool insertUnmangledName)
+{
+    ASSERT(currentLevel() >= GLOBAL_LEVEL);
+    if (insertUnmangledName)
+    {
+        // Insert the unmangled name to detect potential future redefinition as a variable.
+        table[GLOBAL_LEVEL]->insertUnmangled(function);
+    }
+    table[GLOBAL_LEVEL]->insert(function);
+}
+
 TVariable *TSymbolTable::insertVariable(ESymbolLevel level, const char *name, const TType *type)
 {
     ASSERT(level <= LAST_BUILTIN_LEVEL);
@@ -275,6 +379,12 @@
     return insert(level, variable);
 }
 
+bool TSymbolTable::insert(ESymbolLevel level, TSymbol *symbol)
+{
+    ASSERT(level > LAST_BUILTIN_LEVEL || mUserDefinedUniqueIdsStart == -1);
+    return table[level]->insert(symbol);
+}
+
 bool TSymbolTable::insertStructType(ESymbolLevel level, TStructure *str)
 {
     ASSERT(str);
@@ -525,6 +635,24 @@
     return prec;
 }
 
+void TSymbolTable::addInvariantVarying(const std::string &originalName)
+{
+    ASSERT(atGlobalLevel());
+    table[currentLevel()]->addInvariantVarying(originalName);
+}
+
+bool TSymbolTable::isVaryingInvariant(const std::string &originalName) const
+{
+    ASSERT(atGlobalLevel());
+    return table[currentLevel()]->isVaryingInvariant(originalName);
+}
+
+void TSymbolTable::setGlobalInvariant(bool invariant)
+{
+    ASSERT(atGlobalLevel());
+    table[currentLevel()]->setGlobalInvariant(invariant);
+}
+
 void TSymbolTable::insertUnmangledBuiltInName(const char *name, ESymbolLevel level)
 {
     ASSERT(level >= 0 && level < static_cast<ESymbolLevel>(table.size()));
diff --git a/src/compiler/translator/SymbolTable.h b/src/compiler/translator/SymbolTable.h
index f66863e..269fe43 100644
--- a/src/compiler/translator/SymbolTable.h
+++ b/src/compiler/translator/SymbolTable.h
@@ -44,49 +44,6 @@
 namespace sh
 {
 
-class TSymbolTableLevel
-{
-  public:
-    typedef TUnorderedMap<TString, TSymbol *> tLevel;
-    typedef tLevel::const_iterator const_iterator;
-    typedef const tLevel::value_type tLevelPair;
-    typedef std::pair<tLevel::iterator, bool> tInsertResult;
-
-    TSymbolTableLevel() : mGlobalInvariant(false) {}
-    ~TSymbolTableLevel();
-
-    bool insert(TSymbol *symbol);
-
-    // Insert a function using its unmangled name as the key.
-    bool insertUnmangled(TFunction *function);
-
-    TSymbol *find(const TString &name) const;
-
-    void addInvariantVarying(const std::string &name) { mInvariantVaryings.insert(name); }
-
-    bool isVaryingInvariant(const std::string &name)
-    {
-        return (mGlobalInvariant || mInvariantVaryings.count(name) > 0);
-    }
-
-    void setGlobalInvariant(bool invariant) { mGlobalInvariant = invariant; }
-
-    void insertUnmangledBuiltInName(const char *name);
-    bool hasUnmangledBuiltIn(const char *name) const;
-
-  protected:
-    tLevel level;
-    std::set<std::string> mInvariantVaryings;
-    bool mGlobalInvariant;
-
-  private:
-    struct CharArrayComparator
-    {
-        bool operator()(const char *a, const char *b) const { return strcmp(a, b) < 0; }
-    };
-    std::set<const char *, CharArrayComparator> mUnmangledBuiltInNames;
-};
-
 // Define ESymbolLevel as int rather than an enum since level can go
 // above GLOBAL_LEVEL and cause atBuiltInLevel() to fail if the
 // compiler optimizes the >= of the last element to ==.
@@ -119,27 +76,18 @@
     bool isEmpty() const { return table.empty(); }
     bool atBuiltInLevel() const { return currentLevel() <= LAST_BUILTIN_LEVEL; }
     bool atGlobalLevel() const { return currentLevel() == GLOBAL_LEVEL; }
-    void push()
-    {
-        table.push_back(new TSymbolTableLevel);
-        precisionStack.push_back(new PrecisionStackLevel);
-    }
 
-    void pop()
-    {
-        delete table.back();
-        table.pop_back();
-
-        delete precisionStack.back();
-        precisionStack.pop_back();
-    }
+    void push();
+    void pop();
 
     // The declare* entry points are used when parsing and declare symbols at the current scope.
-    // They return the created symbol / true in case the declaration was successful, and nullptr /
-    // false if the declaration failed due to redefinition.
+    // They return the created true in case the declaration was successful, and false if the
+    // declaration failed due to redefinition.
     bool declareVariable(TVariable *variable);
     bool declareStructType(TStructure *str);
     bool declareInterfaceBlock(TInterfaceBlock *interfaceBlock);
+    // Functions are always declared at global scope.
+    void declareUserDefinedFunction(TFunction *function, bool insertUnmangledName);
 
     // The insert* entry points are used when initializing the symbol table with built-ins.
     // They return the created symbol / true in case the declaration was successful, and nullptr /
@@ -233,22 +181,25 @@
                                               const TType *rvalue,
                                               const char *name);
 
-    TSymbol *find(const TString &name,
-                  int shaderVersion,
-                  bool *builtIn   = nullptr,
-                  bool *sameScope = nullptr) const;
+    // These return the TFunction pointer to keep using to refer to this function.
+    const TFunction *markUserDefinedFunctionHasPrototypeDeclaration(
+        const TString &mangledName,
+        bool *hadPrototypeDeclarationOut);
+    const TFunction *setUserDefinedFunctionParameterNamesFromDefinition(const TFunction *function,
+                                                                        bool *wasDefinedOut);
 
-    TSymbol *findGlobal(const TString &name) const;
+    const TSymbol *find(const TString &name,
+                        int shaderVersion,
+                        bool *builtIn   = nullptr,
+                        bool *sameScope = nullptr) const;
 
-    TSymbol *findBuiltIn(const TString &name, int shaderVersion) const;
+    const TSymbol *findGlobal(const TString &name) const;
 
-    TSymbol *findBuiltIn(const TString &name, int shaderVersion, bool includeGLSLBuiltins) const;
+    const TSymbol *findBuiltIn(const TString &name, int shaderVersion) const;
 
-    TSymbolTableLevel *getOuterLevel()
-    {
-        assert(currentLevel() >= 1);
-        return table[currentLevel() - 1];
-    }
+    const TSymbol *findBuiltIn(const TString &name,
+                               int shaderVersion,
+                               bool includeGLSLBuiltins) const;
 
     void setDefaultPrecision(TBasicType type, TPrecision prec)
     {
@@ -263,26 +214,15 @@
 
     // This records invariant varyings declared through
     // "invariant varying_name;".
-    void addInvariantVarying(const std::string &originalName)
-    {
-        ASSERT(atGlobalLevel());
-        table[currentLevel()]->addInvariantVarying(originalName);
-    }
+    void addInvariantVarying(const std::string &originalName);
+
     // If this returns false, the varying could still be invariant
     // if it is set as invariant during the varying variable
     // declaration - this piece of information is stored in the
     // variable's type, not here.
-    bool isVaryingInvariant(const std::string &originalName) const
-    {
-        ASSERT(atGlobalLevel());
-        return table[currentLevel()]->isVaryingInvariant(originalName);
-    }
+    bool isVaryingInvariant(const std::string &originalName) const;
 
-    void setGlobalInvariant(bool invariant)
-    {
-        ASSERT(atGlobalLevel());
-        table[currentLevel()]->setGlobalInvariant(invariant);
-    }
+    void setGlobalInvariant(bool invariant);
 
     const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); }
 
@@ -296,6 +236,8 @@
     friend class TSymbolUniqueId;
     int nextUniqueIdValue();
 
+    class TSymbolTableLevel;
+
     ESymbolLevel currentLevel() const { return static_cast<ESymbolLevel>(table.size() - 1); }
 
     TVariable *insertVariable(ESymbolLevel level,
@@ -303,11 +245,9 @@
                               const TType *type,
                               SymbolType symbolType);
 
-    bool insert(ESymbolLevel level, TSymbol *symbol)
-    {
-        ASSERT(level > LAST_BUILTIN_LEVEL || mUserDefinedUniqueIdsStart == -1);
-        return table[level]->insert(symbol);
-    }
+    bool insert(ESymbolLevel level, TSymbol *symbol);
+
+    TFunction *findUserDefinedFunction(const TString &name) const;
 
     // Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00 and
     // above.
diff --git a/src/compiler/translator/Types.cpp b/src/compiler/translator/Types.cpp
index fb01658..b53bee3 100644
--- a/src/compiler/translator/Types.cpp
+++ b/src/compiler/translator/Types.cpp
@@ -210,7 +210,7 @@
 {
 }
 
-TType::TType(TInterfaceBlock *interfaceBlockIn,
+TType::TType(const TInterfaceBlock *interfaceBlockIn,
              TQualifier qualifierIn,
              TLayoutQualifier layoutQualifierIn)
     : type(EbtInterfaceBlock),
@@ -757,7 +757,7 @@
     }
 }
 
-void TType::setInterfaceBlock(TInterfaceBlock *interfaceBlockIn)
+void TType::setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn)
 {
     if (mInterfaceBlock != interfaceBlockIn)
     {
diff --git a/src/compiler/translator/Types.h b/src/compiler/translator/Types.h
index bd5df2d..d56b07c 100644
--- a/src/compiler/translator/Types.h
+++ b/src/compiler/translator/Types.h
@@ -98,7 +98,7 @@
           unsigned char ss = 1);
     explicit TType(const TPublicType &p);
     explicit TType(const TStructure *userDef);
-    TType(TInterfaceBlock *interfaceBlockIn,
+    TType(const TInterfaceBlock *interfaceBlockIn,
           TQualifier qualifierIn,
           TLayoutQualifier layoutQualifierIn);
     TType(const TType &t);
@@ -213,8 +213,8 @@
     // Note that the array element type might still be an array type in GLSL ES version >= 3.10.
     void toArrayElementType();
 
-    TInterfaceBlock *getInterfaceBlock() const { return mInterfaceBlock; }
-    void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn);
+    const TInterfaceBlock *getInterfaceBlock() const { return mInterfaceBlock; }
+    void setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn);
     bool isInterfaceBlock() const { return type == EbtInterfaceBlock; }
 
     bool isVector() const { return primarySize > 1 && secondarySize == 1; }
@@ -341,7 +341,7 @@
     // 1) Represents an interface block.
     // 2) Represents the member variable of an unnamed interface block.
     // It's nullptr also for members of named interface blocks.
-    TInterfaceBlock *mInterfaceBlock;
+    const TInterfaceBlock *mInterfaceBlock;
 
     // nullptr unless this is a struct
     const TStructure *mStructure;
@@ -357,7 +357,7 @@
     TBasicType type;
     unsigned char primarySize;    // size of vector or cols of matrix
     unsigned char secondarySize;  // rows of matrix
-    TStructure *userDef;
+    const TStructure *userDef;
     TSourceLoc line;
 
     // true if the type was defined by a struct specifier rather than a reference to a type name.
@@ -374,7 +374,9 @@
         isStructSpecifier = false;
     }
 
-    void initializeStruct(TStructure *aUserDef, bool aIsStructSpecifier, const TSourceLoc &aLine)
+    void initializeStruct(const TStructure *aUserDef,
+                          bool aIsStructSpecifier,
+                          const TSourceLoc &aLine)
     {
         type              = EbtStruct;
         primarySize       = 1;
@@ -421,7 +423,7 @@
     unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; }
     unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; }
 
-    TStructure *getUserDef() const { return typeSpecifierNonArray.userDef; }
+    const TStructure *getUserDef() const { return typeSpecifierNonArray.userDef; }
     const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; }
 
     bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; }
diff --git a/src/compiler/translator/glslang.l b/src/compiler/translator/glslang.l
index c12161d..6a52f4b 100644
--- a/src/compiler/translator/glslang.l
+++ b/src/compiler/translator/glslang.l
@@ -441,7 +441,7 @@
     struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
 
     int token = IDENTIFIER;
-    TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->getShaderVersion());
+    const TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->getShaderVersion());
     if (symbol && symbol->isStruct())
     {
         token = TYPE_NAME;
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index 214eac0..aeddf29 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -69,7 +69,7 @@
             unsigned int u;
             bool b;
         };
-        TSymbol* symbol;
+        const TSymbol* symbol;
     } lex;
     struct {
         TOperator op;
@@ -1196,7 +1196,7 @@
     }
     | TYPE_NAME {
         // This is for user defined type names. The lexical phase looked up the type.
-        TStructure *structure = static_cast<TStructure*>($1.symbol);
+        const TStructure *structure = static_cast<const TStructure*>($1.symbol);
         $$.initializeStruct(structure, false, @1);
     }
     ;
@@ -1456,7 +1456,7 @@
 
 function_definition
     : function_prototype {
-        context->parseFunctionDefinitionHeader(@1, &($1.function), &($1.intermFunctionPrototype));
+        context->parseFunctionDefinitionHeader(@1, $1.function, &($1.intermFunctionPrototype));
     }
     compound_statement_no_new_scope {
         $$ = context->addFunctionDefinition($1.intermFunctionPrototype, $3, @1);
diff --git a/src/compiler/translator/glslang_lex.cpp b/src/compiler/translator/glslang_lex.cpp
index 71b2f2e..c1221a8 100644
--- a/src/compiler/translator/glslang_lex.cpp
+++ b/src/compiler/translator/glslang_lex.cpp
@@ -3797,7 +3797,7 @@
     struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
 
     int token = IDENTIFIER;
-    TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->getShaderVersion());
+    const TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->getShaderVersion());
     if (symbol && symbol->isStruct())
     {
         token = TYPE_NAME;
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index e567197..00809dd 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -310,7 +310,7 @@
             unsigned int u;
             bool b;
         };
-        TSymbol* symbol;
+        const TSymbol* symbol;
     } lex;
     struct {
         TOperator op;
@@ -743,36 +743,36 @@
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   251,   251,   252,   255,   265,   268,   273,   278,   283,
-     288,   297,   303,   306,   309,   312,   315,   318,   324,   331,
-     337,   341,   349,   352,   358,   362,   369,   374,   381,   389,
-     392,   395,   401,   404,   407,   410,   417,   418,   419,   420,
-     428,   429,   432,   435,   442,   443,   446,   452,   453,   457,
-     464,   465,   468,   471,   474,   480,   481,   484,   490,   491,
-     498,   499,   506,   507,   514,   515,   521,   522,   528,   529,
-     535,   536,   542,   543,   549,   550,   551,   552,   556,   557,
-     558,   562,   566,   570,   574,   581,   584,   590,   597,   604,
-     607,   610,   614,   618,   622,   626,   630,   637,   644,   647,
-     654,   662,   679,   689,   692,   698,   702,   706,   710,   717,
-     724,   727,   731,   735,   740,   747,   751,   755,   759,   764,
-     771,   775,   781,   784,   790,   794,   801,   807,   811,   815,
-     818,   821,   830,   835,   839,   842,   845,   848,   851,   855,
-     858,   862,   865,   868,   871,   874,   877,   884,   891,   894,
-     897,   903,   910,   913,   919,   922,   925,   928,   934,   937,
-     944,   949,   956,   961,   972,   975,   978,   981,   984,   987,
-     991,   995,   999,  1003,  1007,  1011,  1015,  1019,  1023,  1027,
-    1031,  1035,  1039,  1043,  1047,  1051,  1055,  1059,  1063,  1067,
-    1071,  1078,  1081,  1084,  1087,  1090,  1093,  1096,  1099,  1102,
-    1105,  1108,  1111,  1114,  1117,  1120,  1123,  1126,  1129,  1132,
-    1142,  1149,  1156,  1159,  1162,  1165,  1168,  1171,  1174,  1177,
-    1180,  1183,  1186,  1189,  1192,  1195,  1198,  1206,  1206,  1209,
-    1209,  1215,  1218,  1224,  1227,  1234,  1238,  1244,  1247,  1253,
-    1257,  1261,  1262,  1268,  1269,  1270,  1271,  1272,  1273,  1274,
-    1278,  1282,  1282,  1282,  1289,  1290,  1294,  1294,  1295,  1295,
-    1300,  1304,  1311,  1315,  1322,  1323,  1327,  1333,  1337,  1346,
-    1346,  1353,  1356,  1362,  1366,  1372,  1372,  1377,  1377,  1381,
-    1381,  1389,  1392,  1398,  1401,  1407,  1411,  1418,  1421,  1424,
-    1427,  1430,  1438,  1444,  1450,  1453,  1459,  1459
+       0,   250,   250,   251,   254,   264,   267,   272,   277,   282,
+     287,   296,   302,   305,   308,   311,   314,   317,   323,   330,
+     336,   340,   348,   351,   357,   361,   368,   373,   380,   388,
+     391,   394,   400,   403,   406,   409,   416,   417,   418,   419,
+     427,   428,   431,   434,   441,   442,   445,   451,   452,   456,
+     463,   464,   467,   470,   473,   479,   480,   483,   489,   490,
+     497,   498,   505,   506,   513,   514,   520,   521,   527,   528,
+     534,   535,   541,   542,   548,   549,   550,   551,   555,   556,
+     557,   561,   565,   569,   573,   580,   583,   589,   596,   603,
+     606,   609,   613,   617,   621,   625,   629,   636,   643,   646,
+     653,   661,   678,   688,   691,   697,   701,   705,   709,   716,
+     723,   726,   730,   734,   739,   746,   750,   754,   758,   763,
+     770,   774,   780,   783,   789,   793,   800,   806,   810,   814,
+     817,   820,   829,   834,   838,   841,   844,   847,   850,   854,
+     857,   861,   864,   867,   870,   873,   876,   883,   890,   893,
+     896,   902,   909,   912,   918,   921,   924,   927,   933,   936,
+     943,   948,   955,   960,   971,   974,   977,   980,   983,   986,
+     990,   994,   998,  1002,  1006,  1010,  1014,  1018,  1022,  1026,
+    1030,  1034,  1038,  1042,  1046,  1050,  1054,  1058,  1062,  1066,
+    1070,  1077,  1080,  1083,  1086,  1089,  1092,  1095,  1098,  1101,
+    1104,  1107,  1110,  1113,  1116,  1119,  1122,  1125,  1128,  1131,
+    1141,  1148,  1155,  1158,  1161,  1164,  1167,  1170,  1173,  1176,
+    1179,  1182,  1185,  1188,  1191,  1194,  1197,  1205,  1205,  1208,
+    1208,  1214,  1217,  1223,  1226,  1233,  1237,  1243,  1246,  1252,
+    1256,  1260,  1261,  1267,  1268,  1269,  1270,  1271,  1272,  1273,
+    1277,  1281,  1281,  1281,  1288,  1289,  1293,  1293,  1294,  1294,
+    1299,  1303,  1310,  1314,  1321,  1322,  1326,  1332,  1336,  1345,
+    1345,  1352,  1355,  1361,  1365,  1371,  1371,  1376,  1376,  1380,
+    1380,  1388,  1391,  1397,  1400,  1406,  1410,  1417,  1420,  1423,
+    1426,  1429,  1437,  1443,  1449,  1452,  1458,  1458
 };
 #endif
 
@@ -4383,7 +4383,7 @@
 
     {
         // This is for user defined type names. The lexical phase looked up the type.
-        TStructure *structure = static_cast<TStructure*>((yyvsp[0].lex).symbol);
+        const TStructure *structure = static_cast<const TStructure*>((yyvsp[0].lex).symbol);
         (yyval.interm.typeSpecifierNonArray).initializeStruct(structure, false, (yylsp[0]));
     }
 
@@ -4912,7 +4912,7 @@
   case 296:
 
     {
-        context->parseFunctionDefinitionHeader((yylsp[0]), &((yyvsp[0].interm).function), &((yyvsp[0].interm).intermFunctionPrototype));
+        context->parseFunctionDefinitionHeader((yylsp[0]), (yyvsp[0].interm).function, &((yyvsp[0].interm).intermFunctionPrototype));
     }
 
     break;
diff --git a/src/compiler/translator/glslang_tab.h b/src/compiler/translator/glslang_tab.h
index ae436c7..048831b 100644
--- a/src/compiler/translator/glslang_tab.h
+++ b/src/compiler/translator/glslang_tab.h
@@ -221,7 +221,7 @@
             unsigned int u;
             bool b;
         };
-        TSymbol* symbol;
+        const TSymbol *symbol;
     } lex;
     struct {
         TOperator op;