@@ -59,47 +59,115 @@ bool SubstitutionEntry::identifierEquals(Node *lhs, Node *rhs) {
59
59
return true ;
60
60
}
61
61
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
+
63
84
if (treatAsIdentifier) {
64
- combineHash ((size_t ) Node::Kind::Identifier);
85
+ hash = combineHash (hash, (size_t )Node::Kind::Identifier);
65
86
assert (node->hasText ());
66
87
switch (node->getKind ()) {
67
88
case Node::Kind::InfixOperator:
68
89
case Node::Kind::PrefixOperator:
69
90
case Node::Kind::PostfixOperator:
70
91
for (char c : node->getText ()) {
71
- combineHash ((unsigned char )translateOperatorChar (c));
92
+ hash = combineHash (hash, (unsigned char )translateOperatorChar (c));
72
93
}
73
- return ;
94
+ return hash ;
74
95
default :
75
96
break ;
76
97
}
77
98
} else {
78
- combineHash ((size_t ) node->getKind ());
99
+ hash = combineHash (hash, (size_t ) node->getKind ());
79
100
}
80
101
if (node->hasIndex ()) {
81
- combineHash (node->getIndex ());
102
+ hash = combineHash (hash, node->getIndex ());
82
103
} else if (node->hasText ()) {
83
104
for (char c : node->getText ()) {
84
- combineHash ((unsigned char ) c);
105
+ hash = combineHash (hash, (unsigned char ) c);
85
106
}
86
107
}
87
108
for (Node *child : *node) {
88
- deepHash (child);
109
+ SubstitutionEntry entry = entryForNode (child, treatAsIdentifier);
110
+ hash = combineHash (hash, entry.hash ());
89
111
}
112
+
113
+ return hash;
90
114
}
91
115
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
+ }
95
121
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 );
100
140
}
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;
103
171
}
104
172
105
173
// Find a substitution and return its index.
@@ -340,7 +408,7 @@ bool Remangler::trySubstitution(Node *node, SubstitutionEntry &entry,
340
408
return true ;
341
409
342
410
// Go ahead and initialize the substitution entry.
343
- entry. setNode (node, treatAsIdentifier);
411
+ entry = entryForNode (node, treatAsIdentifier);
344
412
345
413
int Idx = findSubstitution (entry);
346
414
if (Idx < 0 )
0 commit comments