Stackless Comes to the Web 🕸 Build

I made a beeline for us being able to use stackless in the web build, because that's a place where it can get us some benefits. Much work has brought it there, and the ReplPad served up as of today is stackless! No Asyncify at all!

  • We get size benefits - Without the extra code generation added by Asyncify the %libr3.wasm file was down from ~1.8 megabytes to ~1.1 (I'd said I recalled it made things about twice the size, and that's in the ballpark)

    • There hasn't been any extreme push to optimize Ren-C on size, but I think it will be appealing when someone could have access to the functionality of the interpreter on their website for under a megabyte... when things like Golden Layout are a megabyte just for tabbed windows, a whole interpreter and PARSE doesn't seem a bad deal!

    • I want to push ever more of the features into little "WebAssembly DLLs" that you can pick from a-la-carte, and only pay for what you use. How minimal a core we can get is a question to pursue. But right now there's lots of stuffing (two PARSE implementations, for example) that hopefully the future can rein in.

  • We get speed benefits - Asyncify didn't just add bytes to the compiled code, those were bytes that were instructions that did stuff. It added bookkeeping to know how to unwind stacks of generic code it didn't know anything about.

    ren-c-asyncify>> x: [] delta-time [repeat 10000 [append x [a b]]]
    == 0:00:00.070
    ren-c-stackless>> x: [] delta-time [repeat 10000 [append x [a b]]]
    == 0:00:00.028

    That comparison isn't 100% fair, because that asyncify version is post-stackless code, hence it was instrumenting the stackless trampoline. But I'd imagine that it's easily twice as fast, as well as being half the size!

In just this evening after the change, I've already done some performance work that makes the Web REPL feel significantly snappier...try it out!

But Most Importantly, We Get More Working Features!

Asyncify's big achilles heel is that when it suspends your codebase, it's suspended. It can't do anything until it is fully resumed.*

* You can actually put a few functions on a blacklist of things that can be called despite the stack being suspended. But it's probably the case that the most important parts of your program need the asyncify treatment: in Ren-C's case, that was the evaluator. There's things you can do without the evaluator (scan code into array structures, for instance?)

Stackless makes us masters of time and space as far as the stack is concerned. @gchiu was trying to do something seemingly trivial, like attach some JavaScript to a button that would call:

 reb.Elide("write clipboard:// {hello}")

With all that's been accomplished so far you'd think that would have been relatively easy. But the moment when you call it matters a lot. The Repl was rigged very carefully to work with Asyncify and be able to run code when it was "its turn"--e.g. when it wasn't sleeping, having passed the baton to the GUI to gather user input.

With stackless these things become unblocked, and a lot of the tricky manipulations that weren't under our control are coming under it. Things should hopefully get better (!)

Question: Can We Hang Onto Some of the Asyncify Knowledge?

Having been through the labor of making code that wasn't stackless interoperate in the browser, I can't help but wonder if there's some way that we can keep the functionality in our pocket in case some situation could be helped by it.

I don't completely understand the custom unwinding concepts, but Alon makes it sound like we might be able to take any non-stackless natives and specifically instrument them. Like if when the Trampoline went to unwind it hit a stackful wall (a "root frame", as I call them) we might be able to selectively bundle the call stack between that wall and the next stackless point.

I'm not sure if it's worth weeks of effort to figure out if we can do it, but it's probably worth a bit. There are codebases of WebAssembly stuff for doing graphics and music and things like that...and we might want to hook them in a way that they call into us, even if they rely on Asyncify to do their work.

We've talked about having more "technology demos" just to show the versatility (e.g. integrating with WasmEdge) and so I feel like the more the merrier on that.

(It's hard to prioritize when there's so many cool directions to take things! But I continue to go after fundamentals, and try to stay the course on that...)


Mind-blowing, fantastic work Brian! Your work has put things in a place where they're poised to break-out!

1 Like

Some build settings adjusted and libr3.wasm is now down to just 681k.

But that's nowhere near the bottom of where we can go with this, I'm certain of it!