| 5 Sep 2026 | |||
| Voldenet | and yeah iirc jit only works for x86 unless it was changed, I'm kind of hoping that it's able to make this check even further somehow | 10:00 | |
| or x86_64 | |||
| even faster* | 10:01 | ||
| timo | the benchmark in question is very susceptible to a hot cache + hot preloader + hot branch predictor | 10:10 | |
| in moarvm we have two parts that might usually both be called "the jit" and only the second half is missing for non-x86-64 | 10:11 | ||
| the bytecode specializer is still in effect on every architecture we run on | |||
| apogee_ntv | If there are improvements I can do to the benchmark or suggestions on the code please tell me, happy to dig deeper, I'm just very new to the moarvm source and how it all works together. | 10:45 | |
| timo | it's the curse of every microbenchmark, really | 10:53 | |
| the right solution must be to not turn a getlexperinvtype into a constant lookup if the bytecode isn't actually specialized on the invocant type in the first place | 10:59 | ||
| apogee_ntv | Yeah, I couldn't see any way to tell if it was an invocant type from the metadata, the check that was there was just checking if arg0 was an object of a known type but for topic setting postfixes, arg0 is the topic. | 13:19 | |
| timo | yes, we may need to give moar more context to work with from the high level language | 13:24 | |
| apogee_ntv | Yeah so pass something like arg0_is_not_invocant in the frame metadata and then if it's true, fold to use the indexed pointer, if false, use the constant? | 14:01 | |
| I'd have to look at how the metadata arrives and how it gets attached | 14:02 | ||
| timo | I'm imagining it could be made a part of the callsite | 14:33 | |
| maybe there is something else we can very cheaply look up to check if we're in an actual "specialized on invocant" situation or not | 14:35 | ||
| for example, we already have a "caller is outer" flag somewhere. that could combine well with the information of "what is actually passed into its arg0" | 14:36 | ||
| I don't remember if we're inlining the frame with the problematic instruction, and whether turning inlining off makes a difference or not | 14:37 | ||
| Voldenet | it fails with `MVM_SPESH_INLINE_DISABLE=1` | 14:40 | |
| apogee_ntv | It fails under most things short of fully disabling spesh yeah | 15:33 | |
| 6 Sep 2026 | |||
| timo | i'm finally starting to recover from a pain that's been plaguing me for a week+, so i can finally think a bit more clearly about the code, but i'll be AFK all day; since we can look up lexicals at spesh time, why don't we look up ::?CLASS and see if it matches the type facts we have for the first argument? does that make sense? and if it doesn't match, we don't specialize getlexperinvtype to become | 09:35 | |
| a constant, or we take the "speculatively make it a constant but do the lookup anyway and guard" thing from the current pull request | |||
| ::?CLASS isn't necessarily the right one though, could be we have to check ::?ROLE instead or something else | |||
| I still haven't looked at the code at all for this | |||
| ok i remember now why that wouldn't work; the getlexes that we use getlexperinvtype for are all dependent on looking up their lexicals through closures, so we actually can't look the things up statically at spesh time, we have to rely on values we see in the spesh log | 09:57 | ||
| if we can't easily put a "we're invoking this not with an invocant, just with a boring regular object argument" bit of information somewhere, we may have to change where the compiler emits getlexperinvtype; IIRC it's just getlex with some special logging and semantics when spesh sees it | 09:58 | ||
| so it should never be wrong to just put getlex instead of getlexperinvtype, just less opportunity for optimization | 09:59 | ||
| the compiler probably has a much easier time figuring out if the first argument to the callable it's compiling at the moment is related to the current "invocant type" or not | 10:00 | ||
| we could also literally introduce a new op that also takes the type, or value, of the current invocant, i.e. what's in "self", so that spesh can log and/or check that at spesh time too | |||
| apogee_ntv | Would you like me to take a look at that? I'm very unfamiliar with the levels above spesh. Any suggestions for where to look first? (I want to learn the codebases but it's more than a little daunting I will admit :D) | 12:38 | |
| My instinctive thought would be to have the metadata emit a bit to say that ?::CLASS == arg0, I'm just not sure what that would cost. That way if true we could specialize on invocant and if not, use the indexed pointer as a fallback less aggressive specialization. | 12:43 | ||
| It seems knowable at compile time but my knowledge of Rakudo and the AST is minimal. | 12:44 | ||
| Alternatively the postfix should lower to the same AST as the block. | 12:46 | ||
| It feels unintuitive that one optimizes better than the other one. | |||
| timo | I assume we can't just inline the block because it sets $_ and $_ is dynamically scoped? | 19:29 | |
| lizmat | $_ *was* dynamically scoped in 6.c, but no longer in 6.d | 19:30 | |
| m: use v6.c; dd $_.VAR.dynamic | 19:31 | ||
| camelia | Bool::True | ||
| lizmat | m: use v6.d; dd $_.VAR.dynamic | ||
| camelia | Bool::False | ||
| timo | on the other hand, lexical-to-local-lowering should already be able to handle $_ regularly for the case of a `with True { ... }` or `... with True` | 19:32 | |
| actually, how do we handle $_ at the moment with a postfix with or postfix if? can we inline that form properly? | 19:33 | ||
| a difference between `with True { ... }` and `... with True` is that one logically introduces a scope that is also visible to introspection with OUTER:: and what-not | 19:36 | ||
| godbolt.org/z/KjeG7Exfr btw did you all already know about this | 19:43 | ||
| apogee_ntv | Postfix with is the case on the ticket, arg0 ends up as $foo in 'with $foo' so if $foo is an object with a known type, it gets specialized on $foo (which doesn't work when it's a role method being composed by a class -- the class lookup uses the original calling class). | 20:40 | |
| so any call to the method with Str (for example) looks up the specialization against the wrong role-composed class. | 20:41 | ||
| If you call with $foo as an Int, it works fine because that isnt specialized yet | 20:42 | ||
| timo | have you already looked into the spesh log emitted for the test code? | 20:45 | |
| apogee_ntv | I did but it was the day I filed the ticket so I've forgotten most of it :D | 20:46 | |
| timo | also before some more golfing I think? | ||
| apogee_ntv | Voldenet did the golfing IIRC. I just added the Int test to try to falsify my theory. | 21:18 | |
| 7 Sep 2026 | |||
| lizmat | . | 07:40 | |
| 12 Sep 2026 | |||
| MasterDuke | timo: lalitm.com/post/buildprof/ seems like something you'd be interested in | 20:43 | |
| imgur.com/a/73DYhQy screenshot of the output after profiling a rakudo build | 20:52 | ||