TType: Store array sizes vector as a pointer.

This makes TType a literal type, and thus is something that could be
constexpr.

Work started by jmadill here: https://crrev.com/c/776278

Bug: angleproject:1432
Change-Id: I707ddf81eaf029f49d62d2836b7166d265cbdfa1
Reviewed-on: https://chromium-review.googlesource.com/786316
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/CollectVariables.cpp b/src/compiler/translator/CollectVariables.cpp
index 1fa86bb..bd8cbc9 100644
--- a/src/compiler/translator/CollectVariables.cpp
+++ b/src/compiler/translator/CollectVariables.cpp
@@ -262,8 +262,11 @@
     info->name       = name;
     info->mappedName = name;
     info->type       = GLVariableType(type);
-    info->arraySizes.assign(type.getArraySizes().begin(), type.getArraySizes().end());
     info->precision = GLVariablePrecision(type);
+    if (auto *arraySizes = type.getArraySizes())
+    {
+        info->arraySizes.assign(arraySizes->begin(), arraySizes->end());
+    }
 }
 
 void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name,
@@ -581,7 +584,10 @@
     variableOut->name       = name.getString().c_str();
     variableOut->mappedName = getMappedName(name);
 
-    variableOut->arraySizes.assign(type.getArraySizes().begin(), type.getArraySizes().end());
+    if (auto *arraySizes = type.getArraySizes())
+    {
+        variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end());
+    }
 }
 
 Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index bb18beb..d5ff761 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -38,9 +38,12 @@
 {
     TStringStream fnName;
     fnName << prefix << "_";
-    for (unsigned int arraySize : type.getArraySizes())
+    if (type.isArray())
     {
-        fnName << arraySize << "_";
+        for (unsigned int arraySize : *type.getArraySizes())
+        {
+            fnName << arraySize << "_";
+        }
     }
     fnName << TypeString(type);
     return fnName.str();
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 67207ca..c97f91d 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1928,7 +1928,8 @@
         // will default to setting array sizes to 1. We have not checked yet whether the initializer
         // actually is an array or not. Having a non-array initializer for an unsized array will
         // result in an error later, so we don't generate an error message here.
-        type.sizeUnsizedArrays(initializer->getType().getArraySizes());
+        auto *arraySizes = initializer->getType().getArraySizes();
+        type.sizeUnsizedArrays(arraySizes);
     }
     if (!declareVariable(line, identifier, type, &variable))
     {
@@ -3493,7 +3494,7 @@
     if (arrayType->isUnsizedArray())
     {
         error(line, errorMessage, token);
-        arrayType->sizeUnsizedArrays(TVector<unsigned int>());
+        arrayType->sizeUnsizedArrays(nullptr);
     }
 }
 
@@ -3546,13 +3547,13 @@
     {
         TIntermTyped *element = arg->getAsTyped();
         ASSERT(element);
-        size_t dimensionalityFromElement = element->getType().getArraySizes().size() + 1u;
-        if (dimensionalityFromElement > type.getArraySizes().size())
+        size_t dimensionalityFromElement = element->getType().getNumArraySizes() + 1u;
+        if (dimensionalityFromElement > type.getNumArraySizes())
         {
             error(line, "constructing from a non-dereferenced array", "constructor");
             return false;
         }
-        else if (dimensionalityFromElement < type.getArraySizes().size())
+        else if (dimensionalityFromElement < type.getNumArraySizes())
         {
             if (dimensionalityFromElement == 1u)
             {
@@ -3585,7 +3586,7 @@
     {
         if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line))
         {
-            type.sizeUnsizedArrays(TVector<unsigned int>());
+            type.sizeUnsizedArrays(nullptr);
             return CreateZeroNode(type);
         }
         TIntermTyped *firstElement = arguments->at(0)->getAsTyped();
@@ -3594,11 +3595,11 @@
         {
             type.sizeOutermostUnsizedArray(static_cast<unsigned int>(arguments->size()));
         }
-        for (size_t i = 0; i < firstElement->getType().getArraySizes().size(); ++i)
+        for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i)
         {
-            if (type.getArraySizes()[i] == 0u)
+            if ((*type.getArraySizes())[i] == 0u)
             {
-                type.setArraySize(i, firstElement->getType().getArraySizes().at(i));
+                type.setArraySize(i, (*firstElement->getType().getArraySizes())[i]);
             }
         }
         ASSERT(!type.isUnsizedArray());
@@ -4758,18 +4759,22 @@
 
     for (TField *declarator : *declaratorList)
     {
-        auto declaratorArraySizes = declarator->type()->getArraySizes();
         // Don't allow arrays of arrays in ESSL < 3.10.
-        if (!declaratorArraySizes.empty())
+        if (declarator->type()->isArray())
         {
             checkArrayElementIsNotArray(typeSpecifier.getLine(), typeSpecifier);
         }
 
+        auto *declaratorArraySizes = declarator->type()->getArraySizes();
+
         TType *type = declarator->type();
         *type       = TType(typeSpecifier);
-        for (unsigned int arraySize : declaratorArraySizes)
+        if (declaratorArraySizes != nullptr)
         {
-            type->makeArray(arraySize);
+            for (unsigned int arraySize : *declaratorArraySizes)
+            {
+                type->makeArray(arraySize);
+            }
         }
 
         checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *declarator);
@@ -5062,20 +5067,21 @@
         }
     }
 
-    if (left->isArray() || right->isArray())
+    if (left->isArray() != right->isArray())
     {
+        error(loc, "array / non-array mismatch", GetOperatorString(op));
+        return false;
+    }
+
+    if (left->isArray())
+    {
+        ASSERT(right->isArray());
         if (mShaderVersion < 300)
         {
             error(loc, "Invalid operation for arrays", GetOperatorString(op));
             return false;
         }
 
-        if (left->isArray() != right->isArray())
-        {
-            error(loc, "array / non-array mismatch", GetOperatorString(op));
-            return false;
-        }
-
         switch (op)
         {
             case EOpEqual:
@@ -5088,7 +5094,7 @@
                 return false;
         }
         // At this point, size of implicitly sized arrays should be resolved.
-        if (left->getType().getArraySizes() != right->getType().getArraySizes())
+        if (*left->getType().getArraySizes() != *right->getType().getArraySizes())
         {
             error(loc, "array size mismatch", GetOperatorString(op));
             return false;
diff --git a/src/compiler/translator/Types.cpp b/src/compiler/translator/Types.cpp
index d59a3d8..530ffe3 100644
--- a/src/compiler/translator/Types.cpp
+++ b/src/compiler/translator/Types.cpp
@@ -123,6 +123,7 @@
       layoutQualifier(TLayoutQualifier::Create()),
       primarySize(0),
       secondarySize(0),
+      mArraySizes(nullptr),
       mInterfaceBlock(nullptr),
       mStructure(nullptr),
       mIsStructSpecifier(false),
@@ -139,8 +140,9 @@
       layoutQualifier(TLayoutQualifier::Create()),
       primarySize(ps),
       secondarySize(ss),
-      mInterfaceBlock(0),
-      mStructure(0),
+      mArraySizes(nullptr),
+      mInterfaceBlock(nullptr),
+      mStructure(nullptr),
       mIsStructSpecifier(false),
       mMangledName(nullptr)
 {
@@ -155,8 +157,9 @@
       layoutQualifier(TLayoutQualifier::Create()),
       primarySize(ps),
       secondarySize(ss),
-      mInterfaceBlock(0),
-      mStructure(0),
+      mArraySizes(nullptr),
+      mInterfaceBlock(nullptr),
+      mStructure(nullptr),
       mIsStructSpecifier(false),
       mMangledName(nullptr)
 {
@@ -171,6 +174,7 @@
       layoutQualifier(p.layoutQualifier),
       primarySize(p.getPrimarySize()),
       secondarySize(p.getSecondarySize()),
+      mArraySizes(nullptr),
       mInterfaceBlock(nullptr),
       mStructure(nullptr),
       mIsStructSpecifier(false),
@@ -180,7 +184,7 @@
     ASSERT(secondarySize <= 4);
     if (p.isArray())
     {
-        mArraySizes = *p.arraySizes;
+        mArraySizes = new TVector<unsigned int>(*p.arraySizes);
     }
     if (p.getUserDef())
     {
@@ -198,6 +202,7 @@
       layoutQualifier(TLayoutQualifier::Create()),
       primarySize(1),
       secondarySize(1),
+      mArraySizes(nullptr),
       mInterfaceBlock(nullptr),
       mStructure(userDef),
       mIsStructSpecifier(false),
@@ -216,6 +221,7 @@
       layoutQualifier(layoutQualifierIn),
       primarySize(1),
       secondarySize(1),
+      mArraySizes(nullptr),
       mInterfaceBlock(interfaceBlockIn),
       mStructure(0),
       mIsStructSpecifier(false),
@@ -223,12 +229,41 @@
 {
 }
 
-TType::TType(const TType &) = default;
-
-TType::~TType()
+TType::TType(const TType &t)
+    : type(t.type),
+      precision(t.precision),
+      qualifier(t.qualifier),
+      invariant(t.invariant),
+      memoryQualifier(t.memoryQualifier),
+      layoutQualifier(t.layoutQualifier),
+      primarySize(t.primarySize),
+      secondarySize(t.secondarySize),
+      mArraySizes(t.mArraySizes ? new TVector<unsigned int>(*t.mArraySizes) : nullptr),
+      mInterfaceBlock(t.mInterfaceBlock),
+      mStructure(t.mStructure),
+      mIsStructSpecifier(t.mIsStructSpecifier),
+      mMangledName(t.mMangledName)
 {
 }
 
+TType &TType::operator=(const TType &t)
+{
+    type               = t.type;
+    precision          = t.precision;
+    qualifier          = t.qualifier;
+    invariant          = t.invariant;
+    memoryQualifier    = t.memoryQualifier;
+    layoutQualifier    = t.layoutQualifier;
+    primarySize        = t.primarySize;
+    secondarySize      = t.secondarySize;
+    mArraySizes        = t.mArraySizes ? new TVector<unsigned int>(*t.mArraySizes) : nullptr;
+    mInterfaceBlock    = t.mInterfaceBlock;
+    mStructure         = t.mStructure;
+    mIsStructSpecifier = t.mIsStructSpecifier;
+    mMangledName       = t.mMangledName;
+    return *this;
+}
+
 bool TType::canBeConstructed() const
 {
     switch (type)
@@ -370,10 +405,13 @@
         stream << getQualifierString() << " ";
     if (precision != EbpUndefined)
         stream << getPrecisionString() << " ";
-    for (auto arraySizeIter = mArraySizes.rbegin(); arraySizeIter != mArraySizes.rend();
-         ++arraySizeIter)
+    if (mArraySizes)
     {
-        stream << "array[" << (*arraySizeIter) << "] of ";
+        for (auto arraySizeIter = mArraySizes->rbegin(); arraySizeIter != mArraySizes->rend();
+             ++arraySizeIter)
+        {
+            stream << "array[" << (*arraySizeIter) << "] of ";
+        }
     }
     if (isMatrix())
         stream << getCols() << "X" << getRows() << " matrix of ";
@@ -536,13 +574,16 @@
         mangledName += static_cast<char>('0' + getNominalSize());
     }
 
-    for (unsigned int arraySize : mArraySizes)
+    if (mArraySizes)
     {
-        char buf[20];
-        snprintf(buf, sizeof(buf), "%d", arraySize);
-        mangledName += '[';
-        mangledName += buf;
-        mangledName += ']';
+        for (unsigned int arraySize : *mArraySizes)
+        {
+            char buf[20];
+            snprintf(buf, sizeof(buf), "%d", arraySize);
+            mangledName += '[';
+            mangledName += buf;
+            mangledName += ']';
+        }
     }
 
     mangledName += ';';
@@ -566,12 +607,15 @@
     if (totalSize == 0)
         return 0;
 
-    for (size_t arraySize : mArraySizes)
+    if (mArraySizes)
     {
-        if (arraySize > INT_MAX / totalSize)
-            totalSize = INT_MAX;
-        else
-            totalSize *= arraySize;
+        for (size_t arraySize : *mArraySizes)
+        {
+            if (arraySize > INT_MAX / totalSize)
+                totalSize = INT_MAX;
+            else
+                totalSize *= arraySize;
+        }
     }
 
     return totalSize;
@@ -591,15 +635,18 @@
         return 0;
     }
 
-    for (unsigned int arraySize : mArraySizes)
+    if (mArraySizes)
     {
-        if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count))
+        for (unsigned int arraySize : *mArraySizes)
         {
-            count = std::numeric_limits<int>::max();
-        }
-        else
-        {
-            count *= static_cast<int>(arraySize);
+            if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count))
+            {
+                count = std::numeric_limits<int>::max();
+            }
+            else
+            {
+                count *= static_cast<int>(arraySize);
+            }
         }
     }
 
@@ -608,8 +655,12 @@
 
 unsigned int TType::getArraySizeProduct() const
 {
+    if (!mArraySizes)
+        return 1u;
+
     unsigned int product = 1u;
-    for (unsigned int arraySize : mArraySizes)
+
+    for (unsigned int arraySize : *mArraySizes)
     {
         product *= arraySize;
     }
@@ -618,7 +669,10 @@
 
 bool TType::isUnsizedArray() const
 {
-    for (unsigned int arraySize : mArraySizes)
+    if (!mArraySizes)
+        return false;
+
+    for (unsigned int arraySize : *mArraySizes)
     {
         if (arraySize == 0u)
         {
@@ -640,33 +694,38 @@
     {
         return false;
     }
-    if (arrayType.mArraySizes.size() != mArraySizes.size() + 1u)
+    if (arrayType.getNumArraySizes() != getNumArraySizes() + 1u)
     {
         return false;
     }
-    for (size_t i = 0; i < mArraySizes.size(); ++i)
+    if (isArray())
     {
-        if (mArraySizes[i] != arrayType.mArraySizes[i])
+        for (size_t i = 0; i < mArraySizes->size(); ++i)
         {
-            return false;
+            if ((*mArraySizes)[i] != (*arrayType.mArraySizes)[i])
+            {
+                return false;
+            }
         }
     }
     return true;
 }
 
-void TType::sizeUnsizedArrays(const TVector<unsigned int> &arraySizes)
+void TType::sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes)
 {
-    for (size_t i = 0u; i < mArraySizes.size(); ++i)
+    size_t newArraySizesSize = newArraySizes ? newArraySizes->size() : 0;
+    for (size_t i = 0u; i < getNumArraySizes(); ++i)
     {
-        if (mArraySizes[i] == 0)
+        if ((*mArraySizes)[i] == 0)
         {
-            if (i < arraySizes.size())
+            if (i < newArraySizesSize)
             {
-                mArraySizes[i] = arraySizes[i];
+                ASSERT(newArraySizes != nullptr);
+                (*mArraySizes)[i] = (*newArraySizes)[i];
             }
             else
             {
-                mArraySizes[i] = 1u;
+                (*mArraySizes)[i] = 1u;
             }
         }
     }
@@ -676,8 +735,8 @@
 void TType::sizeOutermostUnsizedArray(unsigned int arraySize)
 {
     ASSERT(isArray());
-    ASSERT(mArraySizes.back() == 0u);
-    mArraySizes.back() = arraySize;
+    ASSERT(mArraySizes->back() == 0u);
+    mArraySizes->back() = arraySize;
 }
 
 void TType::setBasicType(TBasicType t)
@@ -711,31 +770,39 @@
 
 void TType::makeArray(unsigned int s)
 {
-    mArraySizes.push_back(s);
+    if (!mArraySizes)
+        mArraySizes = new TVector<unsigned int>();
+
+    mArraySizes->push_back(s);
     invalidateMangledName();
 }
 
 void TType::makeArrays(const TVector<unsigned int> &sizes)
 {
-    mArraySizes.insert(mArraySizes.end(), sizes.begin(), sizes.end());
+    if (!mArraySizes)
+        mArraySizes = new TVector<unsigned int>();
+
+    mArraySizes->insert(mArraySizes->end(), sizes.begin(), sizes.end());
     invalidateMangledName();
 }
 
 void TType::setArraySize(size_t arrayDimension, unsigned int s)
 {
-    ASSERT(arrayDimension < mArraySizes.size());
-    if (mArraySizes.at(arrayDimension) != s)
+    ASSERT(mArraySizes != nullptr);
+    ASSERT(arrayDimension < mArraySizes->size());
+    if (mArraySizes->at(arrayDimension) != s)
     {
-        mArraySizes[arrayDimension] = s;
+        (*mArraySizes)[arrayDimension] = s;
         invalidateMangledName();
     }
 }
 
 void TType::toArrayElementType()
 {
-    if (mArraySizes.size() > 0)
+    ASSERT(mArraySizes != nullptr);
+    if (mArraySizes->size() > 0)
     {
-        mArraySizes.pop_back();
+        mArraySizes->pop_back();
         invalidateMangledName();
     }
 }
diff --git a/src/compiler/translator/Types.h b/src/compiler/translator/Types.h
index 63d6242..7dc84c5 100644
--- a/src/compiler/translator/Types.h
+++ b/src/compiler/translator/Types.h
@@ -194,10 +194,8 @@
     TType(TInterfaceBlock *interfaceBlockIn,
           TQualifier qualifierIn,
           TLayoutQualifier layoutQualifierIn);
-    ~TType();
-
-    TType(const TType &);
-    TType &operator=(const TType &) = default;
+    TType(const TType &t);
+    TType &operator=(const TType &t);
 
     TBasicType getBasicType() const { return type; }
     void setBasicType(TBasicType t);
@@ -241,22 +239,27 @@
 
     bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
     bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; }
-    bool isArray() const { return !mArraySizes.empty(); }
-    bool isArrayOfArrays() const { return mArraySizes.size() > 1u; }
-    const TVector<unsigned int> &getArraySizes() const { return mArraySizes; }
+    bool isArray() const { return mArraySizes != nullptr && !mArraySizes->empty(); }
+    bool isArrayOfArrays() const { return isArray() && mArraySizes->size() > 1u; }
+    size_t getNumArraySizes() const { return isArray() ? mArraySizes->size() : 0; }
+    const TVector<unsigned int> *getArraySizes() const { return mArraySizes; }
     unsigned int getArraySizeProduct() const;
     bool isUnsizedArray() const;
-    unsigned int getOutermostArraySize() const { return mArraySizes.back(); }
-
+    unsigned int getOutermostArraySize() const {
+         ASSERT(isArray());
+         return mArraySizes->back();
+    }
     void makeArray(unsigned int s);
+
     // sizes contain new outermost array sizes.
     void makeArrays(const TVector<unsigned int> &sizes);
     // Here, the array dimension value 0 corresponds to the innermost array.
     void setArraySize(size_t arrayDimension, unsigned int s);
 
-    // Will set unsized array sizes according to arraySizes. In case there are more unsized arrays
-    // than there are sizes in arraySizes, defaults to setting array sizes to 1.
-    void sizeUnsizedArrays(const TVector<unsigned int> &arraySizes);
+    // Will set unsized array sizes according to newArraySizes. In case there are more
+    // unsized arrays than there are sizes in newArraySizes, defaults to setting any
+    // remaining array sizes to 1.
+    void sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes);
 
     // Will size the outermost array according to arraySize.
     void sizeOutermostUnsizedArray(unsigned int arraySize);
@@ -291,8 +294,12 @@
 
     bool operator==(const TType &right) const
     {
+        size_t numArraySizesL = getNumArraySizes();
+        size_t numArraySizesR = right.getNumArraySizes();
+        bool arraySizesEqual  = numArraySizesL == numArraySizesR &&
+                               (numArraySizesL == 0 || *mArraySizes == *right.mArraySizes);
         return type == right.type && primarySize == right.primarySize &&
-               secondarySize == right.secondarySize && mArraySizes == right.mArraySizes &&
+               secondarySize == right.secondarySize && arraySizesEqual &&
                mStructure == right.mStructure;
         // don't check the qualifier, it's not ever what's being sought after
     }
@@ -305,12 +312,14 @@
             return primarySize < right.primarySize;
         if (secondarySize != right.secondarySize)
             return secondarySize < right.secondarySize;
-        if (mArraySizes.size() != right.mArraySizes.size())
-            return mArraySizes.size() < right.mArraySizes.size();
-        for (size_t i = 0; i < mArraySizes.size(); ++i)
+        size_t numArraySizesL = getNumArraySizes();
+        size_t numArraySizesR = right.getNumArraySizes();
+        if (numArraySizesL != numArraySizesR)
+            return numArraySizesL < numArraySizesR;
+        for (size_t i = 0; i < numArraySizesL; ++i)
         {
-            if (mArraySizes[i] != right.mArraySizes[i])
-                return mArraySizes[i] < right.mArraySizes[i];
+            if ((*mArraySizes)[i] != (*right.mArraySizes)[i])
+                return (*mArraySizes)[i] < (*right.mArraySizes)[i];
         }
         if (mStructure != right.mStructure)
             return mStructure < right.mStructure;
@@ -384,7 +393,7 @@
 
     // Used to make an array type. Outermost array size is stored at the end of the vector. Having 0
     // in this vector means an unsized array.
-    TVector<unsigned int> mArraySizes;
+    TVector<unsigned int> *mArraySizes;
 
     // This is set only in the following two cases:
     // 1) Represents an interface block.
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
index fdd04cb..9738370 100644
--- a/src/compiler/translator/util.cpp
+++ b/src/compiler/translator/util.cpp
@@ -456,7 +456,10 @@
 TString ArrayString(const TType &type)
 {
     TStringStream arrayString;
-    const TVector<unsigned int> &arraySizes = type.getArraySizes();
+    if (!type.isArray())
+        return arrayString.str();
+
+    const TVector<unsigned int> &arraySizes = *type.getArraySizes();
     for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend();
          ++arraySizeIter)
     {