diff options
author | Alon Zakai <azakai@google.com> | 2019-06-15 12:04:16 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-15 12:04:16 -0700 |
commit | 1cd34c211dffa66fa2f2e45f3f9291e8ad836e07 (patch) | |
tree | 74fc2c7c15872d2c23d8b7eed7865486069549ce /src/ir/module-utils.h | |
parent | 22ba24118ef04720e6c7605dbaf90b22cdba006f (diff) | |
download | binaryen-1cd34c211dffa66fa2f2e45f3f9291e8ad836e07.tar.gz binaryen-1cd34c211dffa66fa2f2e45f3f9291e8ad836e07.tar.bz2 binaryen-1cd34c211dffa66fa2f2e45f3f9291e8ad836e07.zip |
Bysyncify: async transform for wasm (#2172)
This adds a new pass, Bysyncify, which transforms code to allow unwind and rewinding the call stack and local state. This allows things like coroutines, turning synchronous code asynchronous, etc.
The new pass file itself has a large comment on top with docs.
So far the tests here seem to show this works, but this hasn't been tested heavily yet. My next step is to hook this up to emscripten as a replacement for asyncify/emterpreter, see emscripten-core/emscripten#8561
Note that this is completely usable by itself, so it could be useful for any language that needs coroutines etc., and not just ones using LLVM and/or emscripten. See docs on the ABI in the pass source.
Diffstat (limited to 'src/ir/module-utils.h')
-rw-r--r-- | src/ir/module-utils.h | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h index c13e9f1ca..88298fd43 100644 --- a/src/ir/module-utils.h +++ b/src/ir/module-utils.h @@ -19,6 +19,7 @@ #include "ir/find_all.h" #include "ir/manipulation.h" +#include "pass.h" #include "wasm.h" namespace wasm { @@ -287,6 +288,62 @@ template<typename T> inline void iterDefinedEvents(Module& wasm, T visitor) { } } +// Performs a parallel map on function in the module, emitting a map object +// of function => result. +// TODO: use in inlining and elsewhere +template<typename T> struct ParallelFunctionMap { + + typedef std::map<Function*, T> Map; + Map map; + + typedef std::function<void(Function*, T&)> Func; + + struct Info { + Map* map; + Func work; + }; + + ParallelFunctionMap(Module& wasm, Func work) { + // Fill in map, as we operate on it in parallel (each function to its own + // entry). + for (auto& func : wasm.functions) { + map[func.get()]; + } + + // Run on the imports first. TODO: parallelize this too + for (auto& func : wasm.functions) { + if (func->imported()) { + work(func.get(), map[func.get()]); + } + } + + // Run on the implemented functions. + struct Mapper : public WalkerPass<PostWalker<Mapper>> { + + bool isFunctionParallel() override { return true; } + + Mapper(Info* info) : info(info) {} + + Mapper* create() override { return new Mapper(info); } + + void doWalkFunction(Function* curr) { + assert((*info->map).count(curr)); + info->work(curr, (*info->map)[curr]); + } + + private: + Info* info; + }; + + Info info = {&map, work}; + + PassRunner runner(&wasm); + runner.setIsNested(true); + runner.add<Mapper>(&info); + runner.run(); + } +}; + } // namespace ModuleUtils } // namespace wasm |