<div dir="ltr"><div>Hi Florin,</div><div><br></div>What you're describing is a subset of the block optimizations present in other Smalltalk.<div><br><div>What typically happens in some other Smalltalks:</div><div>1 Blocks without any uses of the enclosing environment (variables or non local returns) are called clean block, the BlockClosure instance can be created at compiled time, such blocks do not require any allocation at runtime, this is what you described for empty blocks.</div><div>2 Blocks without non local returns are called copying block, the BlockClosure instance has to be created at runtime to hold copied values and the indirection vector if required, but does not need to hold a reference to the outerContext, which in practice allows some optimizations (in Cog it avoids allocation an object to marry the frame, in GraalSqueak it would allow to avoid having a virtual frame for the block outer context in some cases).</div></div><div>3 Blocks with non local returns are full blocks, and everything is required.</div><div><br></div><div>By default Squeak only uses 3, the reason is that 1 and 2 decrease debugging possibilities, and 1 also messes up identity. Your optimization has both flaws. Of course, if you do the optimization only for empty blocks, and not for all blocks without access to the enclosing environment, you limit the damage done reducing debugging possibilities (when inspecting the empty block the outer context reference would be nil instead of the outer context, but you cannot step in the debugger into empty blocks, so damage is limited). You still mess up identity. Here are code snippets showing the 2 problems:</div><div><u>Debugging</u></div><div>DoIt>> [ ] outerContext == thisContext.</div><div>With your optimization the DoIt now yields a different result (false instead of true)</div><div><u>Identity</u></div><div>A>>foo</div><div>  ^ [ ]</div><div>DoIt>> A new foo == A new foo.</div><div>With your optimization the DoIt now yields a different result (true instead of false)</div><div><br></div><div>One idea by moving from BlockClosure to FullBlockClosure (with a dedicated compiled block per closure) was, among other things, to allow block 1 and 2 to be implemented easily. There are various issues with the startpc hack that FullBlockClosure solves in a nice way. For example, if you try to do your optimization in Cog, Cog's JIT may get confused on where to find the bytecode of the BlockClosure stored in the literal and the optimization may not work (Cog does not JIT unreachable bytecode). The outerContext reference can also be nil instead of a fake context with full blocks, there's a bit in the full block closure instruction for this case.</div><div><br></div><div>It would be also interesting to implement Block 2 in GraalSqueak and see how much it reduces deoptimization metadata. I believe Tim did some similar experiment in RSqueak.</div><div><div><br></div><div>Good luck implementing your optimization. Have fun :-)</div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Jan 11, 2020 at 7:42 AM Florin Mateoc <<a href="mailto:florin.mateoc@gmail.com">florin.mateoc@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> <div dir="ltr"><div>Hi,</div><div><br></div><div>I was thinking of implementing a relatively simple optimization for empty blocks - there's something in the air about blocks lately :)</div><div><br></div><div>The compiler would create them as a new kind of literal (a subclass of BlockClosure), so there would be no block creation at runtime. Even the bytecodes for them would be simplified - it would be just a load literal. As far as I can tell, this would also not require any VM or bytecode changes.

</div><div>I also don't think they would clash with the coming full block closures.</div><div><br>
</div><div>See attached to see what the new class definition would look like. By employing Eliot's trick of re-using startpc, they can even return a non-nil constant or other literals, and thus can even cover a little more than just purely empty blocks. And we could also reuse these literals, there is no point in creating multiple instances for []. <br></div><div>Given how often we use "at: aKey ifAbsent: []" or "detect: [:| ...] ifNone: []", I think it would be worth it, but let's see what you guys think. <br></div><div>Worst case, I'll just implement it in GraalSqueak :). Just kidding, I'll do it in GraalSqueak anyway :)</div><div><br></div><div>Florin<br></div></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><span style="font-size:12.8px">Clément Béra<br></span><span style="color:rgb(0,0,238)"><a href="https://clementbera.github.io/" target="_blank">https://clementbera.github.io/</a></span><div style="font-size:12.8px"><a href="https://clementbera.wordpress.com/" target="_blank">https://clementbera.wordpress.com/</a></div></div></div></div></div></div>