Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix typetools/checker-framework issue#3249 #132

Closed
wants to merge 9 commits into from

Conversation

d367wang
Copy link

@d367wang d367wang commented May 19, 2020

This PR fixes typetools#3249

Copy link
Member

@wmdietl wmdietl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this fix!
Can you add test cases for typetools#1727 and typetools#3249 to show that the issue is actually fixed?

output += "boolean literal is true\n";
isWhileTrue = true;
} else {
if (nodeList.size() > firstConditionPos + 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does javac treat while (!false) as a special case?
Is it really worth handling such unusual code?


boolean isWhileTrue = false;
int firstConditionPos = nodeList.size();
String output = "First condition position" + String.valueOf(firstConditionPos) + "\n";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove the debug output and the commented-out assert below.

@@ -4878,8 +4878,34 @@ public Node visitWhileLoop(WhileLoopTree tree, Void p) {

// Condition
addLabelForNextNode(conditionStart);

boolean isWhileTrue = false;
int firstConditionPos = nodeList.size();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of going through the converted nodes, wouldn't it be easier to just look at the condition tree and see whether it's the literal true?


while (true) {
B op = getB();
// :: warning: (known.nonnull)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead you could make the return type of getB @Nullable B. Otherwise the example isn't very convincing...


// Is condition constant true?
boolean isWhileTrue = false;

if (tree.getCondition() != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the condition tree could ever be null, could it?
So maybe change this to

if (tree.getCondition() == null) {
  raise error;
}

Then you can move the declaration of isWhileTrue to line 4906 and simply have boolean isWhileTrue = condType.isTrue() and avoid the unnecessary initialization with false.

extendWithExtendedNode(cjump);

if (!isWhileTrue) {
ConditionalJump cjump = new ConditionalJump(loopEntry, loopExit);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment here to explain why we do this.

extendWithExtendedNode(new UnconditionalJump(conditionStart));

// If the condition is constant true, the successor of loop end is loop entry, instead
// of condition start
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

End the sentence with .

}

// Loop body
addLabelForNextNode(loopEntry);
if (tree.getStatement() != null) {
scan(tree.getStatement(), p);
}
extendWithExtendedNode(new UnconditionalJump(conditionStart));

// If the condition is constant true, the successor of loop end is loop entry, instead
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the effect of this change? Is it really necessary to skip the condition for a while true?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, Javac bytecode generator merges the control flow at the end of the loop body with the condition start, so this change is just an optimization.

checker/tests/nullness/flow/Issue3249.java Show resolved Hide resolved
@d367wang d367wang requested a review from wmdietl June 8, 2020 23:59
Copy link
Member

@wmdietl wmdietl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more small comments to address.
Once they are and tests pass, please make a PR against typetools and we'll continue there.

local = 1;
break;
}
// :: error: (assignment.type.incompatible)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting that this isn't a constant... do you understand why? If you do, add a comment to explain.

if (tree.getCondition() != null) {
unbox(scan(tree.getCondition(), p));

// Is condition constant true?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should go to the declaration of isWhileTrue a bit further down.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, there is already documentation down there, so just remove this.

unbox(scan(tree.getCondition(), p));

// Is condition constant true?
assert tree.getCondition() != null : "while loop condition must not be null";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made this change throughout in typetools#3364
I didn't add descriptions, so to avoid a merge problem maybe remove the one here as well.


// Is condition constant true?
assert tree.getCondition() != null : "while loop condition must not be null";
// Check whether the loop condition is constant true, the criteria is consistent with
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about Determine whether loop condition is a constant true, according to the compiler logic.?


unbox(scan(tree.getCondition(), p));

// If the loop condition is not constant true, the control flow is split into two
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this comment into the then block.

@@ -4908,7 +4919,15 @@ public Node visitWhileLoop(WhileLoopTree tree, Void p) {
if (tree.getStatement() != null) {
scan(tree.getStatement(), p);
}
extendWithExtendedNode(new UnconditionalJump(conditionStart));

// If the condition is constant true, for the purpose of improving the dataflow analysis
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the performance argument rather weak - it's a constant true expression.
I would add a brief comment to the then and else block, just stating something like:
then: The condition is constant true so we can directly jump back to the loop entry.
else: Otherwise, jump back to evaluate the condition.

@d367wang d367wang requested a review from wmdietl June 15, 2020 10:02
Copy link
Member

@wmdietl wmdietl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks very nice now! Please close the PR here and move it to typetools.

@d367wang d367wang closed this Jun 17, 2020
@wmdietl
Copy link
Member

wmdietl commented Jun 18, 2020

New PR is here typetools#3389

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CFG for while (true)
2 participants