Yeah I agree Deno is an interesting comparison, thanks for pointing it out I wasn't aware of it.

On the other points, I would still stick to my suggestion of using WebIDL, at least for Spidermonkey, since you'd have to otherwise write all the glue code yourself. The bindings generation is worth it I think.

Re using Tokio to run the event-loop of the VM, I would probably just use a native thread, like I suggested in the article.

Tokio is really like a runtime for Rust, meaning that if you use it to implement a runtime for say Wasm, then you're trying to run your own runtime within someone else's runtime. Not saying it can't be done, just not how I would do it.

I think Tokio on the other hand could really shine if used in a separate "networking component" that, in a Deno-like server-side runtime, would handle all incoming requests/connections, and then have the "runtime" run in a separate component(and process, if you want some isolation). Let's say you wanted to run different VM's, isolated from each other, you could run each in it's own process, and the networking would also be done in its own, or the "main", process of the overall engine.

Incoming networking requets could then be translated into events or other kind of calls into the user-code running on an isolated VM, which itself is probably best run using a simple event-loop running on a single-thread.

It's similar to what Servo does actually, where there is a "net" component to do the networking(although it's client-side networking off-course), then there is the "constellation" component that is like "one ring to rule them all" main component, and you have the "script" component actually running Spidermonkey VMs each on their own event-loop(let's say roughly one per "tab", plus one per worker).

So the JS/Wasm running on Spidermonkey is "async", like you can await a promise and so on, however it's actually driven by a single-thread, with other components, like "net", running "in-parallel" of "script", in their own process, and using whatever threading or async runtime they need.

So for example, if you do a fetch in JS, then the script component can keep running other stuff in it's task-queues in the meantime(in a single-threaded, one task at a time, fashion), while the net component will do the fetch over the network, and as "stuff happens" related to this fetch, net will enqueue tasks back on the event-loop where the fetch originated, resulting in events/promise resolving on the VM, and executing of handlers in JS.

So not only do "net" and "script" have to run in separate processes for security(spectre) and robustness, they also have to run in parallel of each other, and according to a very specific specification(see for the event-loop of script for example: https://html.spec.whatwg.org/multipage/#event-loop-processin...)

So I guess you could run a tokio runtime in both processes, but it would actually be kinda overkill(Servo does uses Tokio in the "net" component, and that's obviously a good fit since it's doing the networking).

So I'd say the trick would be clearly separating the networking, from the VM(s), probably use something like Tokio in the networking component, and to implement the event-loop driving the VM, I'd just use a native thread, one per VM.

This article is part of a collection of articles going into the architecture of Servo, if you're interested: https://medium.com/programming-servo