Fix linkage.html failures on Mac.

The failure is due to when we initialize variables to 0, we re-create
the struct TType, and it contains a different unique id from the
original struct TType, thus leading to a different hashed name.

BUG=chromium:641129
TEST=webgl_conformance,webgl2_conformance

Change-Id: I267b97fa496f55ea59dacee93af8f6a90f3e66cb
Reviewed-on: https://chromium-review.googlesource.com/409602
Commit-Queue: Zhenyao Mo <zmo@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 53b021a..e085ed5 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -918,7 +918,7 @@
     sh::ShaderVariable var(GL_FLOAT_VEC4, 0);
     var.name = "gl_Position";
     list.push_back(var);
-    InitializeVariables(root, list);
+    InitializeVariables(root, list, symbolTable);
 }
 
 void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermNode *root)
@@ -934,7 +934,7 @@
         }
     }
 
-    sh::UseInterfaceBlockFields(root, list);
+    sh::UseInterfaceBlockFields(root, list, symbolTable);
 }
 
 void TCompiler::initializeOutputVariables(TIntermNode *root)
@@ -955,7 +955,7 @@
             list.push_back(var);
         }
     }
-    InitializeVariables(root, list);
+    InitializeVariables(root, list, symbolTable);
 }
 
 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
diff --git a/src/compiler/translator/InitializeVariables.cpp b/src/compiler/translator/InitializeVariables.cpp
index 576b64c..dafea1b 100644
--- a/src/compiler/translator/InitializeVariables.cpp
+++ b/src/compiler/translator/InitializeVariables.cpp
@@ -9,6 +9,7 @@
 #include "angle_gl.h"
 #include "common/debug.h"
 #include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/util.h"
 
 namespace sh
@@ -20,9 +21,13 @@
 class VariableInitializer : public TIntermTraverser
 {
   public:
-    VariableInitializer(const InitVariableList &vars)
-        : TIntermTraverser(true, false, false), mVariables(vars), mCodeInserted(false)
+    VariableInitializer(const InitVariableList &vars, const TSymbolTable &symbolTable)
+        : TIntermTraverser(true, false, false),
+          mVariables(vars),
+          mSymbolTable(symbolTable),
+          mCodeInserted(false)
     {
+        ASSERT(mSymbolTable.atGlobalLevel());
     }
 
   protected:
@@ -39,6 +44,7 @@
     void insertInitCode(TIntermSequence *sequence);
 
     const InitVariableList &mVariables;
+    const TSymbolTable &mSymbolTable;
     bool mCodeInserted;
 };
 
@@ -62,23 +68,23 @@
     for (const auto &var : mVariables)
     {
         TString name = TString(var.name.c_str());
-        TType type   = sh::GetShaderVariableType(var);
 
-        // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
-        // doesn't have array assignment.
         if (var.isArray())
         {
+            // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
+            // doesn't have array assignment.
             size_t pos = name.find_last_of('[');
             if (pos != TString::npos)
             {
                 name = name.substr(0, pos);
             }
-            TType elementType = type;
-            elementType.clearArrayness();
+            TType elementType = sh::GetShaderVariableBasicType(var);
+            TType arrayType   = elementType;
+            arrayType.setArraySize(var.elementCount());
 
             for (unsigned int i = 0; i < var.arraySize; ++i)
             {
-                TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
+                TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, arrayType);
                 TIntermBinary *element     = new TIntermBinary(EOpIndexDirect, arraySymbol,
                                                            TIntermTyped::CreateIndexNode(i));
 
@@ -88,8 +94,20 @@
                 sequence->insert(sequence->begin(), assignment);
             }
         }
+        else if (var.isStruct())
+        {
+            TVariable *structInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
+            ASSERT(structInfo);
+
+            TIntermSymbol *symbol = new TIntermSymbol(0, name, structInfo->getType());
+            TIntermTyped *zero    = TIntermTyped::CreateZero(structInfo->getType());
+
+            TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
+            sequence->insert(sequence->begin(), assign);
+        }
         else
         {
+            TType type            = sh::GetShaderVariableBasicType(var);
             TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
             TIntermTyped *zero    = TIntermTyped::CreateZero(type);
 
@@ -101,9 +119,11 @@
 
 }  // namespace anonymous
 
-void InitializeVariables(TIntermNode *root, const InitVariableList &vars)
+void InitializeVariables(TIntermNode *root,
+                         const InitVariableList &vars,
+                         const TSymbolTable &symbolTable)
 {
-    VariableInitializer initializer(vars);
+    VariableInitializer initializer(vars, symbolTable);
     root->traverse(&initializer);
 }
 
diff --git a/src/compiler/translator/InitializeVariables.h b/src/compiler/translator/InitializeVariables.h
index 8083577..9a34245 100644
--- a/src/compiler/translator/InitializeVariables.h
+++ b/src/compiler/translator/InitializeVariables.h
@@ -12,11 +12,20 @@
 namespace sh
 {
 class TIntermNode;
+class TSymbolTable;
 
 typedef std::vector<sh::ShaderVariable> InitVariableList;
 
-// This function cannot currently initialize structures containing arrays for an ESSL 1.00 backend.
-void InitializeVariables(TIntermNode *root, const InitVariableList &vars);
+// Currently this function is only capable of initializing variables of basic types,
+// array of basic types, or struct of basic types.
+// For now it is used for the following two scenarios:
+//   1. initializing gl_Position;
+//   2. initializing ESSL 3.00 shaders' output variables (which might be structs).
+// Specifically, it's not feasible to make it work for local variables because if their
+// types are structs, we can't look into TSymbolTable to find the TType data.
+void InitializeVariables(TIntermNode *root,
+                         const InitVariableList &vars,
+                         const TSymbolTable &symbolTable);
 }  // namespace sh
 
 #endif  // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
diff --git a/src/compiler/translator/SymbolTable.cpp b/src/compiler/translator/SymbolTable.cpp
index 34ef025..188f810 100644
--- a/src/compiler/translator/SymbolTable.cpp
+++ b/src/compiler/translator/SymbolTable.cpp
@@ -126,6 +126,12 @@
     return symbol;
 }
 
+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
 {
diff --git a/src/compiler/translator/SymbolTable.h b/src/compiler/translator/SymbolTable.h
index 439d6b4..7c4d3aa 100644
--- a/src/compiler/translator/SymbolTable.h
+++ b/src/compiler/translator/SymbolTable.h
@@ -459,8 +459,11 @@
 
     TSymbol *find(const TString &name, int shaderVersion,
                   bool *builtIn = NULL, bool *sameScope = NULL) const;
+
+    TSymbol *findGlobal(const TString &name) const;
+
     TSymbol *findBuiltIn(const TString &name, int shaderVersion) const;
-    
+
     TSymbolTableLevel *getOuterLevel()
     {
         assert(currentLevel() >= 1);
diff --git a/src/compiler/translator/UseInterfaceBlockFields.cpp b/src/compiler/translator/UseInterfaceBlockFields.cpp
index 2a1a812..390e2b0 100644
--- a/src/compiler/translator/UseInterfaceBlockFields.cpp
+++ b/src/compiler/translator/UseInterfaceBlockFields.cpp
@@ -11,6 +11,7 @@
 #include "compiler/translator/UseInterfaceBlockFields.h"
 
 #include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/util.h"
 
 namespace sh
@@ -22,9 +23,13 @@
 class UseUniformBlockMembers : public TIntermTraverser
 {
   public:
-    UseUniformBlockMembers(const InterfaceBlockList &blocks)
-        : TIntermTraverser(true, false, false), mBlocks(blocks), mCodeInserted(false)
+    UseUniformBlockMembers(const InterfaceBlockList &blocks, const TSymbolTable &symbolTable)
+        : TIntermTraverser(true, false, false),
+          mBlocks(blocks),
+          mSymbolTable(symbolTable),
+          mCodeInserted(false)
     {
+        ASSERT(mSymbolTable.atGlobalLevel());
     }
 
   protected:
@@ -36,6 +41,7 @@
     void AddFieldUseStatements(const ShaderVariable &var, TIntermSequence *sequence);
 
     const InterfaceBlockList &mBlocks;
+    const TSymbolTable &mSymbolTable;
     bool mCodeInserted;
 };
 
@@ -57,8 +63,6 @@
                                                    TIntermSequence *sequence)
 {
     TString name = TString(var.name.c_str());
-    TType type   = GetShaderVariableType(var);
-
     if (var.isArray())
     {
         size_t pos = name.find_last_of('[');
@@ -66,33 +70,35 @@
         {
             name = name.substr(0, pos);
         }
-        TType elementType = type;
-        elementType.clearArrayness();
+    }
+    const TType *type;
+    TType basicType;
+    if (var.isStruct())
+    {
+        TVariable *structInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
+        ASSERT(structInfo);
+        const TType &structType = structInfo->getType();
+        type                    = &structType;
+    }
+    else
+    {
+        basicType = sh::GetShaderVariableBasicType(var);
+        type      = &basicType;
+    }
+    ASSERT(type);
 
-        TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
+    TIntermSymbol *symbol = new TIntermSymbol(0, name, *type);
+    if (var.isArray())
+    {
         for (unsigned int i = 0; i < var.arraySize; ++i)
         {
             TIntermBinary *element =
-                new TIntermBinary(EOpIndexDirect, arraySymbol, TIntermTyped::CreateIndexNode(i));
-
-            sequence->insert(sequence->begin(), element);
-        }
-    }
-    else if (var.isStruct())
-    {
-        TIntermSymbol *structSymbol = new TIntermSymbol(0, name, type);
-        for (unsigned int i = 0; i < var.fields.size(); ++i)
-        {
-            TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct, structSymbol,
-                                                       TIntermTyped::CreateIndexNode(i));
-
+                new TIntermBinary(EOpIndexDirect, symbol, TIntermTyped::CreateIndexNode(i));
             sequence->insert(sequence->begin(), element);
         }
     }
     else
     {
-        TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
-
         sequence->insert(sequence->begin(), symbol);
     }
 }
@@ -110,9 +116,10 @@
         }
         else if (block.arraySize > 0)
         {
-            TType type                 = GetInterfaceBlockType(block);
-            TString name               = TString(block.instanceName.c_str());
-            TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
+            TString name      = TString(block.instanceName.c_str());
+            TVariable *ubInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
+            ASSERT(ubInfo);
+            TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, ubInfo->getType());
             for (unsigned int i = 0; i < block.arraySize; ++i)
             {
                 TIntermBinary *instanceSymbol = new TIntermBinary(EOpIndexDirect, arraySymbol,
@@ -128,9 +135,10 @@
         }
         else
         {
-            TType type                 = GetInterfaceBlockType(block);
-            TString name               = TString(block.instanceName.c_str());
-            TIntermSymbol *blockSymbol = new TIntermSymbol(0, name, type);
+            TString name      = TString(block.instanceName.c_str());
+            TVariable *ubInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
+            ASSERT(ubInfo);
+            TIntermSymbol *blockSymbol = new TIntermSymbol(0, name, ubInfo->getType());
             for (unsigned int i = 0; i < block.fields.size(); ++i)
             {
                 TIntermBinary *element = new TIntermBinary(
@@ -144,9 +152,11 @@
 
 }  // namespace anonymous
 
-void UseInterfaceBlockFields(TIntermNode *root, const InterfaceBlockList &blocks)
+void UseInterfaceBlockFields(TIntermNode *root,
+                             const InterfaceBlockList &blocks,
+                             const TSymbolTable &symbolTable)
 {
-    UseUniformBlockMembers useUniformBlock(blocks);
+    UseUniformBlockMembers useUniformBlock(blocks, symbolTable);
     root->traverse(&useUniformBlock);
 }
 
diff --git a/src/compiler/translator/UseInterfaceBlockFields.h b/src/compiler/translator/UseInterfaceBlockFields.h
index 024bfd4..a789bb7 100644
--- a/src/compiler/translator/UseInterfaceBlockFields.h
+++ b/src/compiler/translator/UseInterfaceBlockFields.h
@@ -17,9 +17,14 @@
 namespace sh
 {
 
+class TSymbolTable;
+
 using InterfaceBlockList = std::vector<sh::InterfaceBlock>;
 
-void UseInterfaceBlockFields(TIntermNode *root, const InterfaceBlockList &blocks);
+void UseInterfaceBlockFields(TIntermNode *root,
+                             const InterfaceBlockList &blocks,
+                             const TSymbolTable &symbolTable);
+
 }  // namespace sh
 
 #endif  // COMPILER_TRANSLATOR_USEINTERFACEBLOCKFIELDS_H_
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
index 54a1a2c..89f237c 100644
--- a/src/compiler/translator/util.cpp
+++ b/src/compiler/translator/util.cpp
@@ -302,27 +302,6 @@
     }
 }
 
-TType GetInterfaceBlockType(const sh::InterfaceBlock &block)
-{
-    TType type;
-    TFieldList *fields = new TFieldList;
-    TSourceLoc loc;
-    for (const auto &field : block.fields)
-    {
-        TType *fieldType = new TType(GetShaderVariableType(field));
-        fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc));
-    }
-
-    TInterfaceBlock *interfaceBlock = new TInterfaceBlock(
-        new TString(block.name.c_str()), fields, new TString(block.instanceName.c_str()),
-        block.arraySize, TLayoutQualifier::create());
-
-    type.setBasicType(EbtInterfaceBlock);
-    type.setInterfaceBlock(interfaceBlock);
-    type.setArraySize(block.arraySize);
-    return type;
-}
-
 TType GetShaderVariableBasicType(const sh::ShaderVariable &var)
 {
     switch (var.type)
@@ -383,35 +362,6 @@
     }
 }
 
-TType GetShaderVariableType(const sh::ShaderVariable &var)
-{
-    TType type;
-    if (var.isStruct())
-    {
-        TFieldList *fields = new TFieldList;
-        TSourceLoc loc;
-        for (const auto &field : var.fields)
-        {
-            TType *fieldType = new TType(GetShaderVariableType(field));
-            fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc));
-        }
-        TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields);
-
-        type.setBasicType(EbtStruct);
-        type.setStruct(structure);
-    }
-    else
-    {
-        type = GetShaderVariableBasicType(var);
-    }
-
-    if (var.isArray())
-    {
-        type.setArraySize(var.elementCount());
-    }
-    return type;
-}
-
 TOperator TypeToConstructorOperator(const TType &type)
 {
     switch (type.getBasicType())
diff --git a/src/compiler/translator/util.h b/src/compiler/translator/util.h
index ce8bd9d..bfad5fb 100644
--- a/src/compiler/translator/util.h
+++ b/src/compiler/translator/util.h
@@ -37,9 +37,7 @@
 InterpolationType GetInterpolationType(TQualifier qualifier);
 TString ArrayString(const TType &type);
 
-TType GetInterfaceBlockType(const sh::InterfaceBlock &block);
 TType GetShaderVariableBasicType(const sh::ShaderVariable &var);
-TType GetShaderVariableType(const sh::ShaderVariable &var);
 
 TOperator TypeToConstructorOperator(const TType &type);