@@ -59,47 +59,115 @@ bool SubstitutionEntry::identifierEquals(Node *lhs, Node *rhs) {
5959 return true ;
6060}
6161
62- void SubstitutionEntry::deepHash (Node *node) {
62+ bool SubstitutionEntry::deepEquals (Node *lhs, Node *rhs) const {
63+ if (!lhs->isSimilarTo (rhs))
64+ return false ;
65+
66+ for (auto li = lhs->begin (), ri = rhs->begin (), le = lhs->end ();
67+ li != le; ++li, ++ri) {
68+ if (!deepEquals (*li, *ri))
69+ return false ;
70+ }
71+
72+ return true ;
73+ }
74+
75+ static inline size_t combineHash (size_t currentHash, size_t newValue) {
76+ return 33 * currentHash + newValue;
77+ }
78+
79+ // / Calculate the hash for a node.
80+ size_t RemanglerBase::hashForNode (Node *node,
81+ bool treatAsIdentifier) {
82+ size_t hash = 0 ;
83+
6384 if (treatAsIdentifier) {
64- combineHash ((size_t ) Node::Kind::Identifier);
85+ hash = combineHash (hash, (size_t )Node::Kind::Identifier);
6586 assert (node->hasText ());
6687 switch (node->getKind ()) {
6788 case Node::Kind::InfixOperator:
6889 case Node::Kind::PrefixOperator:
6990 case Node::Kind::PostfixOperator:
7091 for (char c : node->getText ()) {
71- combineHash ((unsigned char )translateOperatorChar (c));
92+ hash = combineHash (hash, (unsigned char )translateOperatorChar (c));
7293 }
73- return ;
94+ return hash ;
7495 default :
7596 break ;
7697 }
7798 } else {
78- combineHash ((size_t ) node->getKind ());
99+ hash = combineHash (hash, (size_t ) node->getKind ());
79100 }
80101 if (node->hasIndex ()) {
81- combineHash (node->getIndex ());
102+ hash = combineHash (hash, node->getIndex ());
82103 } else if (node->hasText ()) {
83104 for (char c : node->getText ()) {
84- combineHash ((unsigned char ) c);
105+ hash = combineHash (hash, (unsigned char ) c);
85106 }
86107 }
87108 for (Node *child : *node) {
88- deepHash (child);
109+ SubstitutionEntry entry = entryForNode (child, treatAsIdentifier);
110+ hash = combineHash (hash, entry.hash ());
89111 }
112+
113+ return hash;
90114}
91115
92- bool SubstitutionEntry::deepEquals (Node *lhs, Node *rhs) const {
93- if (!lhs->isSimilarTo (rhs))
94- return false ;
116+ // / Rotate a size_t by N bits
117+ static inline size_t rotate (size_t value, size_t shift) {
118+ const size_t bits = sizeof (size_t ) * 8 ;
119+ return (value >> shift) | (value << (bits - shift));
120+ }
95121
96- for (auto li = lhs->begin (), ri = rhs->begin (), le = lhs->end ();
97- li != le; ++li, ++ri) {
98- if (!deepEquals (*li, *ri))
99- return false ;
122+ // / Compute a hash value from a node *pointer*.
123+ // / Used for look-ups in HashHash. The numbers in here were determined
124+ // / experimentally.
125+ static inline size_t nodeHash (Node *node) {
126+ // Multiply by a magic number
127+ const size_t nodePrime = ((size_t )node) * 2043 ;
128+
129+ // We rotate by a different amount because the alignment of Node
130+ // changes depending on the machine's pointer size
131+ switch (sizeof (size_t )) {
132+ case 4 :
133+ return rotate (nodePrime, 11 );
134+ case 8 :
135+ return rotate (nodePrime, 12 );
136+ case 16 :
137+ return rotate (nodePrime, 13 );
138+ default :
139+ return rotate (nodePrime, 12 );
100140 }
101-
102- return true ;
141+ }
142+
143+ // / Construct a SubstitutionEntry for a given node.
144+ // / This will look in the HashHash to see if we already know the hash
145+ // / (which avoids recursive hashing on the Node tree).
146+ SubstitutionEntry RemanglerBase::entryForNode (Node *node,
147+ bool treatAsIdentifier) {
148+ const size_t ident = treatAsIdentifier ? 4 : 0 ;
149+ const size_t hash = nodeHash (node) + ident;
150+
151+ // Use linear probing with a limit
152+ for (size_t n = 0 ; n < HashHashMaxProbes; ++n) {
153+ const size_t ndx = (hash + n) & (HashHashCapacity - 1 );
154+ SubstitutionEntry entry = HashHash[ndx];
155+
156+ if (entry.isEmpty ()) {
157+ size_t entryHash = hashForNode (node, treatAsIdentifier);
158+ entry.setNode (node, treatAsIdentifier, entryHash);
159+ HashHash[ndx] = entry;
160+ return entry;
161+ } else if (entry.matches (node, treatAsIdentifier)) {
162+ return entry;
163+ }
164+ }
165+
166+ // Hash table is full at this hash value
167+ SubstitutionEntry entry;
168+ size_t entryHash = hashForNode (node, treatAsIdentifier);
169+ entry.setNode (node, treatAsIdentifier, entryHash);
170+ return entry;
103171}
104172
105173// Find a substitution and return its index.
@@ -340,7 +408,7 @@ bool Remangler::trySubstitution(Node *node, SubstitutionEntry &entry,
340408 return true ;
341409
342410 // Go ahead and initialize the substitution entry.
343- entry. setNode (node, treatAsIdentifier);
411+ entry = entryForNode (node, treatAsIdentifier);
344412
345413 int Idx = findSubstitution (entry);
346414 if (Idx < 0 )
0 commit comments