Fix break not turning into LocalJumpError soon enough #4694
The strategy here is as it was in 1.7: mark literal blocks as "escaped" when the call they were originally passed to returns. Break operations can then immediately trigger a LocalJumpError and be rescued in all the various ways reported in #4686 and #4577.
This does not fix super calls because the additional work is nontrivial (pushing literal-closure param through a lot of code in interpreter and JIT) and the exposure surface is pretty small for super PLUS literal closure PLUS break PLUS escaping of that block.
Fixes #4686. Fixes #4577. The logic here adds finally wrappers around all call paths that receive a block. When the call exits, the block is marked "escaped" since it no longer has a method activation to go with it. This indicates that non-local flow, like break, should immediately trigger a LocalJumpError. This passes specs but has not been tested extensively with other types of call forms that receive blocks.
enebo left a comment
I think I would like the comments I made in interpreter addressed but can easily be talked out of wanting them. The null check is not used by all instrs there and duplication of block + blockType looks icky...It is a minor comment so don't let it hold us up. Otherwise it all makes sense.
I've made all suggested tweaks and I'm happy with it.
Note that I had to re-add a null check in IRRuntimeHelpers.initiateNonLocalReturn because it appears that that instruction is also used to return from a singleton class body. I saw an error in the JRuby suite, running without that null check, that looked like this:
We may want to see if this really needs to be a non-local return (@enebo).
I will open a separate issue for the known-unfixed super behavior.