Prefix user-defined names in GLSL output

Now user-defined names are prefixed by _u in GLSL output in case name
hashing is not on. Internal names such as names of temporary variables
created in AST transformations are written out as such.

This makes handling of internal function names and internal variable
names consistent. It also removes the possibility of name conflicts
between user-defined names and internal names in case name hashing is
not on. In the same vein, it makes it safe to use GLSL reserved words
that are not reserved in ESSL as variable names in case name hashing
is not on.

This also makes the GLSL output more consistent with how names are
handled in HLSL output. Name hashing code is shared between
VariableInfo and OutputGLSLBase to ensure names are handled
consistently in both. The name that's used in the shader source for a
given interface variable is written out to ShaderVariable::mappedName.

An exception needs to be made for identifiers close to the length
limit, since adding any prefix would take them over the limit. But
they can be just written out as such, since we don't have any builtins
or ANGLE internal variables that have as long names and could create a
conflict.

BUG=angleproject:2139
BUG=angleproject:2038
TEST=angle_unittests, angle_end2end_tests, WebGL conformance tests

Change-Id: Id6ed052c4fab2d091227dc9a3668083053b67a38
Reviewed-on: https://chromium-review.googlesource.com/507647
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/HashNames.cpp b/src/compiler/translator/HashNames.cpp
index 369ef13..6bc90fa 100644
--- a/src/compiler/translator/HashNames.cpp
+++ b/src/compiler/translator/HashNames.cpp
@@ -6,18 +6,67 @@
 
 #include "compiler/translator/HashNames.h"
 
+#include "compiler/translator/IntermNode.h"
+
 namespace sh
 {
 
+namespace
+{
+
+// GLSL ES 3.00.6 section 3.9: the maximum length of an identifier is 1024 characters.
+static const unsigned int kESSLMaxIdentifierLength = 1024u;
+
+static const char *kHashedNamePrefix = "webgl_";
+
+// Can't prefix with just _ because then we might introduce a double underscore, which is not safe
+// in GLSL (ESSL 3.00.6 section 3.8: All identifiers containing a double underscore are reserved for
+// use by the underlying implementation). u is short for user-defined.
+static const char *kUnhashedNamePrefix              = "_u";
+static const unsigned int kUnhashedNamePrefixLength = 2u;
+
 TString HashName(const TString &name, ShHashFunction64 hashFunction)
 {
-    if (hashFunction == nullptr || name.empty())
-        return name;
+    ASSERT(!name.empty());
+    ASSERT(hashFunction);
     khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
     TStringStream stream;
-    stream << HASHED_NAME_PREFIX << std::hex << number;
+    stream << kHashedNamePrefix << std::hex << number;
     TString hashedName = stream.str();
     return hashedName;
 }
 
+}  // anonymous namespace
+
+TString HashName(const TName &name, ShHashFunction64 hashFunction, NameMap *nameMap)
+{
+    if (name.getString().empty() || name.isInternal())
+    {
+        return name.getString();
+    }
+    if (hashFunction == nullptr)
+    {
+        if (name.getString().length() + kUnhashedNamePrefixLength > kESSLMaxIdentifierLength)
+        {
+            // If the identifier length is already close to the limit, we can't prefix it. This is
+            // not a problem since there are no builtins or ANGLE's internal variables that would
+            // have as long names and could conflict.
+            return name.getString();
+        }
+        return kUnhashedNamePrefix + name.getString();
+    }
+    if (nameMap)
+    {
+        NameMap::const_iterator it = nameMap->find(name.getString().c_str());
+        if (it != nameMap->end())
+            return it->second.c_str();
+    }
+    TString hashedName = HashName(name.getString(), hashFunction);
+    if (nameMap)
+    {
+        (*nameMap)[name.getString().c_str()] = hashedName.c_str();
+    }
+    return hashedName;
+}
+
 }  // namespace sh