Add a constexpr constructor for TFunction

Access to TFunction parameters is now handled through two new members:
a pointer to a parameter array and a parameter count.

There's still also a vector pointer in TFunction for adding function
parameters one by one. This is used when parsing user-defined
functions.

TEST=angle_unittests
BUG=angleproject:2267

Change-Id: I86987ae56b7cf37f010d0651e9861789050aec2b
Reviewed-on: https://chromium-review.googlesource.com/923987
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
index 5111aaa..b981f8b 100644
--- a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
+++ b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -127,8 +127,8 @@
                 new TVariable(mSymbolTable, kReturnValueVariableName, returnValueVariableType,
                               SymbolType::AngleInternal);
             TFunction *func = new TFunction(mSymbolTable, node->getFunction()->name(),
-                                            StaticType::GetBasic<EbtVoid>(),
-                                            node->getFunction()->symbolType(), false);
+                                            node->getFunction()->symbolType(),
+                                            StaticType::GetBasic<EbtVoid>(), false);
             for (size_t i = 0; i < node->getFunction()->getParamCount(); ++i)
             {
                 func->addParameter(node->getFunction()->getParam(i));
diff --git a/src/compiler/translator/DeferGlobalInitializers.cpp b/src/compiler/translator/DeferGlobalInitializers.cpp
index 1704d41..0e14054 100644
--- a/src/compiler/translator/DeferGlobalInitializers.cpp
+++ b/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -22,6 +22,7 @@
 #include "compiler/translator/IntermNode.h"
 #include "compiler/translator/IntermNode_util.h"
 #include "compiler/translator/ReplaceVariable.h"
+#include "compiler/translator/StaticType.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
@@ -104,8 +105,9 @@
     TIntermBlock *initGlobalsBlock = new TIntermBlock();
     initGlobalsBlock->getSequence()->swap(*deferredInitializers);
 
-    TFunction *initGlobalsFunction = new TFunction(
-        symbolTable, kInitGlobalsString, new TType(EbtVoid), SymbolType::AngleInternal, false);
+    TFunction *initGlobalsFunction =
+        new TFunction(symbolTable, kInitGlobalsString, SymbolType::AngleInternal,
+                      StaticType::GetBasic<EbtVoid>(), false);
 
     TIntermFunctionPrototype *initGlobalsFunctionPrototype =
         CreateInternalFunctionPrototypeNode(*initGlobalsFunction);
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index f2714b0..268a4a4 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -715,8 +715,8 @@
     ImmutableString mangledName = TFunctionLookup::GetMangledName(functionName.data(), *arguments);
     if (mInternalFunctions.find(mangledName) == mInternalFunctions.end())
     {
-        TFunction *func = new TFunction(mSymbolTable, functionName, new TType(returnType),
-                                        SymbolType::AngleInternal, knownToNotHaveSideEffects);
+        TFunction *func = new TFunction(mSymbolTable, functionName, SymbolType::AngleInternal,
+                                        new TType(returnType), knownToNotHaveSideEffects);
         ASSERT(parameters.size() == arguments->size());
         for (size_t i = 0; i < parameters.size(); ++i)
         {
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 06cd1c8..474fdc4 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -3429,7 +3429,7 @@
     }
 
     // Add the function as a prototype after parsing it (we do not support recursion)
-    return new TFunction(&symbolTable, name, new TType(type), SymbolType::UserDefined, false);
+    return new TFunction(&symbolTable, name, SymbolType::UserDefined, new TType(type), false);
 }
 
 TFunctionLookup *TParseContext::addNonConstructorFunc(const ImmutableString &name,
diff --git a/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/compiler/translator/RemoveDynamicIndexing.cpp
index 155e3d1..2b77ab3 100644
--- a/src/compiler/translator/RemoveDynamicIndexing.cpp
+++ b/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -406,8 +406,8 @@
             if (mIndexedVecAndMatrixTypes.find(type) == mIndexedVecAndMatrixTypes.end())
             {
                 indexingFunction =
-                    new TFunction(mSymbolTable, indexingFunctionName, GetFieldType(type),
-                                  SymbolType::AngleInternal, true);
+                    new TFunction(mSymbolTable, indexingFunctionName, SymbolType::AngleInternal,
+                                  GetFieldType(type), true);
                 indexingFunction->addParameter(
                     TConstParameter(kBaseName, GetBaseType(type, false)));
                 indexingFunction->addParameter(TConstParameter(kIndexName, kIndexType));
@@ -456,8 +456,8 @@
                     ImmutableString functionName(
                         GetIndexFunctionName(node->getLeft()->getType(), true));
                     indexedWriteFunction =
-                        new TFunction(mSymbolTable, functionName, StaticType::GetBasic<EbtVoid>(),
-                                      SymbolType::AngleInternal, false);
+                        new TFunction(mSymbolTable, functionName, SymbolType::AngleInternal,
+                                      StaticType::GetBasic<EbtVoid>(), false);
                     indexedWriteFunction->addParameter(
                         TConstParameter(kBaseName, GetBaseType(type, true)));
                     indexedWriteFunction->addParameter(TConstParameter(kIndexName, kIndexType));
diff --git a/src/compiler/translator/RunAtTheEndOfShader.cpp b/src/compiler/translator/RunAtTheEndOfShader.cpp
index ca82a07..9a6f8d6 100644
--- a/src/compiler/translator/RunAtTheEndOfShader.cpp
+++ b/src/compiler/translator/RunAtTheEndOfShader.cpp
@@ -25,6 +25,7 @@
 #include "compiler/translator/IntermNode.h"
 #include "compiler/translator/IntermNode_util.h"
 #include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/StaticType.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
@@ -68,8 +69,8 @@
                        TSymbolTable *symbolTable)
 {
     // Replace main() with main0() with the same body.
-    TFunction *oldMain = new TFunction(symbolTable, ImmutableString(""), new TType(EbtVoid),
-                                       SymbolType::AngleInternal, false);
+    TFunction *oldMain = new TFunction(symbolTable, ImmutableString(""), SymbolType::AngleInternal,
+                                       StaticType::GetBasic<EbtVoid>(), false);
     TIntermFunctionDefinition *oldMainDefinition =
         CreateInternalFunctionDefinitionNode(*oldMain, main->getBody());
 
@@ -77,8 +78,8 @@
     ASSERT(replaced);
 
     // void main()
-    TFunction *newMain =
-        new TFunction(symbolTable, kMainString, new TType(EbtVoid), SymbolType::UserDefined, false);
+    TFunction *newMain = new TFunction(symbolTable, kMainString, SymbolType::UserDefined,
+                                       StaticType::GetBasic<EbtVoid>(), false);
     TIntermFunctionPrototype *newMainProto = new TIntermFunctionPrototype(newMain);
 
     // {
diff --git a/src/compiler/translator/Symbol.cpp b/src/compiler/translator/Symbol.cpp
index daaa33f..3e7b83a 100644
--- a/src/compiler/translator/Symbol.cpp
+++ b/src/compiler/translator/Symbol.cpp
@@ -126,37 +126,66 @@
 
 TFunction::TFunction(TSymbolTable *symbolTable,
                      const ImmutableString &name,
-                     const TType *retType,
                      SymbolType symbolType,
-                     bool knownToNotHaveSideEffects,
-                     TOperator tOp,
-                     TExtension extension)
-    : TSymbol(symbolTable, name, symbolType, extension),
+                     const TType *retType,
+                     bool knownToNotHaveSideEffects)
+    : TSymbol(symbolTable, name, symbolType, TExtension::UNDEFINED),
+      mParametersVector(new TParamVector()),
+      mParameters(nullptr),
+      mParamCount(0u),
       returnType(retType),
-      mangledName(nullptr),
-      op(tOp),
+      mMangledName(""),
+      mOp(EOpNull),
       defined(false),
       mHasPrototypeDeclaration(false),
       mKnownToNotHaveSideEffects(knownToNotHaveSideEffects)
 {
     // Functions with an empty name are not allowed.
     ASSERT(symbolType != SymbolType::Empty);
-    ASSERT(name != nullptr || symbolType == SymbolType::AngleInternal || tOp != EOpNull);
+    ASSERT(name != nullptr || symbolType == SymbolType::AngleInternal);
 }
 
-void TFunction::clearParameters()
+TFunction::TFunction(TSymbolTable *symbolTable,
+                     const ImmutableString &name,
+                     TExtension extension,
+                     TConstParameter *parameters,
+                     size_t paramCount,
+                     const TType *retType,
+                     TOperator op,
+                     bool knownToNotHaveSideEffects)
+    : TSymbol(symbolTable, name, SymbolType::BuiltIn, extension),
+      mParametersVector(nullptr),
+      mParameters(parameters),
+      mParamCount(paramCount),
+      returnType(retType),
+      mMangledName(""),
+      mOp(op),
+      defined(false),
+      mHasPrototypeDeclaration(false),
+      mKnownToNotHaveSideEffects(knownToNotHaveSideEffects)
 {
-    parameters.clear();
-    mangledName = ImmutableString("");
+    ASSERT(name != nullptr);
+    ASSERT(op != EOpNull);
+    ASSERT(paramCount == 0 || parameters != nullptr);
+    mMangledName = buildMangledName();
 }
 
-void TFunction::swapParameters(const TFunction &parametersSource)
+void TFunction::addParameter(const TConstParameter &p)
 {
-    clearParameters();
-    for (auto parameter : parametersSource.parameters)
-    {
-        addParameter(parameter);
-    }
+    ASSERT(mParametersVector);
+    mParametersVector->push_back(p);
+    mParameters  = mParametersVector->data();
+    mParamCount  = mParametersVector->size();
+    mMangledName = ImmutableString("");
+}
+
+void TFunction::shareParameters(const TFunction &parametersSource)
+{
+    mParametersVector = nullptr;
+    mParameters       = parametersSource.mParameters;
+    mParamCount       = parametersSource.mParamCount;
+    ASSERT(parametersSource.name() == name());
+    mMangledName = parametersSource.mMangledName;
 }
 
 ImmutableString TFunction::buildMangledName() const
@@ -164,9 +193,9 @@
     std::string newName(name().data(), name().length());
     newName += kFunctionMangledNameSeparator;
 
-    for (const auto &p : parameters)
+    for (size_t i = 0u; i < mParamCount; ++i)
     {
-        newName += p.type->getMangledName();
+        newName += mParameters[i].type->getMangledName();
     }
     return ImmutableString(newName);
 }
diff --git a/src/compiler/translator/Symbol.h b/src/compiler/translator/Symbol.h
index 0322cbe..cc5a81a 100644
--- a/src/compiler/translator/Symbol.h
+++ b/src/compiler/translator/Symbol.h
@@ -159,9 +159,10 @@
 // Immutable version of TParameter.
 struct TConstParameter
 {
+    POOL_ALLOCATOR_NEW_DELETE();
     TConstParameter() : name(""), type(nullptr) {}
     explicit TConstParameter(const ImmutableString &n) : name(n), type(nullptr) {}
-    explicit TConstParameter(const TType *t) : name(""), type(t) {}
+    constexpr explicit TConstParameter(const TType *t) : name(""), type(t) {}
     TConstParameter(const ImmutableString &n, const TType *t) : name(n), type(t) {}
 
     // Both constructor arguments must be const.
@@ -197,44 +198,48 @@
 class TFunction : public TSymbol
 {
   public:
+    // User-defined function
     TFunction(TSymbolTable *symbolTable,
               const ImmutableString &name,
-              const TType *retType,
               SymbolType symbolType,
-              bool knownToNotHaveSideEffects,
-              TOperator tOp        = EOpNull,
-              TExtension extension = TExtension::UNDEFINED);
+              const TType *retType,
+              bool knownToNotHaveSideEffects);
+
+    // Built-in function
+    TFunction(TSymbolTable *symbolTable,
+              const ImmutableString &name,
+              TExtension extension,
+              TConstParameter *parameters,
+              size_t paramCount,
+              const TType *retType,
+              TOperator op,
+              bool knownToNotHaveSideEffects);
 
     bool isFunction() const override { return true; }
 
-    void addParameter(const TConstParameter &p)
-    {
-        parameters.push_back(p);
-        mangledName = ImmutableString("");
-    }
-
-    void swapParameters(const TFunction &parametersSource);
+    void addParameter(const TConstParameter &p);
+    void shareParameters(const TFunction &parametersSource);
 
     ImmutableString getMangledName() const override
     {
-        if (mangledName == "")
+        if (mMangledName == "")
         {
-            mangledName = buildMangledName();
+            mMangledName = buildMangledName();
         }
-        return mangledName;
+        return mMangledName;
     }
 
     const TType &getReturnType() const { return *returnType; }
 
-    TOperator getBuiltInOp() const { return op; }
+    TOperator getBuiltInOp() const { return mOp; }
 
     void setDefined() { defined = true; }
     bool isDefined() { return defined; }
     void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; }
     bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; }
 
-    size_t getParamCount() const { return parameters.size(); }
-    const TConstParameter &getParam(size_t i) const { return parameters[i]; }
+    size_t getParamCount() const { return mParamCount; }
+    const TConstParameter &getParam(size_t i) const { return mParameters[i]; }
 
     bool isKnownToNotHaveSideEffects() const { return mKnownToNotHaveSideEffects; }
 
@@ -242,15 +247,37 @@
     bool isImageFunction() const;
 
   private:
-    void clearParameters();
+    constexpr TFunction(const TSymbolUniqueId &id,
+                        const ImmutableString &name,
+                        TExtension extension,
+                        const TConstParameter *parameters,
+                        size_t paramCount,
+                        const TType *retType,
+                        const ImmutableString &mangledName,
+                        TOperator op,
+                        bool knownToNotHaveSideEffects)
+        : TSymbol(id, name, SymbolType::BuiltIn, extension),
+          mParametersVector(nullptr),
+          mParameters(parameters),
+          mParamCount(paramCount),
+          returnType(retType),
+          mMangledName(mangledName),
+          mOp(op),
+          defined(false),
+          mHasPrototypeDeclaration(false),
+          mKnownToNotHaveSideEffects(knownToNotHaveSideEffects)
+    {
+    }
 
     ImmutableString buildMangledName() const;
 
-    typedef TVector<TConstParameter> TParamList;
-    TParamList parameters;
+    typedef TVector<TConstParameter> TParamVector;
+    TParamVector *mParametersVector;
+    const TConstParameter *mParameters;
+    size_t mParamCount;
     const TType *const returnType;
-    mutable ImmutableString mangledName;
-    const TOperator op;  // Only set for built-ins
+    mutable ImmutableString mMangledName;
+    const TOperator mOp;  // Only set for built-ins
     bool defined;
     bool mHasPrototypeDeclaration;
     bool mKnownToNotHaveSideEffects;
diff --git a/src/compiler/translator/SymbolTable.cpp b/src/compiler/translator/SymbolTable.cpp
index 49b49fc..a4110ce 100644
--- a/src/compiler/translator/SymbolTable.cpp
+++ b/src/compiler/translator/SymbolTable.cpp
@@ -174,9 +174,9 @@
     // 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);
+        // The previous declaration should have the same parameters as the function definition
+        // (parameter names may differ).
+        firstDeclaration->shareParameters(*function);
     }
 
     *wasDefinedOut = firstDeclaration->isDefined();
@@ -591,30 +591,32 @@
     }
     else
     {
-        TFunction *function =
-            new TFunction(this, ImmutableString(name), rvalue, SymbolType::BuiltIn, false, op, ext);
-
-        function->addParameter(TConstParameter(ptype1));
+        size_t paramCount       = 1;
+        TConstParameter *params = new TConstParameter[5];
+        new (params) TConstParameter(ptype1);
 
         if (ptype2)
         {
-            function->addParameter(TConstParameter(ptype2));
+            new (params + 1) TConstParameter(ptype2);
+            paramCount = 2;
         }
-
         if (ptype3)
         {
-            function->addParameter(TConstParameter(ptype3));
+            new (params + 2) TConstParameter(ptype3);
+            paramCount = 3;
         }
-
         if (ptype4)
         {
-            function->addParameter(TConstParameter(ptype4));
+            new (params + 3) TConstParameter(ptype4);
+            paramCount = 4;
         }
-
         if (ptype5)
         {
-            function->addParameter(TConstParameter(ptype5));
+            new (params + 4) TConstParameter(ptype5);
+            paramCount = 5;
         }
+        TFunction *function =
+            new TFunction(this, ImmutableString(name), ext, params, paramCount, rvalue, op, false);
 
         ASSERT(hasUnmangledBuiltInAtLevel(name, level));
         insert(level, function);
@@ -658,8 +660,8 @@
                                                      const char *name)
 {
     insertUnmangledBuiltInName(name, level);
-    insert(level,
-           new TFunction(this, ImmutableString(name), rvalue, SymbolType::BuiltIn, false, op));
+    insert(level, new TFunction(this, ImmutableString(name), TExtension::UNDEFINED, nullptr, 0,
+                                rvalue, op, false));
 }
 
 void TSymbolTable::insertBuiltInFunctionNoParametersExt(ESymbolLevel level,
@@ -669,8 +671,7 @@
                                                         const char *name)
 {
     insertUnmangledBuiltInName(name, level);
-    insert(level,
-           new TFunction(this, ImmutableString(name), rvalue, SymbolType::BuiltIn, false, op, ext));
+    insert(level, new TFunction(this, ImmutableString(name), ext, nullptr, 0, rvalue, op, false));
 }
 
 void TSymbolTable::setDefaultPrecision(TBasicType type, TPrecision prec)