diff options
author | Alon Zakai <azakai@google.com> | 2020-01-24 11:28:18 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-24 11:28:18 -0800 |
commit | 1a0530da9c0217e7118965aeb4ee1f59f68df73c (patch) | |
tree | a20d1d84a9fd0b5d12a7ae4de76a02559a1005dc /src | |
parent | 1ca6394d34c827904e6ececb6463ef4899c95fe9 (diff) | |
download | binaryen-1a0530da9c0217e7118965aeb4ee1f59f68df73c.tar.gz binaryen-1a0530da9c0217e7118965aeb4ee1f59f68df73c.tar.bz2 binaryen-1a0530da9c0217e7118965aeb4ee1f59f68df73c.zip |
Handle indirect calls in CallGraphPropertyAnalysis (#2624)
We ignored them, which is a bad default, as typically they imply
we can call anything in the table (and the table might change).
Instead, notice indirect calls during traversal, and force the user
to decide whether to ignore them or not.
This was only an issue in PostEmscripten because the other
user, Asyncify, already had indirect call analysis because it
needed it for other things.
Fixes a bug uncovered by #2619 and fixes the current binaryen
roll.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/module-utils.h | 15 | ||||
-rw-r--r-- | src/passes/Asyncify.cpp | 3 | ||||
-rw-r--r-- | src/passes/PostEmscripten.cpp | 4 |
3 files changed, 18 insertions, 4 deletions
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h index 703ae3e53..93d110120 100644 --- a/src/ir/module-utils.h +++ b/src/ir/module-utils.h @@ -341,6 +341,7 @@ template<typename T> struct CallGraphPropertyAnalysis { struct FunctionInfo { std::set<Function*> callsTo; std::set<Function*> calledBy; + bool hasIndirectCall = false; }; typedef std::map<Function*, T> Map; @@ -362,6 +363,10 @@ template<typename T> struct CallGraphPropertyAnalysis { info.callsTo.insert(module->getFunction(curr->target)); } + void visitCallIndirect(CallIndirect* curr) { + info.hasIndirectCall = true; + } + private: Module* module; T& info; @@ -382,14 +387,20 @@ template<typename T> struct CallGraphPropertyAnalysis { } } + enum IndirectCalls { IgnoreIndirectCalls, IndirectCallsHaveProperty }; + // Propagate a property from a function to those that call it. void propagateBack(std::function<bool(const T&)> hasProperty, std::function<bool(const T&)> canHaveProperty, - std::function<void(T&)> addProperty) { + std::function<void(T&)> addProperty, + IndirectCalls indirectCalls) { // The work queue contains items we just learned can change the state. UniqueDeferredQueue<Function*> work; for (auto& func : wasm.functions) { - if (hasProperty(map[func.get()])) { + if (hasProperty(map[func.get()]) || + (indirectCalls == IndirectCallsHaveProperty && + map[func.get()].hasIndirectCall)) { + addProperty(map[func.get()]); work.push(func.get()); } } diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp index b7e8c90e0..a4ff5794b 100644 --- a/src/passes/Asyncify.cpp +++ b/src/passes/Asyncify.cpp @@ -549,7 +549,8 @@ public: return !info.isBottomMostRuntime && !info.inBlacklist; }, - [](Info& info) { info.canChangeState = true; }); + [](Info& info) { info.canChangeState = true; }, + scanner.IgnoreIndirectCalls); map.swap(scanner.map); diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp index e6eeb8e2a..ccf985c50 100644 --- a/src/passes/PostEmscripten.cpp +++ b/src/passes/PostEmscripten.cpp @@ -154,9 +154,11 @@ struct PostEmscripten : public Pass { } }); + // Assume an indirect call might throw. analyzer.propagateBack([](const Info& info) { return info.canThrow; }, [](const Info& info) { return true; }, - [](Info& info) { info.canThrow = true; }); + [](Info& info) { info.canThrow = true; }, + analyzer.IndirectCallsHaveProperty); // Apply the information. struct OptimizeInvokes : public WalkerPass<PostWalker<OptimizeInvokes>> { |