Rakudo.js update - hunting down failing roast tests
Currently I'm working to getting rakudo.js to pass (our choosen subset of tests) in Chrome rather then on node.js.
For that I'm using the karma test runner (which should also allow testing all the other browsers easily).
The way the process works is that the Perl 6 test files get compiled to JavaScript and bundled by the parcel with everything they needs to run. The bundling includes the setting, runtime and even the whole Rakudo compiler (tests use EVAL a lot).
As as side node it turns out that for debugging purposes node bundled-everything.js emulates running in the browser very closely.
The first big obstacle was that a whole bunch of tests run a new rakudo process to execute some code.
In the browser running shell commands obviously doesn't work.
In the tests it's almost always done by using a &is_run from Test::Helper.
I added a new nqp::p6fakerun op that's called by that sub that runs rakudo in a new global context and hijacks the standard input, output and error. This required actually having a savable and restorable the global state (After refactoring I now keep most of it in a single global object). This took a ton of fiddling and changing stuff all over but hopefully will be also useable to precompile things in the same process to save on loading time. Some of the tests needed a few things faked (like a new faked pid or passing env variables) so I implemented that too.
The second big obstacle was the other backend don't precompile tests when running them (and neither does rakudo.js on node). It turns out that the backend indepenent part of rakudo has a bunch of undiscovered bugs. After finding this the hard way by wasting a lot of time on trying to find the root source of one or two of them in rakudo.js itself. I wrote a helper to run tests by wrapping them in modules to discover those. That approach runs into problems on some tests that can't be so easily wrapped so I'm currently working on way to precompile the tests directly on the moar backend. Once that's done I will add a spectest variant to spot those bugs easily and prevent more from getting introduced as well as help fixing all of the existing ones.
The third obstacle was that that node.js implements couroutines using the fiber module (which as far as I'm aware uses threads underneath). In the browser we use async/await for couroutines. I generate code that's usable by both approaches by emitting commented out /*async*/ and /*await*/ keywords and doing a fairly cheap textual substitution when needed later on.
It turned out a bunch of awaits (and a few asyncs) where missing which resulted in often strange bugs. I painstakingly found where they where missing and added them.
Some of the sequences tests found subtle bugs in our coroutines implementation.
The way our coroutine implementation handled exception was incorrect and needed to be fixed. I got rid of the currently handled exception stack too (and put it on the caller context).
For fixing async/await problems later found that running on a special "canary" version of node helps a lot as it has a new flag to print out stack traces for async/await.
The problem I'm going to work on next is getting source maps to work in the browser.
Some adhoc bugs caused by the bundling process will likely need to get fixed on the way.
You can use async/await in node 8 (the latest LTS).
As well as using the same code in node.js as in the browser, the install will be quicker and more reliable without the fibers module.
ps this is a super great and important project, im very excited
I'm using fibers because to avoid paying the performance price of using async/await all over the place when compiling the setting etc., with fibers you only pay when you actually use gather/take.