@@ -66,28 +66,38 @@ using ModuleElement = std::pair<ModuleElementKind, Name>;
66
66
// Information from an indirect call: the name of the table, and the heap type.
67
67
using IndirectCall = std::pair<Name, HeapType>;
68
68
69
- // Visit or walk an expression to find what things are referenced.
70
- struct ReferenceFinder
71
- : public PostWalker<ReferenceFinder,
72
- UnifiedExpressionVisitor<ReferenceFinder>> {
73
- // Our findings are placed in these data structures, which the user of this
74
- // code can then process. We mark both uses and references, and also note
75
- // uses of specific things that require special handling, like refFuncs.
69
+ // Visit or walk an expression to find important things. We note them on data
70
+ // structures that the caller can then process.
71
+ //
72
+ // We could in theory merge this class in with Analyzer, allowing us to
73
+ // directly apply our findings - that is, rather than add to a data structure,
74
+ // then the caller iterates on it and calls a method on them all, we could call
75
+ // that method as we go. However, separating the classes is simpler as we need
76
+ // different handling in different cases (when scanning for references vs when
77
+ // scanning normally, see below).
78
+ //
79
+ // In theory we could parallelize this class, processing all functions in
80
+ // advance, rather than as we go (single-threaded). However, this turns out not
81
+ // to be faster in practice (perhaps because the single-threaded approach uses
82
+ // less memory).
83
+ struct Noter : public PostWalker <Noter, UnifiedExpressionVisitor<Noter>> {
84
+ // We mark both uses and references, and also note specific things that
85
+ // require special handling, like refFuncs.
76
86
std::vector<ModuleElement> used, referenced;
77
87
std::vector<HeapType> callRefTypes;
78
88
std::vector<Name> refFuncs;
79
89
std::vector<StructField> structFields;
80
90
std::vector<IndirectCall> indirectCalls;
81
91
82
- // Add an item to the output data structures.
92
+ // Note an item on our output data structures.
83
93
void use (ModuleElement element) { used.push_back (element); }
84
94
void reference (ModuleElement element) { referenced.push_back (element); }
85
- void useCallRef (HeapType type) { callRefTypes.push_back (type); }
86
- void useRefFunc (Name refFunc) { refFuncs.push_back (refFunc); }
87
- void useStructField (StructField structField) {
95
+ void noteCallRef (HeapType type) { callRefTypes.push_back (type); }
96
+ void noteRefFunc (Name refFunc) { refFuncs.push_back (refFunc); }
97
+ void noteStructField (StructField structField) {
88
98
structFields.push_back (structField);
89
99
}
90
- void useIndirectCall (Name table, HeapType type) {
100
+ void noteIndirectCall (Name table, HeapType type) {
91
101
indirectCalls.push_back ({table, type});
92
102
}
93
103
@@ -154,12 +164,12 @@ struct ReferenceFinder
154
164
// We refer to the table, but may not use all parts of it, that depends on
155
165
// the heap type we call with.
156
166
reference ({ModuleElementKind::Table, curr->table });
157
- useIndirectCall (curr->table , curr->heapType );
167
+ noteIndirectCall (curr->table , curr->heapType );
158
168
// Note a possible call of a function reference as well, as something might
159
169
// be written into the table during runtime. With precise tracking of what
160
170
// is written into the table we could do better here; we could also see
161
171
// which tables are immutable. TODO
162
- useCallRef (curr->heapType );
172
+ noteCallRef (curr->heapType );
163
173
}
164
174
165
175
void visitCallRef (CallRef* curr) {
@@ -168,17 +178,17 @@ struct ReferenceFinder
168
178
return ;
169
179
}
170
180
171
- useCallRef (curr->target ->type .getHeapType ());
181
+ noteCallRef (curr->target ->type .getHeapType ());
172
182
}
173
183
174
- void visitRefFunc (RefFunc* curr) { useRefFunc (curr->func ); }
184
+ void visitRefFunc (RefFunc* curr) { noteRefFunc (curr->func ); }
175
185
176
186
void visitStructGet (StructGet* curr) {
177
187
if (curr->ref ->type == Type::unreachable || curr->ref ->type .isNull ()) {
178
188
return ;
179
189
}
180
190
auto type = curr->ref ->type .getHeapType ();
181
- useStructField (StructField{type, curr->index });
191
+ noteStructField (StructField{type, curr->index });
182
192
}
183
193
};
184
194
@@ -276,25 +286,25 @@ struct Analyzer {
276
286
277
287
// Find references in this expression, and apply them. Anything found here
278
288
// is used.
279
- ReferenceFinder finder ;
280
- finder .setModule (module );
281
- finder .visit (curr);
282
- for (auto element : finder .used ) {
289
+ Noter noter ;
290
+ noter .setModule (module );
291
+ noter .visit (curr);
292
+ for (auto element : noter .used ) {
283
293
use (element);
284
294
}
285
- for (auto element : finder .referenced ) {
295
+ for (auto element : noter .referenced ) {
286
296
reference (element);
287
297
}
288
- for (auto type : finder .callRefTypes ) {
298
+ for (auto type : noter .callRefTypes ) {
289
299
useCallRefType (type);
290
300
}
291
- for (auto func : finder .refFuncs ) {
301
+ for (auto func : noter .refFuncs ) {
292
302
useRefFunc (func);
293
303
}
294
- for (auto structField : finder .structFields ) {
304
+ for (auto structField : noter .structFields ) {
295
305
useStructField (structField);
296
306
}
297
- for (auto call : finder .indirectCalls ) {
307
+ for (auto call : noter .indirectCalls ) {
298
308
useIndirectCall (call);
299
309
}
300
310
@@ -604,18 +614,18 @@ struct Analyzer {
604
614
// here).
605
615
void addReferences (Expression* curr) {
606
616
// Find references anywhere in this expression so we can apply them.
607
- ReferenceFinder finder ;
608
- finder .setModule (module );
609
- finder .walk (curr);
617
+ Noter noter ;
618
+ noter .setModule (module );
619
+ noter .walk (curr);
610
620
611
- for (auto element : finder .used ) {
621
+ for (auto element : noter .used ) {
612
622
reference (element);
613
623
}
614
- for (auto element : finder .referenced ) {
624
+ for (auto element : noter .referenced ) {
615
625
reference (element);
616
626
}
617
627
618
- for (auto func : finder .refFuncs ) {
628
+ for (auto func : noter .refFuncs ) {
619
629
// If a function ends up referenced but not used then later down we will
620
630
// empty it out by replacing its body with an unreachable, which always
621
631
// validates. For that reason all we need to do here is mark the function
0 commit comments