Use ImmutableString for HLSL texture references

This also adds ImmutableStringBuilder class, which can be used to
build ImmutableStrings in place without extra allocations if the
maximum length is known in advance.

BUG=angleproject:2267
TEST=angle_unittests

Change-Id: I4dfb78adeb0cffcfad0d25753fb8063466012c92
Reviewed-on: https://chromium-review.googlesource.com/886362
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/TextureFunctionHLSL.cpp b/src/compiler/translator/TextureFunctionHLSL.cpp
index d2b65a6..36898ff 100644
--- a/src/compiler/translator/TextureFunctionHLSL.cpp
+++ b/src/compiler/translator/TextureFunctionHLSL.cpp
@@ -11,6 +11,7 @@
 
 #include "compiler/translator/TextureFunctionHLSL.h"
 
+#include "compiler/translator/ImmutableStringBuilder.h"
 #include "compiler/translator/UtilsHLSL.h"
 
 namespace sh
@@ -104,8 +105,8 @@
 
 void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
                                      const TextureFunctionHLSL::TextureFunction &textureFunction,
-                                     const TString &textureReference,
-                                     const TString &samplerReference)
+                                     const ImmutableString &textureReference,
+                                     const ImmutableString &samplerReference)
 {
     out << textureReference;
     if (IsIntegerSampler(textureFunction.sampler) ||
@@ -450,37 +451,56 @@
 void GetTextureReference(TInfoSinkBase &out,
                          const TextureFunctionHLSL::TextureFunction &textureFunction,
                          const ShShaderOutput outputType,
-                         TString *textureReference,
-                         TString *samplerReference)
+                         ImmutableString *textureReference,
+                         ImmutableString *samplerReference)
 {
     if (outputType == SH_HLSL_4_1_OUTPUT)
     {
-        TString suffix = TextureGroupSuffix(textureFunction.sampler);
+        static const ImmutableString kTexturesStr("textures");
+        static const ImmutableString kSamplersStr("samplers");
+        static const ImmutableString kSamplerIndexStr("[samplerIndex]");
+        static const ImmutableString kTextureIndexStr("[textureIndex]");
+        static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
+        ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
+
         if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
         {
-            *textureReference = TString("textures") + suffix + "[samplerIndex]";
-            *samplerReference = TString("samplers") + suffix + "[samplerIndex]";
+            ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
+                                                     kSamplerIndexStr.length());
+            textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
+            *textureReference = textureRefBuilder;
+            ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
+                                                     kSamplerIndexStr.length());
+            samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
+            *samplerReference = samplerRefBuilder;
         }
         else
         {
-            out << "    const uint textureIndex = samplerIndex - textureIndexOffset" << suffix
-                << ";\n";
-            *textureReference = TString("textures") + suffix + "[textureIndex]";
-            out << "    const uint samplerArrayIndex = samplerIndex - samplerIndexOffset" << suffix
-                << ";\n";
-            *samplerReference = TString("samplers") + suffix + "[samplerArrayIndex]";
+            out << "    const uint textureIndex = samplerIndex - textureIndexOffset"
+                << suffix.data() << ";\n";
+            ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
+                                                     kTextureIndexStr.length());
+            textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
+            *textureReference = textureRefBuilder;
+
+            out << "    const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
+                << suffix.data() << ";\n";
+            ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
+                                                     kSamplerArrayIndexStr.length());
+            samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
+            *samplerReference = samplerRefBuilder;
         }
     }
     else
     {
-        *textureReference = "x";
-        *samplerReference = "s";
+        *textureReference = ImmutableString("x");
+        *samplerReference = ImmutableString("s");
     }
 }
 
 void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
                                    const TextureFunctionHLSL::TextureFunction &textureFunction,
-                                   const TString &textureReference,
+                                   const ImmutableString &textureReference,
                                    bool getDimensionsIgnoresBaseLevel)
 {
     if (IsSampler2DMS(textureFunction.sampler))
@@ -565,7 +585,7 @@
     TInfoSinkBase &out,
     const TextureFunctionHLSL::TextureFunction &textureFunction,
     const ShShaderOutput outputType,
-    const TString &textureReference,
+    const ImmutableString &textureReference,
     TString *texCoordX,
     TString *texCoordY,
     TString *texCoordZ)
@@ -811,8 +831,8 @@
     TInfoSinkBase &out,
     const TextureFunctionHLSL::TextureFunction &textureFunction,
     const ShShaderOutput outputType,
-    const TString &textureReference,
-    const TString &samplerReference,
+    const ImmutableString &textureReference,
+    const ImmutableString &samplerReference,
     const TString &texCoordX,
     const TString &texCoordY,
     const TString &texCoordZ)
@@ -1291,8 +1311,8 @@
         // sampling we need to call the function directly on references to the texture and sampler
         // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
         // tests.
-        TString textureReference;
-        TString samplerReference;
+        ImmutableString textureReference("");
+        ImmutableString samplerReference("");
         GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
 
         if (textureFunction.method == TextureFunction::SIZE)