Welcome to the main channel on the development of MoarVM, a virtual machine for NQP and Rakudo (moarvm.org). This channel is being logged for historical purposes.
Set by lizmat on 24 May 2021.
00:02 reportable6 left 02:15 [Coke] left 02:34 [Coke] joined 02:44 frost joined 02:47 releasable6 left, nativecallable6 left, nativecallable6 joined, releasable6 joined, statisfiable6 left 02:48 statisfiable6 joined 03:04 reportable6 joined 04:49 evalable6 left, linkable6 left 04:52 evalable6 joined 05:52 evalable6 left 05:53 evalable6 joined 06:02 reportable6 left 06:03 reportable6 joined 08:06 MasterDuke left
Nicholas good *, #moarvm 08:39
08:55 patrickb joined
lizmat Nicholas o/ 09:43
09:49 linkable6 joined 10:16 linkable6 left 10:19 linkable6 joined
jnthnwrthngtn moarning o/ 10:29
Nicholas \o 10:30
nine moarning goodness!
jnthnwrthngtn: did you follow my investigation yesterday evening? 10:34
10:34 janhen joined
jnthnwrthngtn nine: Not closely. 10:37
Bit short on time for Raku things this week, alas. Plus I've got a sore throat and other cold-y symptoms. :/ 10:38
nine jnthnwrthngtn: oh, sad to hear that :/ Hope you'll get better soon 10:39
Nicholas :/
jnthnwrthngtn On the upside, I do now have my permanent residence permit at last. :)
Yeah, I'm hoping it's just a boring "was walking in cold weather, caught a cold" thing rather than anything more sinister. 10:40
Nicholas So you never need to visit the wrong side of Prague again? :-)
nine jnthnwrthngtn: the one question on which I'd really appreciate input is: return_o calls MVM_try_return which finds an exit handler on the current frame. It then calls MVM_frame_dispatch_from_c to run this exit handler. MVM_frame_dispatch_from_c set's the caller's return address to current cur_op. But that was already advanced, so it actually points right at the end of the bytecode. So when we return from the 10:41
jnthnwrthngtn Well, not for 10 years or so.
nine exit handler the runloop exits the bytecode. How is this supposed to work?
Nicholas in 10 years we might even have self driving taxis... 10:42
jnthnwrthngtn nine: At the point we call the exit handler block the frame whose exit handler it is is still on the stack, since dynamics should be in scope. Ahead of the dispatch_from_c it sets a special return handler for remove_after_handler. When we finish running the LEAVE block, we return_o from it. That frame is removed from the callstack, we then also find the special return handler, which in turn triggers removal 10:45
of one further frame.
The return address that is written in dispatch_from_c should never be relevant in so far as we never truly return into the frame in question, but the special return handler removes it also. 10:46
This is how it's meant to work and how the code looks, but I'm guessing if you're asking, it can somehow go wrong. 10:47
fwiw, I'd planned to re-work this lot so that a) we install code ahead of the return_o to run the exit handler, and b) static frames carry an "exit handler address" so we can also run it during unwind. 10:48
(So that in the non-exceptional case we can do stuff like inlning LEAVE blocks, or at least get rid of the massive amount of indirection and overhead imposed today)
nine jnthnwrthngtn: ok, thanks, that helps a lot! So I'll have to investigate why the special return handler (which definitely is on the stack) doesn't unwind far enough
jnthnwrthngtn Well, one thing that gets a bit icky: the special return handler is triggered from in unwind frame, which then in turn calls unwind_frame again 10:49
nine I noticed, yes
jnthnwrthngtn This should not matter, because after the special unwind there would be a frame on the stack top 10:50
nine I'm very much looking forward to knowing the explanation. Most of all because of that peculiar behaviour: MVM_SPESH_BLOCKING=1 makes it fail reliably but even with MVM_SPESH_LIMIT=1. So somehow there's a bit of spesh in there but not because of actually speshed frames
jnthnwrthngtn And that's the termination condition for the loop.
Oh. That's weird. 10:51
And disabling spesh fixes it? Does it need blocking to be on, or does LIMIT=1 block it?
iirc disabling spesh also disables the optimization that sees us allocate frames right off on the heap if we see they tend to get promoted 10:52
nine So far I haven't seen a failure with spesh disabled.
I cought it with `MVM_SPESH_LIMIT=1 MVM_SPESH_BLOCKING=1 rr record rakudo` and confirmed that none of the involved frames are speshed
Actually it looks like it fails reliably even without MVM_SPESH_BLOCKING=1 if MVM_SPESH_LIMIT=1 is present 10:54
So really either env var will do
Which usually means "memory layout". But in any case, I'll single step through the sequence in rr. That should shine some light 10:56
11:34 evalable6 left, linkable6 left 11:35 linkable6 joined 12:02 reportable6 left 12:03 reportable6 joined 12:06 kjp left 13:06 statisfiable6 left, quotable6 left, linkable6 left, benchable6 left, reportable6 left, bloatable6 left, bisectable6 left, greppable6 left, tellable6 left, squashable6 left, notable6 left, shareable6 left, unicodable6 left, committable6 left, releasable6 left, nativecallable6 left, coverable6 left, sourceable6 left, committable6 joined, coverable6 joined, bloatable6 joined 13:07 bisectable6 joined 13:08 releasable6 joined, quotable6 joined, tellable6 joined 13:09 shareable6 joined 13:37 evalable6 joined 14:07 notable6 joined, benchable6 joined, reportable6 joined 14:08 squashable6 joined 14:09 statisfiable6 joined 14:18 vrurg joined 14:20 vrurg_ left
nine jnthnwrthngtn: ah, I think I understand what's going on. Not the spesh part, but the rest: it fails to clean up that frame, because the special return handler call stack entry is not followed directly by a frame entry. There's a region entry in between because the special return entry didn't fit into the previous region anymore 14:30
14:30 vrurg_ joined
nine When the frame is right on the top of the stack, the do/while loop cleans it up. But since it isn't, it cleans up the region and exits the loop when it finds that the new frame is a bytecode frame. 14:31
A crude hack would be adding a flag to unwind_frame that counts if a frame was actually removed and only then exits the loop 14:32
14:33 vrurg_ left, vrurg_ joined, vrurg left
jnthnwrthngtn nine: The spesh part is probably what I mentioned earlier: with spesh disabled I think we always heap-promote frames, not eagerly put them on the heap if they tend to get promoted 14:40
And thus it results in different sizes of things on the stack and creates this boundary sitaution.
I'm still slightly confused how what you're describing happens (but I can imagine it does...) 14:41
In that the nested call should mean we are entering unwind frame once for each of the 2 frames we expect to remove
And either what's on the top is a frame (and we exit it) or is not (and we work towards there being a frame on the top) 14:42
oh, hang on, I think I see it 14:43
14:43 frost left
jnthnwrthngtn Yeah. Argh. Indeed. unwind_frame should only ever really be called when there is a frame atop of the call stack. It should probably have an assertion that this is the case. 14:44
So perhaps the special return handler should also drop any continuation tag or region start records too before invoking the special return handler, *or* we should have an unwind_frame_from_anything that first clears up any region start or continuation tag records 14:46
14:53 janhen left 15:07 greppable6 joined 15:08 linkable6 joined 15:09 sourceable6 joined 16:08 nativecallable6 joined 16:20 patrickb left
nine I guess the most interesting open question is how to avoid duplicating a lot of code while keeping runtime cost at 0. I'll play around with the code a bit and see if something sticks 16:27
Well, runtime cost for non-special-return cases. There's no free lunch for the latter 16:29
jnthnwrthngtn I'd first put in the assertion that, at the entry to unwind_frame, the top-most thing is a frame 16:32
nine Apparently it's quite common for a MVM_CALLSTACK_RECORD_DISPATCH_RECORDED to be on stack_top in unwind_frame 16:33
jnthnwrthngtn That's a bit odd.
Maybe I forget, but I didn't think we used unwind_frame in the situation that we had a dispatch program that produced a non-bytecode result 16:34
nine This happens even in the first call during NQP's build in a garden variety return_o 16:36
When returning from a frame that doesn't even do any dispatch? 16:40
Ah, man, what a stupid mistake. Maybe just not put that assertion into the loop? 16:51
jnthnwrthngtn :D 16:52
Typical Fri...oh.
nine Well, I could take it as a sign, that hacking dinner dinner is more appropriate right now than hacking code. But then, do I want to use a sharp knife in my condition? :D 16:53
Anyway, when put into the right place, the assertion seems to catch this situation 16:54
17:07 unicodable6 joined, lizmat_ joined, [Coke]_ joined 17:09 leont_ joined 17:10 gfldex_ joined 17:16 [Coke] left, lizmat left, colemanx left, gfldex left, leont left, camelia left, leont_ is now known as leont 17:22 colemanx joined, camelia joined 17:32 lizmat_ left 17:33 lizmat joined 18:02 reportable6 left 18:06 [Coke]_ left 18:13 Colt joined 18:25 TempIRCLogger left, TempIRCLogger joined 18:26 [Coke] joined 18:56 Colt left 18:57 Colt joined 19:01 Colt left 19:02 Colt joined, gfldex_ is now known as gfldex 19:03 Colt left, Colt1 joined, Colt1 left 19:05 reportable6 joined 19:06 Colt joined 20:00 dogbert17 left 20:03 dogbert17 joined 20:09 dogbert11 joined, dogbert17 left 20:22 vrurg_ is now known as vrurg 20:25 dogbert11 left 20:43 dogbert11 joined 21:22 dogbert11 left 21:24 dogbert11 joined 22:15 dogbert11 left, dogbert11 joined 22:22 dogbert17 joined, dogbert11 left 23:16 dogbert11 joined 23:18 dogbert17 left