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
8262295: C2: Out-of-Bounds Array Load from Clone Source #2708
8262295: C2: Out-of-Bounds Array Load from Clone Source #2708
Conversation
👋 Welcome back rrich! A progress list of the required criteria for merging this PR into |
c193fd9
to
bba51bb
Compare
bba51bb
to
a56f8d2
Compare
Webrevs
|
* | ||
* @build sun.hotspot.WhiteBox | ||
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox | ||
* @run main/othervm -XX:+UseSerialGC -Xmx128m |
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.
Add * @requires vm.gc.Serial
to avoid conflict when testing env specifies different GC.
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.
Done. Good you spotted this.
@@ -533,7 +533,23 @@ bool MemNode::detect_ptr_independence(Node* p1, AllocateNode* a1, | |||
Node* LoadNode::find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const { | |||
ArrayCopyNode* ac = find_array_copy_clone(phase, ld_alloc, mem); | |||
if (ac != NULL) { | |||
return ac; | |||
Node* ld_addp = in(MemNode::Address); |
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.
I think you need to check (ld_addp->is_AddP()) as at line #560.
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.
Ok, I've added the check.
src/hotspot/share/opto/memnode.cpp
Outdated
Node* src = ac->in(ArrayCopyNode::Src); | ||
const TypeAryPtr* ary_t = phase->type(src)->isa_aryptr(); | ||
|
||
if (ary_t != NULL) { |
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.
Needs Comment explaining what code does.
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.
Ok, I've added a few lines of comment. Let me know if you think something's still missing.
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.
Nice.
@reinrich 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 141 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. ➡️ To integrate this PR with the above commit message to the |
Thank you for your review Vladimir. |
src/hotspot/share/opto/memnode.cpp
Outdated
const TypeX* ld_offs_t = phase->type(ld_offs)->isa_intptr_t(); | ||
const TypeInt* sizetype = ary_t->size(); | ||
|
||
if (ld_offs_t->_lo >= header && ld_offs_t->_hi < sizetype->_lo * elemsize + header) { |
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.
Isn't there a risk of overflow with sizetype->_lo * elemsize + header?
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.
Yes, I agree. What about using jlong for elemsize and header?
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.
Yes, I agree. What about using jlong for elemsize and header?
Sounds ok to me.
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.
Ok, done.
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 good!
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 good to me.
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 good to me. Just wondering, is the load still hoisted if the source array is a constant array?
src/hotspot/share/opto/memnode.cpp
Outdated
const TypeX* ld_offs_t = phase->type(ld_offs)->isa_intptr_t(); | ||
const TypeInt* sizetype = ary_t->size(); | ||
|
||
if (ld_offs_t->_lo >= header && ld_offs_t->_hi < sizetype->_lo * elemsize + header) { |
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.
Please add parentheses around sizetype->_lo * elemsize + header
.
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.
Done.
In the example below the load from clone in L6 was hoisted to SRC. 1 public static final Integer[] SRC = new Integer[4096];
2 public static void testMethod_dontinline() throws Exception {
3 Object[] clone = SRC.clone();
4 escape1 = new Object();
5 if (SRC.length > 4) {
6 escape2 = clone[4]; // Load L
7 }
8 } Actually the allocation + arraycopy in L3 could be eliminated if it wasn't for the possible deoptimization in L4 and the reference in L6. Would be cool to do the cloning lazily during deoptimization. But probably the gain isn't worth the effort/complexity. |
Thanks for your review Tobias! |
Okay, thanks for verifying! |
EA already does that - for small arrays (EliminateAllocationArraySizeLimit = 64). The issue is size because we have to put all SRC's elements on stack for reallocation during deoptimization. Changing size
|
Yes, EA does it for small arrays. I though it could be done for large ones too. What I meant was doing the allocation and then the arraycopy too on deoptimization but my thinking was a little naive of course :) as the src array might get modified before. Sorry for that and thanks for pointing out that EA can do that for smaller arrays. |
/integrate |
@reinrich Since your change was applied there have been 194 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit 9689863. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
This c2 fix makes the optimization of loads from the result array of a
Object.clone() call dependent on a compile time range check in order to prevent
out-of-bounds array loads described in JDK-8262295.
Testing: The included reproducer test. The fix passed also our CI testing: JCK
and JTREG, also in Xcomp mode, SPECjvm2008, SPECjbb2015, SAP specific tests with
fastdebug and release builds on all platforms.
Alternatively the transformed load could be made dependent on a range check at
runtime. Based on our automated benchmarking it wouldn't be worth
it. Our benchmark results include quite a bit of noise though.
Progress
Issue
Reviewers
Download
To checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/2708/head:pull/2708
$ git checkout pull/2708
To update a local copy of the PR:
$ git checkout pull/2708
$ git pull https://git.openjdk.java.net/jdk pull/2708/head