Bug 303448 - Wrong code generation optimization when assert condition is false
Summary: Wrong code generation optimization when assert condition is false
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.6   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 3.6 M6   Edit
Assignee: Ayushman Jain CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-02-21 18:30 EST by Olivier Thomann CLA
Modified: 2010-03-08 13:47 EST (History)
0 users

See Also:
Olivier_Thomann: review+


Attachments
proposed fix v0.5 + regression tests (62.28 KB, patch)
2010-02-24 05:14 EST, Ayushman Jain CLA
Olivier_Thomann: iplog+
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Olivier Thomann CLA 2010-02-21 18:30:48 EST
Fup of bug 250056.
See bug 250056 comment 11.
Comment 1 Ayushman Jain CLA 2010-02-24 05:14:26 EST
Created attachment 160043 [details]
proposed fix v0.5 + regression tests

The approach is : if any variable is checked against null inside an assert expression, we encode this information in the array UnconditionalFlowInfo$nullStatusChangedInAssert by setting a bit corresponding to its position. This is done via UnconditionalFlowInfo#markedAsNullOrNonNullInAssertExpression(LocalVariableBinding).  So everytime we encounter an if statement where there is a redundant or always false null check , we check if the variable had been marked as null or non null in an assert expression, and if it is, then we dont set the UNREACHABLE bit to optimize code gen. We do this checking via UnconditionalFlowInfo#isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding).

UnconditionalFlowInfo#combineNullStatusChangeInAssertInfo(UnconditionalFlowInfo otherInits) is a helper method which merges the array UnconditionalFlowInfo$nullStatusChangedInAssert in two separate flowInfos.

Also note that the Dead Code warnings no longer appear inside if else blocks in which the condition contains a local variable which was compared with null in an earlier assert expression. This makes sense because just like we dont want to optimize code gen, we also dont want to report over-aggressive dead code warnings when asserts are disabled. All changes in NullReferenceTests pertain to this.
Comment 2 Olivier Thomann CLA 2010-02-24 13:05:13 EST
Patch looks good.
I'll release it later today.
I'll rewrite a bit the constants in FlowContext to look like:
public static final int CAN_ONLY_NULL_NON_NULL = 0x0000;
//check against null and non null, with definite values -- comparisons
public static final int CAN_ONLY_NULL = 0x0001;
//check against null, with definite values -- comparisons
public static final int CAN_ONLY_NON_NULL = 0x0002;
//check against non null, with definite values -- comparisons
public static final int MAY_NULL = 0x0003;
// check against null, with potential values -- NPE guard
public static final int CHECK_MASK = 0x00FF;
public static final int IN_COMPARISON_NULL = 0x0100;
public static final int IN_COMPARISON_NON_NULL = 0x0200;
// check happened in a comparison
public static final int IN_ASSIGNMENT = 0x0300;
// check happened in an assignment
public static final int IN_INSTANCEOF = 0x0400;
// check happened in an instanceof expression
public static final int CONTEXT_MASK = ~CHECK_MASK;

I never really liked multiple field declarations as in current codebase.
Comment 3 Ayushman Jain CLA 2010-02-24 13:18:16 EST
(In reply to comment #2)
> I'll rewrite a bit the constants in FlowContext to look like:
Ok.

BTW, i forgot to ask one thing. In the 4 new tests introduced in ConformTest.java, the disassembled output contains a different number for diff compliance levels for the method foo, ie. basically the first line of the output - "Method descriptor #x" where x is different for compliance level 1.4, 1.5 and 1.6. I couldnt find an explanation for it, though I'm pretty sure its not a bug or anything. Do you have an idea why this happens?
Comment 4 Olivier Thomann CLA 2010-02-24 13:37:08 EST
(In reply to comment #3)
> BTW, i forgot to ask one thing. In the 4 new tests introduced in
> ConformTest.java, the disassembled output contains a different number for diff
> compliance levels for the method foo, ie. basically the first line of the
> output - "Method descriptor #x" where x is different for compliance level 1.4,
> 1.5 and 1.6. I couldnt find an explanation for it, though I'm pretty sure its
> not a bug or anything. Do you have an idea why this happens?
In 1.4 the code generation for the assert statement ends up with different bytecodes.
In 1.4, the synthetic bit is an attribute and in other versions it is a modifier.

This has a side-effect on the reference into the constant pool (indexes becomes slightly different).

For difference between 1.5 and 1.6, it comes from the fact that the static initializer has a stack map attribute in 1.6 that doesn't exist in 1.5. This also creates an offset in the references to constant pool entries.

Hope this clarifies it.
Comment 5 Ayushman Jain CLA 2010-02-24 13:45:26 EST
(In reply to comment #4)

> Hope this clarifies it.

Yup. Thanks!
Comment 6 Olivier Thomann CLA 2010-02-24 15:22:36 EST
Released for 3.6M6 with changes reported in comment 2.
Regression tests in:
org.eclipse.jdt.core.tests.compiler.regression.NullReferenceTest#testBug303448a
org.eclipse.jdt.core.tests.compiler.regression.NullReferenceTest#testBug303448b

And updated existing tests.
Comment 7 Olivier Thomann CLA 2010-03-08 13:47:07 EST
Verified for 3.6M6 using I20100307-2000.