Skip to content

Commit 2760fc2

Browse files
?
1 parent 8fcba01 commit 2760fc2

File tree

4 files changed

+124
-30
lines changed

4 files changed

+124
-30
lines changed

import-test.wast

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
(module
2+
;; CHECK: (type $t (func (param i32)))
3+
(type $t (func (param i32)))
4+
5+
;; CHECK: (import "" "" (func $imported-func (type $t) (param i32)))
6+
;; (import "" "" (func $imported-func (type $t)))
7+
(import "" "" (func $imported-func (type $t)))
8+
9+
(elem declare $imported-func)
10+
11+
;; CHECK: (func $nop (type $t) (param $0 i32)
12+
;; CHECK-NEXT: (nop)
13+
;; CHECK-NEXT: )
14+
(func $nop (param i32)
15+
)
16+
17+
;; CHECK: (func $indirect-calls (type $1) (param $ref (ref $t))
18+
;; CHECK-NEXT: (call_ref $t
19+
;; CHECK-NEXT: (i32.const 1)
20+
;; CHECK-NEXT: (local.get $ref)
21+
;; CHECK-NEXT: )
22+
;; CHECK-NEXT: )
23+
(func $indirect-calls (param $ref (ref $t))
24+
(call_ref $t (i32.const 1) (local.get $ref))
25+
)
26+
27+
;; CHECK: (func $f (type $1) (param $ref (ref $t))
28+
;; CHECK-NEXT: (nop)
29+
;; CHECK-NEXT: )
30+
(func $f (param $ref (ref $t))
31+
;; $indirect-calls might end up calling an imported function,
32+
;; so we don't know anything about effects here
33+
(call $indirect-calls (local.get $ref))
34+
)
35+
)

src/passes/GlobalEffects.cpp

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
9090
// Note the direct call.
9191
funcInfo.calledFunctions.insert(call->target);
9292
} else if (effects.calls) {
93+
if (!options.closedWorld) {
94+
funcInfo.effects = UnknownEffects;
95+
return;
96+
}
97+
9398
HeapType type;
9499
if (auto* callRef = curr->dynCast<CallRef>()) {
95100
type = callRef->target->type.getHeapType();
@@ -118,6 +123,36 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
118123
return std::move(analysis.map);
119124
}
120125

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+
121156
using CallGraphNode = std::variant<Name, HeapType>;
122157

123158
// Build a call graph for indirect and direct calls.
@@ -126,27 +161,20 @@ using CallGraphNode = std::variant<Name, HeapType>;
126161
// Name -> HeapType : callee is a potential target of a virtual call with this HeapType
127162
// HeapType -> Name : callee is indirectly called by caller
128163
// HeapType -> HeapType : callee is a subtype of caller
164+
165+
// TODO: only track indirect calls in closed world
129166
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>> buildReverseCallGraph(Module& module, const std::map<Function*, FuncInfo> funcInfos) {
130167
// callee : caller
131168
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>
132169
callers;
133170

134171
std::unordered_set<HeapType> allIndirectCalledTypes;
135172

136-
std::unordered_set<Name> funcsWithAddress;
137-
138-
auto refFuncs = TableUtils::getFunctionsNeedingElemDeclare(module);
139-
funcsWithAddress.insert(refFuncs.begin(), refFuncs.end());
140-
ElementUtils::iterAllElementFunctionNames(
141-
&module,
142-
[&funcsWithAddress](Name name) { funcsWithAddress.insert(name); });
143-
for (const auto& export_ : module.exports) {
144-
if (export_->kind == ExternalKind::Function) {
145-
// This exported function might flow back to us even in a closed world,
146-
// so it's essentially addressed.
147-
funcsWithAddress.insert(export_->name);
148-
}
149-
}
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);
150178

151179
for (const auto& [func, info] : funcInfos) {
152180
// Name -> Name for direct calls
@@ -263,6 +291,15 @@ struct GenerateGlobalEffects : public Pass {
263291
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>
264292
callers = buildReverseCallGraph(*module, funcInfos);
265293

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+
// }
302+
266303
propagateEffects(*module, callers, funcInfos);
267304

268305
// Generate the final data, starting from a blank slate where nothing is

test/lit/passes/global-effects-closed-world.wast

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@
194194
;; CHECK: (type $unreachable-via-direct-call (func (param i32)))
195195
(type $unreachable-via-direct-call (func (param i32)))
196196

197+
;; CHECK: (elem declare func $calls-unreachable)
198+
197199
;; CHECK: (func $unreachable (type $0)
198200
;; CHECK-NEXT: (unreachable)
199201
;; CHECK-NEXT: )
@@ -226,5 +228,41 @@
226228
)
227229
)
228230

231+
(module
232+
;; CHECK: (type $t (func (param i32)))
233+
(type $t (func (param i32)))
234+
235+
;; (import "" "" (func $imported-func (type $t)))
236+
;; CHECK: (import "" "" (func $imported-func (type $t) (param i32)))
237+
(import "" "" (func $imported-func (type $t)))
238+
239+
(elem declare $imported-func)
240+
241+
;; CHECK: (func $nop (type $t) (param $0 i32)
242+
;; CHECK-NEXT: (nop)
243+
;; CHECK-NEXT: )
244+
(func $nop (param i32)
245+
)
246+
247+
;; CHECK: (func $indirect-calls (type $1) (param $ref (ref $t))
248+
;; CHECK-NEXT: (call_ref $t
249+
;; CHECK-NEXT: (i32.const 1)
250+
;; CHECK-NEXT: (local.get $ref)
251+
;; CHECK-NEXT: )
252+
;; CHECK-NEXT: )
253+
(func $indirect-calls (param $ref (ref $t))
254+
(call_ref $t (i32.const 1) (local.get $ref))
255+
)
256+
257+
;; CHECK: (func $f (type $1) (param $ref (ref $t))
258+
;; CHECK-NEXT: (nop)
259+
;; CHECK-NEXT: )
260+
(func $f (param $ref (ref $t))
261+
;; $indirect-calls might end up calling an imported function,
262+
;; so we don't know anything about effects here
263+
(call $indirect-calls (local.get $ref))
264+
)
265+
)
266+
229267
;; TODO exact types
230268
;; TODO functions that are referenced other ways besides exporting

test/lit/passes/global-effects-eh-legacy.wast

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -327,22 +327,6 @@
327327
;; WITHOUT-NEXT: (call $return-call-ref-throw-and-catch)
328328
;; WITHOUT-NEXT: )
329329
;; INCLUDE: (func $call-return-call-throw-and-catch (type $void)
330-
;; INCLUDE-NEXT: (try
331-
;; INCLUDE-NEXT: (do
332-
;; INCLUDE-NEXT: (call $return-call-indirect-throw-and-catch)
333-
;; INCLUDE-NEXT: )
334-
;; INCLUDE-NEXT: (catch_all
335-
;; INCLUDE-NEXT: (nop)
336-
;; INCLUDE-NEXT: )
337-
;; INCLUDE-NEXT: )
338-
;; INCLUDE-NEXT: (try
339-
;; INCLUDE-NEXT: (do
340-
;; INCLUDE-NEXT: (call $return-call-ref-throw-and-catch)
341-
;; INCLUDE-NEXT: )
342-
;; INCLUDE-NEXT: (catch_all
343-
;; INCLUDE-NEXT: (nop)
344-
;; INCLUDE-NEXT: )
345-
;; INCLUDE-NEXT: )
346330
;; INCLUDE-NEXT: (call $return-call-throw-and-catch)
347331
;; INCLUDE-NEXT: (call $return-call-indirect-throw-and-catch)
348332
;; INCLUDE-NEXT: (call $return-call-ref-throw-and-catch)

0 commit comments

Comments
 (0)