@@ -101,7 +101,7 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
101101 } else if (auto * callIndirect = curr->dynCast <CallIndirect>()) {
102102 type = callIndirect->heapType ;
103103 } else {
104- assert (false && " Unexpected type of call" );
104+ assert (" Unexpected type of call" );
105105 }
106106
107107 funcInfo.indirectCalledTypes .insert (type);
@@ -123,58 +123,34 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
123123 return std::move (analysis.map );
124124}
125125
126- // Funcs that can be the target of a virtual call
127- // These are either:
128- // - Part of an (elem declare ...) or (elem ...) directive
129- // - Exported, since they may flow back to us from the host
130- std::unordered_set<Name> getFuncsWithAddress (Module& module ) {
131- std::unordered_set<Name> funcsWithAddress;
132- for (const auto & fun : module .functions ) {
133- funcsWithAddress.insert (fun->name );
134- }
135- return funcsWithAddress;
136-
137- // {
138- // auto refFuncs = TableUtils::getFunctionsNeedingElemDeclare(module);
139- // funcsWithAddress.insert(refFuncs.begin(), refFuncs.end());
140- // }
141-
142- // ElementUtils::iterAllElementFunctionNames(
143- // &module,
144- // [&funcsWithAddress](Name name) { funcsWithAddress.insert(name); });
145- // for (const auto& export_ : module.exports) {
146- // if (export_->kind == ExternalKind::Function) {
147- // // This exported function might flow back to us even in a closed world,
148- // // so it's essentially addressed.
149- // funcsWithAddress.insert(export_->name);
150- // }
151- // }
152-
153- // return funcsWithAddress;
154- }
155-
156126using CallGraphNode = std::variant<Name, HeapType>;
157127
158128// Build a call graph for indirect and direct calls.
159129// key (callee) -> value (caller)
160130// Name -> Name : callee is called directly by caller
161- // Name -> HeapType : callee is a potential target of a virtual call with this HeapType
162- // HeapType -> Name : callee is indirectly called by caller
163- // HeapType -> HeapType : callee is a subtype of caller
164-
165- // TODO: only track indirect calls in closed world
166- std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>> buildReverseCallGraph (Module& module , const std::map<Function*, FuncInfo> funcInfos) {
131+ // Name -> HeapType : callee is a potential target of a virtual call
132+ // with this HeapType HeapType -> Name : callee is indirectly called by
133+ // caller HeapType -> HeapType : callee is a subtype of caller If we're
134+ // running in an open world, we only include Name -> Name edges.
135+ std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>
136+ buildReverseCallGraph (Module& module ,
137+ const std::map<Function*, FuncInfo> funcInfos,
138+ bool closedWorld) {
167139 // callee : caller
168- std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>
169- callers;
140+ std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>> callers;
170141
171- std::unordered_set<HeapType> allIndirectCalledTypes;
142+ if (!closedWorld) {
143+ for (const auto & [func, info] : funcInfos) {
144+ // Name -> Name for direct calls
145+ for (const auto & callee : info.calledFunctions ) {
146+ callers[callee].insert (func->name );
147+ }
148+ }
172149
173- // Funcs that can be the target of a virtual call
174- // These are either:
175- // - Part of an (elem declare ...) or (elem ...) directive
176- // - Exported, since they may flow back to us from the host
177- std::unordered_set<Name> funcsWithAddress = getFuncsWithAddress (module );
150+ return callers;
151+ }
152+
153+ std::unordered_set<HeapType> allIndirectCalledTypes;
178154
179155 for (const auto & [func, info] : funcInfos) {
180156 // Name -> Name for direct calls
@@ -188,9 +164,9 @@ std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>> buildRevers
188164 }
189165
190166 // Name -> HeapType for function types
191- if (funcsWithAddress. contains (func-> name )) {
192- callers[func-> name ]. insert (func-> type . getHeapType ());
193- }
167+ // TODO: only look at functions that are addressable
168+ // i.e. appear in a (ref.func) or are exported
169+ callers[func-> name ]. insert (func-> type . getHeapType ());
194170
195171 allIndirectCalledTypes.insert (func->type .getHeapType ());
196172 }
@@ -228,7 +204,8 @@ void propagateEffects(
228204 }
229205 }
230206
231- auto propagate = [&](const CallGraphNode& calleeNode, const CallGraphNode& callerNode) {
207+ auto propagate = [&](const CallGraphNode& calleeNode,
208+ const CallGraphNode& callerNode) {
232209 if (!std::get_if<Name>(&calleeNode) || !std::get_if<Name>(&callerNode)) {
233210 return ;
234211 }
@@ -276,6 +253,7 @@ void propagateEffects(
276253 continue ;
277254 }
278255
256+ // TODO: handle exact refs here
279257 for (const CallGraphNode& callerCaller : callerCallers->second ) {
280258 work.push (std::pair (callee, callerCaller));
281259 }
@@ -289,16 +267,8 @@ struct GenerateGlobalEffects : public Pass {
289267
290268 // callee : caller
291269 std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>
292- callers = buildReverseCallGraph (*module , funcInfos);
293-
294- // for (const auto& [callee, callers] : callers) {
295- // for (const auto& caller : callers) {
296- // const auto* calleeName = std::get_if<Name>(&callee);
297- // const auto* callerName = std::get_if<Name>(&caller);
298- // if (!calleeName || !callerName) continue;
299- // std::cout<<*calleeName<<"\t\t->\t\t"<<*callerName<<"\n";
300- // }
301- // }
270+ callers =
271+ buildReverseCallGraph (*module , funcInfos, getPassOptions ().closedWorld );
302272
303273 propagateEffects (*module , callers, funcInfos);
304274
0 commit comments