-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
8317376: Minor improvements to the 'this' escape analyzer #16208
Conversation
👋 Welcome back acobbs! A progress list of the required criteria for merging this PR into |
@archiecobbs The following labels will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command. |
42f376a
to
fa049a4
Compare
- Track direct, indirect, and outer references for all Ref types. - Keep type information about all references to improve tracking precision. - Track enhanced for() invocations of iterator(), hasNext(), and next(). - Don't report an escape of a non-public outer instances as a leak. - Fix omitted tracking of references from newly instantiated instances. - Fix omitted tracking of leaks via lambda return values. - Remove unneccesary suppressions of this-escape lint warning.
fa049a4
to
03754eb
Compare
@archiecobbs this pull request can not be integrated into git checkout JDK-8317376
git fetch https://git.openjdk.org/jdk.git master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push |
Hummm... I know a few (two) places in |
No, the goal here is simply to remove unnecessary build flags. All Java code is compiled with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The build changes look ok.
@archiecobbs This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
/pingbot |
@archiecobbs Unknown command |
@archiecobbs This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
@archiecobbs This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 161 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@erikj79, @vicente-romero-oracle) but any other Committer may sponsor as well. ➡️ To flag this PR as ready for integration with the above commit message, type |
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks sensible to me
/integrate |
@archiecobbs |
/sponsor |
Going to push as commit 0646284.
Your commit was automatically rebased without conflicts. |
@vicente-romero-oracle @archiecobbs Pushed as commit 0646284. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Please review several fixes and improvements to the
this-escape
lint warning analyzer.The goal here is to apply some relatively simple logical fixes that improve the precision and accuracy of the analyzer, and capture the remaining low-hanging fruit so we can consider the analyzer relatively complete with respect to what's feasible with its current design.
Although the changes are small from a logical point of view, they generate a fairly large patch due to impact of refactoring (sorry!). Most of the patch derives from the first two changes listed below.
The changes are summarized here:
1. Generalize how we categorize references
The
Ref
class hierarchy models the various ways in which, at any point during the execution of a constructor or some other method/constructor that it invokes, there can be live references to the original object under construction lying around. We then look for places where one of theseRef
's might be passed to a subclass method. In other words, the analyzer keeps track of these references and watches what happens to them as the code executes so it can catch them trying to "escape".Previously the
Ref
categories were:ThisRef
- The current instance of the (non-static) method or constructor being analyzedOuterRef
- The current outer instance of the (non-static) method or constructor being analyzedVarRef
- A local variable or method parameter currently in scopeExprRef
- An object reference sitting on top of the Java execution stackYieldRef
- The current switch expression's yield value(s)ReturnRef
- The current method's return value(s)For each of those types, we further classified the "indirection" of the reference, i.e., whether the reference was direct (from the thing itself) or indirect (from something the thing referenced).
The problem with that hierarchy is that we could only track outer instance references that happened to be associated with the current instance. So we might know that
this
had an outer instance reference, but if we saidvar x = this
we wouldn't know thatx
had an outer instance reference.In other words, we should be treating "via an outer instance" as just another flavor of indirection along with "direct" and "indirect".
As a result, with this patch the
OuterRef
class goes away and a newIndirection
enum has been created, with valuesDIRECT
,INDIRECT
, andOUTER
.2. Track the types of all references
By keeping track of the actual type of each reference (as opposed to just looking at its compile-time type), we can make more precise calculations. We weren't doing this before.
For example consider this class:
Previously we would not have detected a 'this' escape because we wouldn't have known that variable
r
is aLeaker$1
, which allows us to deduce thatr.run()
is actuallyLeaker$1.run()
(which we can analyze) instead of justRunnable.run()
(which we can't).Because of this change, some
Ref
types that were previously singletons are no longer singletons. For example, now there can be more than oneReturnRef
in scope at any time, representing different possible types for the method's return value.3. Handling of non-public outer instances
To eliminate some false positives, we no longer warn if a leak happens solely due to a "non-public" outer instance.
For example, consider this code:
The outer
Test
instance associated with objects of typeTest.Inner
is considered "non-public" because it's not directly accessible to the outside world (becauseTest.Inner
is a private class). So while it's true that instances ofTest.Inner
retain a reference to their enclosing instance, an unrelated method likeSystem.out.println()
wouldn't know how to access them. The only way aTest.Inner
could leak its outer instance to such a method is if it did so (perhaps indirectly) through some entrée that the method "knows about". Of course, that's possible, but absent any further analysis (which could be added in the future), the cost/reward trade-off doesn't seem worth generating a warning here.This is an area for future research. In other words: when a
Ref
is passed to unknown code, when is it worth complaining about a leak, and when should we just be silent? Previously we always complained, but now that we have more information about references (namely, their types) we can be a little more discriminating.In any case, this decision is encapsulated in a new method
triggersUnknownInvokeLeak()
.4. Fix tracking of new instances
Previously we were not tracking references from a constructor's "return value", i.e., the new instance. We fix this by pretending that constructors end with
return this
.5. Fix tracking of enhanced
for()
loopsPreviously we were not tracking the implicit invocations of
iterator()
,hasNext()
, andnext()
associated with enhancedfor()
loops. This patch adds that tracking.6. Fix leaks via return values from lambdas and method references
Leaks inside lambdas and methods referred-to by method reference were being detected properly, but leaks from the return values of those things were not.
So for example, this code would escape notice:
This patch fixes this omission.
7. Some minor refactoring to make the code clearer
Ref
methodstoDirect()
,toIndirect()
,toOuter()
, andfromOuter()
8. Remove some unnecessary suppression
Several
*.gmk
build files were suppressingthis-escape
warnings unnecessarily. These have been updated.Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/16208/head:pull/16208
$ git checkout pull/16208
Update a local copy of the PR:
$ git checkout pull/16208
$ git pull https://git.openjdk.org/jdk.git pull/16208/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 16208
View PR using the GUI difftool:
$ git pr show -t 16208
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/16208.diff
Webrev
Link to Webrev Comment