-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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
8305898: Alternative self-forwarding mechanism #13779
Changes from all commits
619e3fa
7dca17a
d6c0bd0
0d066ea
efb08a6
909a810
b9c8ca0
ab4aea0
15a8626
1313a45
06e555d
1d3e833
a559e8d
94e3d07
a142343
915c20b
6d39d57
eb04cd7
40c1b0b
4d9713c
39c3372
0229792
866771c
95341f0
880d564
d35cfb4
9e934ba
4895ad8
3519da7
3838ac0
cd5f237
2a00d30
dbb74fb
eee8ab5
1a4dda1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,7 @@ | |
#include "oops/oopsHierarchy.hpp" | ||
#include "runtime/atomic.hpp" | ||
#include "runtime/globals.hpp" | ||
#include "runtime/safepoint.hpp" | ||
#include "utilities/align.hpp" | ||
#include "utilities/debug.hpp" | ||
#include "utilities/macros.hpp" | ||
|
@@ -270,28 +271,87 @@ bool oopDesc::is_forwarded() const { | |
|
||
// Used by scavengers | ||
void oopDesc::forward_to(oop p) { | ||
assert(p != cast_to_oop(this) || !UseAltGCForwarding, "Must not be called with self-forwarding"); | ||
rkennke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
markWord m = markWord::encode_pointer_as_mark(p); | ||
assert(m.decode_pointer() == p, "encoding must be reversible"); | ||
assert(forwardee(m) == p, "encoding must be reversible"); | ||
set_mark(m); | ||
} | ||
|
||
void oopDesc::forward_to_self() { | ||
#ifdef _LP64 | ||
if (UseAltGCForwarding) { | ||
markWord m = mark(); | ||
// If mark is displaced, we need to preserve the real header during GC. | ||
// It will be restored to the displaced header after GC. | ||
assert(SafepointSynchronize::is_at_safepoint(), "we can only safely fetch the displaced header at safepoint"); | ||
if (m.has_displaced_mark_helper()) { | ||
m = m.displaced_mark_helper(); | ||
} | ||
m = m.set_self_forwarded(); | ||
assert(forwardee(m) == cast_to_oop(this), "encoding must be reversible"); | ||
set_mark(m); | ||
Comment on lines
+283
to
+292
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you explain why we need to restore the displaced mark word here? I wonder why it matters what the old mark word is and why this code can't be changed to something like this:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main reason why we need to implement the self-forwarding is to preserve the upper bits of the mark-word (specifically, the Klass* that we want to place there with JEP 450). If the header is displaced, we would install the self-forwarded bit in the tagged native-pointer that is in the header, meaning we loose the ability to get to the actual header to fetch the Klass*. We do restore the header later, but GC needs access to the Klass* meanwhile. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. While reviewing this patch I was thinking about the current JDK code, which as far as I understand doesn't need to restore the displaced header here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. It might be cleaner to move that part out of here and into #13961, WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that would be good. |
||
} else | ||
#endif | ||
{ | ||
forward_to(oop(this)); | ||
} | ||
} | ||
|
||
oop oopDesc::forward_to_atomic(oop p, markWord compare, atomic_memory_order order) { | ||
assert(p != cast_to_oop(this) || !UseAltGCForwarding, "Must not be called with self-forwarding"); | ||
markWord m = markWord::encode_pointer_as_mark(p); | ||
assert(m.decode_pointer() == p, "encoding must be reversible"); | ||
markWord old_mark = cas_set_mark(m, compare, order); | ||
if (old_mark == compare) { | ||
return nullptr; | ||
} else { | ||
return cast_to_oop(old_mark.decode_pointer()); | ||
return forwardee(old_mark); | ||
} | ||
} | ||
|
||
oop oopDesc::forward_to_self_atomic(markWord compare, atomic_memory_order order) { | ||
#ifdef _LP64 | ||
if (UseAltGCForwarding) { | ||
rkennke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
markWord m = compare; | ||
// If mark is displaced, we need to preserve the real header during GC. | ||
// It will be restored to the displaced header after GC. | ||
assert(SafepointSynchronize::is_at_safepoint(), "we can only safely fetch the displaced header at safepoint"); | ||
if (m.has_displaced_mark_helper()) { | ||
m = m.displaced_mark_helper(); | ||
} | ||
m = m.set_self_forwarded(); | ||
assert(forwardee(m) == cast_to_oop(this), "encoding must be reversible"); | ||
markWord old_mark = cas_set_mark(m, compare, order); | ||
if (old_mark == compare) { | ||
return nullptr; | ||
} else { | ||
assert(old_mark.is_marked(), "must be marked here"); | ||
return forwardee(old_mark); | ||
} | ||
} else | ||
#endif | ||
{ | ||
return forward_to_atomic(cast_to_oop(this), compare, order); | ||
} | ||
} | ||
|
||
oop oopDesc::forwardee(markWord header) const { | ||
assert(header.is_marked(), "only decode when actually forwarded"); | ||
#ifdef _LP64 | ||
if (header.self_forwarded()) { | ||
return cast_to_oop(this); | ||
} else | ||
#endif | ||
{ | ||
return cast_to_oop(header.decode_pointer()); | ||
rkennke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
// Note that the forwardee is not the same thing as the displaced_mark. | ||
// The forwardee is used when copying during scavenge and mark-sweep. | ||
// It does need to clear the low two locking- and GC-related bits. | ||
oop oopDesc::forwardee() const { | ||
assert(is_forwarded(), "only decode when actually forwarded"); | ||
return cast_to_oop(mark().decode_pointer()); | ||
return forwardee(mark()); | ||
} | ||
|
||
// The following method needs to be MT safe. | ||
|
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.
Shall we have a method "oop::forwardee_not_self" which guarantee to be not self fowarded? So we can remove the self-forward if-check in GC critical path.
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.
Are there any paths that don't need to handle self-forwarded state?
Also, it seems to me that the path would be dominated by the load of the mark-word. Testing-and-branching for the self-forwarded bit seems like the minor problem there. It would be nice if we could tell the C++ compiler that the branch is expected to be uncommon, so it could shape the emitted code accordingly, but, afaik, we can't.
If we were to micro-optimize the forwarding-decoding, then it would be more useful to optimize the common pattern:
To something like:
There's a way to improve further on this, as I proposed back in the early versions of #5955, which also avoids the decoding altogether if not forwarded, but it's a little more clunky:
where the scoped OopForwarding object would encapsulate the markWord and the testing and decoding of the fwd-ptr, but it has been rejected back then. But it would certainly help more than an oopDesc::forwardee_not_self() approach (if that were even possible, which I think it is not).
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.
Sorry. It's my misunderstanding. G1ParScanThreadState::do_oop_evac still needs to handle self forward.