ExceptionRegion modeling issues and proposed improvements

Paul Sandoz paul.sandoz at oracle.com
Wed Oct 9 20:04:42 UTC 2024


Hi Adam,

Thanks. I better understand the complexities of a dominating enter paired with an exit. It all works out when lowering models, it fits well with the code model rules, likely making analysis easier such as identifying various sub-graphs (e.g. extract and replace), and interpretation is really straightforward. But that structural constraint makes it very hard to reverse engineer from bytecode exception tables (and arguably generate them too).

It seems preferable when lowering to produce the nested structure we have today (and it comes out naturally when lowering - transformations might merge), but lifting does not require it.

I think it would be useful to derive the set of behavioral rules for your proposal e.g., describe how an interpreter would process operations, validate them, and handle exceptions throw by operations covered by regions
e.g.,

- when an exception region enter is encountered referring to catch blocks A, B, C then an exception region is entered and A, B, C are pushed, in order, onto the catch block stack
- when an exception region exit is encountered referring to catch blocks C, B, A then the exception region is exited and C, B, A are expected, in order, to be on the top of the catch block stack and are popped off

Is the catch block stack order important? Can we encounter an exception region exit that refers to B when the top of the stack is C?

Paul.


On Oct 9, 2024, at 2:43 AM, Adam Sotona <adam.sotona at oracle.com> wrote:

Hi Paul,
see my comments inline.

From: Paul Sandoz <paul.sandoz at oracle.com<mailto:paul.sandoz at oracle.com>>

> I am guessing you explicitly generated the bytecode example? although it is indicative of similar issues for bytecode generated from source?

I've prepared the example as synthetic, however code compiled from source can contain split try blocks and handlers detached from their natural position according to the code flow. Try catch blocks and handlers are position-based, so every bytecode instruction can easily identify the exception stack, however hardly to reach that state from code flow. In many situations a single bci offset is almost a singularity, where BytecodeLift needs to create a graph of synthetic blocks representing various flow transitions around that point.

> It’s not clear to me from this example why we need to detach the referencing of catch blocks from the exception region entry op.


Yes, the example was not the best. The main point is that requirement to match exception region exit with its dominant region entry is extremely complex. Single-entry style of the exception region model is far from the exception table wrapping bytecode offsets orthogonally to the code flow.

> Will it always be the case that an exception.region.enter will dominate a corresponding exception.region.exit? It seems so, and if so an exit can reference an enter.

Unfortunately, no.  Exception.region.exit from the given exception.region will always be dominated by a set of exception.region.entries into the same region, however not always dominated by the single specific exception.region.enter. Entries to the region represent a set dominant to the exits, however they might not be individually dominant.


> Is it related to region exit and re-entry along some particular path of control where eventually all paths join to the region exit?

The exception regions are in many cases orthogonal to the flow graph, so the condition that re-entries should be dominated by a single entry does not reduce the complexity.

> AFAICT another change in behavior is that a return from a method requires no preceding region exits (similar to throw).

I didn't notice there is a difference between athrow and return now. Both are terminating the code flow so how the exception stack should behave after return according to the current model?

> Also with your proposal I don’t yet know the implications when lowering try/catch/finally blocks.

As we discussed - if it is no allowed to jump randomly across bodies, it is probably difficult to model try/catch/finally using the bodies, because the flow may jump across them. If a body can have multiple enter and exit points (and related continuations inside the body and in the parent body flow), then it can model also split try/catch/finally blocks with breaks and continues. If we have this, lift directly to this model and skip the low level exception regions.


> What about the following? (I am unsure of the cbranch in block_4)

As I mentioned above - the single entry dominance condition does not reduce the complexity. Unless we will workaround it by entering and exiting all regions in the entry block, so all following entries will have its single dominant entry. It is similar to the variables initial value, which needs to be initialized with synthetic default value when there is no single dominant VarStoreOp. My proposal makes ExceptionRegion similar to Var declaration (without an initial value).

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/babylon-dev/attachments/20241009/cf46cfe2/attachment-0001.htm>


More information about the babylon-dev mailing list