@@ -262,33 +262,20 @@ template<typename T> inline void iterDefinedEvents(Module& wasm, T visitor) {
262262 }
263263}
264264
265- // Helper class for analyzing the call graph.
266- //
267- // Provides hooks for running some initial calculation on each function (which
268- // is done in parallel), writing to a FunctionInfo structure for each function.
269- // Then you can call propagateBack() to propagate a property of interest to the
270- // calling functions, transitively.
271- //
272- // For example, if some functions are known to call an import "foo", then you
273- // can use this to find which functions call something that might eventually
274- // reach foo, by initially marking the direct callers as "calling foo" and
275- // propagating that backwards.
276- template <typename T> struct CallGraphPropertyAnalysis {
265+ // Helper class for performing an operation on all the functions in the module,
266+ // in parallel, with an Info object for each one that can contain results of
267+ // some computation that the operation performs.
268+ // The operation performend should not modify the wasm module in any way.
269+ // TODO: enforce this
270+ template <typename T> struct ParallelFunctionAnalysis {
277271 Module& wasm;
278272
279- // The basic information for each function about whom it calls and who is
280- // called by it.
281- struct FunctionInfo {
282- std::set<Function*> callsTo;
283- std::set<Function*> calledBy;
284- };
285-
286273 typedef std::map<Function*, T> Map;
287274 Map map;
288275
289276 typedef std::function<void (Function*, T&)> Func;
290277
291- CallGraphPropertyAnalysis (Module& wasm, Func work) : wasm(wasm) {
278+ ParallelFunctionAnalysis (Module& wasm, Func work) : wasm(wasm) {
292279 // Fill in map, as we operate on it in parallel (each function to its own
293280 // entry).
294281 for (auto & func : wasm.functions ) {
@@ -304,30 +291,78 @@ template<typename T> struct CallGraphPropertyAnalysis {
304291
305292 struct Mapper : public WalkerPass <PostWalker<Mapper>> {
306293 bool isFunctionParallel () override { return true ; }
294+ bool modifiesBinaryenIR () override { return false ; }
307295
308- Mapper (Module* module , Map* map, Func work)
296+ Mapper (Module& module , Map& map, Func work)
309297 : module (module ), map(map), work(work) {}
310298
311299 Mapper* create () override { return new Mapper (module , map, work); }
312300
313- void visitCall (Call* curr) {
314- (*map)[this ->getFunction ()].callsTo .insert (
315- module ->getFunction (curr->target ));
316- }
317-
318- void visitFunction (Function* curr) {
319- assert ((*map).count (curr));
320- work (curr, (*map)[curr]);
301+ void doWalkFunction (Function* curr) {
302+ assert (map.count (curr));
303+ work (curr, map[curr]);
321304 }
322305
323306 private:
324- Module* module ;
325- Map* map;
307+ Module& module ;
308+ Map& map;
326309 Func work;
327310 };
328311
329312 PassRunner runner (&wasm);
330- Mapper (&wasm, &map, work).run (&runner, &wasm);
313+ Mapper (wasm, map, work).run (&runner, &wasm);
314+ }
315+ };
316+
317+ // Helper class for analyzing the call graph.
318+ //
319+ // Provides hooks for running some initial calculation on each function (which
320+ // is done in parallel), writing to a FunctionInfo structure for each function.
321+ // Then you can call propagateBack() to propagate a property of interest to the
322+ // calling functions, transitively.
323+ //
324+ // For example, if some functions are known to call an import "foo", then you
325+ // can use this to find which functions call something that might eventually
326+ // reach foo, by initially marking the direct callers as "calling foo" and
327+ // propagating that backwards.
328+ template <typename T> struct CallGraphPropertyAnalysis {
329+ Module& wasm;
330+
331+ // The basic information for each function about whom it calls and who is
332+ // called by it.
333+ struct FunctionInfo {
334+ std::set<Function*> callsTo;
335+ std::set<Function*> calledBy;
336+ };
337+
338+ typedef std::map<Function*, T> Map;
339+ Map map;
340+
341+ typedef std::function<void (Function*, T&)> Func;
342+
343+ CallGraphPropertyAnalysis (Module& wasm, Func work) : wasm(wasm) {
344+ ParallelFunctionAnalysis<T> analysis (wasm, [&](Function* func, T& info) {
345+ work (func, info);
346+ if (func->imported ()) {
347+ return ;
348+ }
349+ struct Mapper : public PostWalker <Mapper> {
350+ Mapper (Module* module , T& info, Func work)
351+ : module (module ), info(info), work(work) {}
352+
353+ void visitCall (Call* curr) {
354+ info.callsTo .insert (module ->getFunction (curr->target ));
355+ }
356+
357+ private:
358+ Module* module ;
359+ T& info;
360+ Func work;
361+ } mapper (&wasm, info, work);
362+ mapper.walk (func->body );
363+ });
364+
365+ map.swap (analysis.map );
331366
332367 // Find what is called by what.
333368 for (auto & pair : map) {
0 commit comments