1 //
2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "compiler/translator/HashNames.h"
8
9 #include "compiler/translator/ImmutableString.h"
10 #include "compiler/translator/ImmutableStringBuilder.h"
11 #include "compiler/translator/IntermNode.h"
12 #include "compiler/translator/Symbol.h"
13
14 namespace sh
15 {
16
17 namespace
18 {
19 constexpr const ImmutableString kHashedNamePrefix("webgl_");
20
HashName(const ImmutableString & name,ShHashFunction64 hashFunction)21 ImmutableString HashName(const ImmutableString &name, ShHashFunction64 hashFunction)
22 {
23 ASSERT(!name.empty());
24 ASSERT(hashFunction);
25 khronos_uint64_t number = (*hashFunction)(name.data(), name.length());
26
27 // Build the hashed name in place.
28 static const unsigned int kHexStrMaxLength = sizeof(number) * 2;
29 static const size_t kHashedNameMaxLength = kHashedNamePrefix.length() + kHexStrMaxLength;
30
31 ImmutableStringBuilder hashedName(kHashedNameMaxLength);
32 hashedName << kHashedNamePrefix;
33
34 hashedName.appendHex(number);
35
36 return hashedName;
37 }
38
AddToNameMapIfNotMapped(const ImmutableString & name,const ImmutableString & hashedName,NameMap * nameMap)39 void AddToNameMapIfNotMapped(const ImmutableString &name,
40 const ImmutableString &hashedName,
41 NameMap *nameMap)
42 {
43 if (nameMap)
44 {
45 NameMap::const_iterator it = nameMap->find(name.data());
46 if (it != nameMap->end())
47 {
48 // (How bout returning?)
49 return;
50 }
51 (*nameMap)[name.data()] = hashedName.data();
52 }
53 }
54
55 } // anonymous namespace
56
HashName(const ImmutableString & name,ShHashFunction64 hashFunction,NameMap * nameMap)57 ImmutableString HashName(const ImmutableString &name,
58 ShHashFunction64 hashFunction,
59 NameMap *nameMap)
60 {
61 const ImmutableString kUnhashedNamePrefix(kUserDefinedNamePrefix);
62
63 if (hashFunction == nullptr)
64 {
65 if (name.length() + kUnhashedNamePrefix.length() > kESSLMaxIdentifierLength)
66 {
67 // If the identifier length is already close to the limit, we can't prefix it. This is
68 // not a problem since there are no builtins or ANGLE's internal variables that would
69 // have as long names and could conflict.
70 return name;
71 }
72 if (name == "gl_ClipDistance" || name == "gl_CullDistance" || name == "gl_LastFragData")
73 {
74 // NOTE(hqle): When gl_ClipDistance is re-declared, it will become an UserDefined
75 // symbol. Normally, UserDefined symbols will have "_u" prefix added to their names by
76 // ANGLE. However, gl_ClipDistance is an exception. If we add "_u" to its name, the
77 // backend won't be able to handle it properly. So for gl_ClipDistance, we won't add
78 // "_u" prefix, instead we return it original name.
79 //
80 // The other way is treating gl_ClipDistance as an AngleInternal symbol when a
81 // re-declaration occurs. AngleInternal symbols will have their name intact. However,
82 // the issue is that the current code put a lot of restrictions on AngleInternal
83 // symbols. For examples:
84 // - CollectVariables.cpp will not consider AngleInternal as varying output variables.
85 // - SymbolTable.cpp will throw an exception if AngleInternal symbols are declared by
86 // users. In this case, it would be gl_ClipDistance. This is because
87 // TSymbolTable::declare() only accepts an UserDefined symbol.
88 // - And potentially many other places that have some assumptions that haven't been
89 // discovered yet.
90 //
91 // If re-declared gl_ClipDistance was to be an AngleInternal symbol, a special "if (name
92 // == "gl_ClipDistance")" handling would have to be put into all the above mentioned
93 // cases. TParseContext::declareVariable() function would also have to be modified in
94 // order to assign AngleInternal symbol type to the re-declared gl_ClipDistance
95 // variable.
96 // Compare to only this place has to be handled if re-declared gl_ClipDistance is
97 // treated as an UserDefined symbol.
98 //
99 // Also, gl_LastFragData should be added.
100 //
101 return name;
102 }
103 ImmutableStringBuilder prefixedName(kUnhashedNamePrefix.length() + name.length());
104 prefixedName << kUnhashedNamePrefix << name;
105 ImmutableString res = prefixedName;
106 AddToNameMapIfNotMapped(name, res, nameMap);
107 return res;
108 }
109
110 // Has a hash function
111 ImmutableString hashedName = HashName(name, hashFunction);
112 AddToNameMapIfNotMapped(name, hashedName, nameMap);
113 return hashedName;
114 }
115
HashName(const TSymbol * symbol,ShHashFunction64 hashFunction,NameMap * nameMap)116 ImmutableString HashName(const TSymbol *symbol, ShHashFunction64 hashFunction, NameMap *nameMap)
117 {
118 if (symbol->symbolType() == SymbolType::Empty)
119 {
120 return kEmptyImmutableString;
121 }
122 if (symbol->symbolType() == SymbolType::AngleInternal ||
123 symbol->symbolType() == SymbolType::BuiltIn)
124 {
125 return symbol->name();
126 }
127 return HashName(symbol->name(), hashFunction, nameMap);
128 }
129
130 } // namespace sh
131