January report of the Perl 6 Development Grant of Jonathan Worthington
Mon, 11-Feb-2019 by
Matthias Bloch
edit post
Jonathan writes:
January was a busy and productive month for my Perl 6 grant work.
Back in November, I was working on allowing us to lower lexical variables into locals. This is possible when they are not closed over, and allows for generation of more efficient code, which is in turn much easier for backends - MoarVM, the JVM, and JavaScript - to deal with in their own optimizers. It can also shorten the lifetimes of objects, leading to better memory performance. I completed and merged the almost-complete work to be able to lower normal variable declarations (such as `my $a = 42`). This will combine well with the ongoing work on escape analysis, since it will be able to eliminate many allocations of Scalar containers.
The next step was to take on the lowering of `$_`. In Perl 6.d, we made this a normal lexical rather than a dynamic lexical (available through `CALLER::`) in order to allow further analysis and optimization. Relatively few Perl 6 users were aware of its dynamic nature anyway, and fewer still making use of it. With the topic variable of course showing up in numerous common idioms, it would be a pity to then have people avoid them in the name of performance, due to the dynamic nature of `$_` impeding analysis. Thus the change in 6.d.
This month I worked on implementing the most immediate optimization that this enabled: being able to also lower `$_` into a local. In a loop like `for 1..10_000_000 { something() }`, previously we would have to allocate an `Int` object for every single iteration. Since `$_` was dynamic, we could not be sure that `something()` - or anything it in turned called - would not access it. Under the new semantics, we can lower it into a local, and then dead code analysis can see that the boxing is useless and discard it, saving a memory allocation every iteration. Even were it used, for example in an array index, we now have opened the door to being able to use escape anslysis in the future to also avoid the allocation.
This work had some amount of fallout, and turned up some rather dubious semantics around regexes matching against the topic variable when in boolean or sink context. This included some curious "at a distance" behavior, where things either worked by a happy accident, or could potentially match against completely unexpected data further down the callstack thanks to the thing they were expected to match against being undefined! I proposed a cleaner set of behaviors here and, with a lack of objections, implemented them.
Along with these optimizations, I also implemented more aggressive scope flattening in Rakudo's static optimizer. When we can show that a particular scope's existence would not be missed - such as the body of an `if` statement which doesn't have any variables in it that get closed over - we can flatten it into the surrouding block. This is a bit cheaper at runtime and leads to more chances to do lexical to local lowering, which - as already mentioned - is the gateway to further optimizations.
Back over in MoarVM, I continued my work on escape analysis and scalar replacement. I took a small detour to implement retention of deoptimization information in specialized bytecode, so we can recover it when inlining. This will allow us to more aggressively optimize code that we inline. I didn't yet enable the full set of optimizations we might do there, but I was able to enable dead instruction elimination, which can save some work (for example, if we see a return value is unused, we can strip out the work that produces it). This more detailed data was also required for the analysis algorithm that works out which object allocations that we eliminate as part of a scalar repalcement need to be restored when deoptimizing. I got most of that worked out, with a few issues left before it could be merged. (Spoiler: those were resolved in early February and it was merged.)
The lexical to local lowering optimization in Rakudo results in lower quality information being available to debuggers, and with the scope of it greatly expanding with my recent work this would have become quite noticeable. I implemented a new mechanism to retain symbol mappings in order to counteract that.
Further to this work, I worked on 8 other smaller issues.
15:50 Lexical to local lowering, including of $_ where possible
07:59 More aggressive block flattening
05:33 Keep deopt information when inlining, allowing more dead code elimination
07:59 Implement deoptimization of scalar-replaced allocations
00:56 Fix sometimes-missing redeclaration error
01:47 Make exceptions doing X::Control be thrown as control exceptions
01:06 Fix hang when a Channel with a reactive subscription was closed and then drained.
00:48 Look into a crash in t/04-nativecall/06-struct.t, comment on issue
01:59 Track down a runaway memory use spesh plugin bug and fix it
00:42 Fix inaccurate reporting of line numbers in simple routines
06:04 Preserve symbol names for debug in lexical to local lowering
00:39 Fix reporting of Failure where exception has no message method
03:18 Analyze and fix an optimizer bug with when inside a loop
Total: 54:39
Of which were covered by previous grant period: 48:30
Of which were covered by current grant period: 6:09
Remaining funding-approved hours on current grant period: 160:51
Remaining community-approved hours on current grant period: 326:51
Category:
(none)
Comments (0)