[interpreter] Add `initThreads` hook to JS output
A threaded test requires a more substantial harness than can be provided in one JavaScript file, and must be implemented differently for Web JS engines vs. console-based JS engines.
The idea is that the surrounding harness will implement the
initThreads() function, and replace the instance and register
functions to send messages to the Worker threads.
The initThreads() function is async so it can block until the threads
are ready. The entire function is wrapped in an async function to
allow for the join command (not yet implemented) to block.
Do you really want to start all threads upfront? Would it not be possible to create them one at a time when executing a thread command? And terminate them with join?
AIUI some (maybe all?) Worker implementations will not work properly when you spawn them and immediately block; they require you to return to the event loop first. We could work around that by making spawn async and waiting for it, I guess.
Though it's still tricky to handle multi-module linking in that case; imagine something like:
(module $ma
(func (export "a"))
...)
(register "ma" $ma)
(module
(import "ma" "a" (func))
(func (export "b"))
...)
(thread (invoke "b"))
Then the invoked thread needs to send modules $ma and $mb to be able to properly instantiate. It seemed simpler to me to have the threads all operating in lockstep instead.
I see. But this would cause a typical test to spawn dozens of workers upfront, although it probably hardly ever uses more than two or three at a time. Isn't that a problem? Would it even work in a browser?
I tried this in a small example in Chrome, and I was able to create ~40 Workers, post modules to them and instantiate before it started running out of memory. Maybe that will be enough?
You're right that it's potentially pretty annoying to write tests in the wast file and not know whether they'll run in the browser. I'll think some more about how to handle sending modules/memories if we spawn threads where it is specified.