Java 12: javac crash with switch expression containing try-catch-finally
Jan Lahoda
jan.lahoda at oracle.com
Tue Mar 26 13:42:35 UTC 2019
Hi Bernard,
I think I like this approach (possibly, it should also be used in the
condition switch expr. branch). Do you want to take the patch to completion?
Thanks,
Jan
On 26.3.2019 00:42, B. Blaser wrote:
> On Mon, 25 Mar 2019 at 19:33, Jan Lahoda <jan.lahoda at oracle.com> wrote:
>>
>> I've updated the patch with a version that strives to handle the boolean
>> switch expressions. Passes all tests except
>> tools/javac/switchexpr/CRT.java, which depends on the exact structure of
>> the generated code. Among other things, I'd like to see if we could
>> generate the current bytecode when there is no try-finally, which should
>> help with the CRT.java test. More testing still needed, though.
>>
>> Jan
>
> It seems we had the same problem with tests like
> 'switchexpr/ExpressionSwitchEmbedding.java'. You solved it with
> 'code.newRegSegment()' but you still allocate one temporary variable
> per 'break'.
>
> The following patch based on yours create only one temporary variable
> per switch expression and preserves roughly the same byte-code without
> 'try-finally' making tests like 'switchexpr/CRT.java' succeed.
>
> So, maybe you'll have an even better solution but 'langtools:tier1'
> along with the test you provided are OK.
>
> What do you think?
>
> Thanks,
> Bernard
>
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
> @@ -165,6 +165,7 @@
> Chain switchExpressionTrueChain;
> Chain switchExpressionFalseChain;
> List<LocalItem> stackBeforeSwitchExpression;
> + LocalItem switchResult;
>
> /** Generate code to load an integer constant.
> * @param n The integer to be loaded.
> @@ -1178,9 +1179,11 @@
>
> private void doHandleSwitchExpression(JCSwitchExpression tree) {
> List<LocalItem> prevStackBeforeSwitchExpression =
> stackBeforeSwitchExpression;
> + LocalItem prevSwitchResult = switchResult;
> int limit = code.nextreg;
> try {
> stackBeforeSwitchExpression = List.nil();
> + switchResult = null;
> if (hasTry(tree)) {
> //if the switch expression contains try-catch, the
> catch handlers need to have
> //an empty stack. So stash whole stack to local
> variables, and restore it before
> @@ -1199,6 +1202,7 @@
> stackBeforeSwitchExpression =
> stackBeforeSwitchExpression.prepend(item);
> item.store();
> }
> + switchResult = makeTemp(tree.type);
> }
> int prevLetExprStart =
> code.setLetExprStackPos(code.state.stacksize);
> try {
> @@ -1208,6 +1212,7 @@
> }
> } finally {
> stackBeforeSwitchExpression = prevStackBeforeSwitchExpression;
> + switchResult = prevSwitchResult;
> code.endScopes(limit);
> }
> }
> @@ -1707,16 +1712,22 @@
> Assert.check(code.isStatementStart());
> final Env<GenContext> targetEnv;
> if (tree.isValueBreak()) {
> - //restore stack as it was before the switch expression:
> - for (LocalItem li : stackBeforeSwitchExpression) {
> - li.load();
> - }
> if (inCondSwitchExpression) {
> CondItem value = genCond(tree.value, CRT_FLOW_TARGET);
> Chain falseJumps = value.jumpFalse();
> - targetEnv = unwindBreak(tree);
> + Env<GenContext> localEnv = unwindBreak(tree);
> code.resolve(value.trueJumps);
> + for (LocalItem li : stackBeforeSwitchExpression) {
> + li.load();
> + }
> Chain trueJumps = code.branch(goto_);
> + endFinalizerGaps(env, localEnv);
> + code.resolve(falseJumps);
> + targetEnv = unwindBreak(tree);
> + for (LocalItem li : stackBeforeSwitchExpression) {
> + li.load();
> + }
> + falseJumps = code.branch(goto_);
> if (switchExpressionTrueChain == null) {
> switchExpressionTrueChain = trueJumps;
> } else {
> @@ -1731,9 +1742,17 @@
> }
> } else {
> genExpr(tree.value, pt).load();
> - code.state.forceStackTop(tree.target.type);
> + if (switchResult != null) switchResult.store();
> targetEnv = unwindBreak(tree);
> - targetEnv.info.addExit(code.branch(goto_));
> + if (code.isAlive()) {
> + for (LocalItem li : stackBeforeSwitchExpression) {
> + li.load();
> + }
> + if (switchResult != null) switchResult.load();
> + code.state.forceStackTop(tree.target.type);
> + targetEnv.info.addExit(code.branch(goto_));
> + code.markDead();
> + }
> }
> } else {
> targetEnv = unwindBreak(tree);
>
More information about the compiler-dev
mailing list