-
Notifications
You must be signed in to change notification settings - Fork 5.9k
8323273: AArch64: Strengthen CompressedClassPointers initialization check for base #17437
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
Conversation
👋 Welcome back linade! A progress list of the required criteria for merging this PR into |
Can I get a review on this patch please : ) |
Ping. Can I get a review for this change? |
Don't you want to add a constraint function to CompressedClassSpaceBaseAddress in globals.hpp so invalid values are rejected during command-line parsing? |
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.
Hi @linade,
as part of Lilliput, we are planning larger changes to this code in mainline - see openjdk/lilliput#128, which will also go in a bit different form into mainline. It would be nice if you could hold off your PR until then.
But I am also not convinced the changes are needed. I see some improvements to code clarity, but those I would rather see after Lilliput hits, in a separate RFE. For the two functional main points this PR addresses:
CompressedClassSpaceBaseAddress
is a development debug-only tool that should do exactly what's on the label: dumbly enforce an address. Its only purpose is to observe the JVM's handling of this address. If that handling includes asserting, I'd like to see that. There is no need for more complexity - it is a simple tool with sharp edges and it only exists for tests.- I don't see what we gain by removing the "reserve anywhere" path. "It may fail with a high probability" is not enough reason - it also may succeed. At the cost of one additional mmap call (which we probably called before that point a hundred times) it still can prevent an early VM death.
Cheers, Thomas
@@ -586,11 +586,14 @@ ReservedSpace Metaspace::reserve_address_space_for_compressed_classes(size_t siz | |||
(char*) CompressedKlassPointers::reserve_address_space_for_compressed_classes(size, RandomizeClassSpaceLocation, | |||
optimize_for_zero_base)); | |||
|
|||
#if !defined(AARCH64) | |||
// On aarch64, this likely wouldn't satisfy the encoding constraints. |
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 don't add platform ifdefs here! We put much work into getting rid of platform-dependent sections. Also, as stated above, I think this change is not needed.
@@ -130,4 +130,14 @@ void CompressedKlassPointers::initialize(address addr, size_t len) { | |||
_base = (end <= (address)unscaled_max) ? nullptr : addr; | |||
|
|||
_range = end - _base; | |||
|
|||
DEBUG_ONLY(assert_is_valid_encoding(addr, len, _base, _shift);) |
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.
asserts are debug only, DEBUG_ONLY is not needed
@@ -67,7 +67,7 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) { | |||
const int alt_index = (ntry & 1) ? 0 : num_immediates / 2; | |||
const int index = (start_index + ntry + alt_index) % num_immediates; | |||
const uint64_t immediate = ((uint64_t)immediates[index]) << 32; | |||
assert(immediate > 0 && Assembler::operand_valid_for_logical_immediate(/*is32*/false, immediate), | |||
assert(immediate > 0 && MacroAssembler::eor_compatible_klass_encoding(immediate) >= 32, |
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 format of this helper is rather awkward. It returns 0 if the address is not compatible? Otherwise, the number of trailing zeros?
I think there is no strong need for any of this, since the original assert is already over-cautious (after all, we only test a range of hard-coded values). But if you like to add a test for the lower 32-bit, I'd just add that here, no need for these functions.
return (base == nullptr /* Zero-based encoding */ || | ||
(1ULL << MacroAssembler::eor_compatible_klass_encoding((uint64_t)base) >= range) || | ||
MacroAssembler::movk_compatible_klass_encoding((uint64_t)base)) && | ||
(shift == -1 /* Not specified */ || shift == 0); |
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.
This duplicates the assert we have in MacroAssembler; why do this twice, in two places?
return (_klass_decode_mode = KlassDecodeXor); | ||
} | ||
} | ||
|
||
const uint64_t shifted_base = | ||
(uint64_t)CompressedKlassPointers::base() >> CompressedKlassPointers::shift(); | ||
guarantee((shifted_base & 0xffff0000ffffffff) == 0, | ||
guarantee(movk_compatible_klass_encoding(shifted_base), | ||
"compressed class base bad alignment"); |
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 also think this code can benefit from a bit cleanup some time in the future, but for now I ask you to hold off: there is no pressing need at the moment, and once Lilliput things have settled, this code should be easier to work with it.
Also, there are a few more things we could improve, and I rather see those in a combined single RFE.
Thanks for pointing out. If so, I will check again after the lilliput changes are in and see if the issue still persists. (I'll also address the review feedbacks then.) But I still think the changes are needed for the following reasons.
The point at which the error handling happens is (init_globals->generate_stubs->..->load_klass->decode_klass_not_null), that is, trying to generate stubs. It doesn't look like a very good place to handle the errors from class space reservation (to me it looks like a double check). I would put asserts right after parsing the command-line value of CompressedClassSpaceBaseAddress, so that the reason of failing is clear. However, since CompressedClassSpaceBaseAddress is develop, instead of adding dedicated asserts, we could also let illegal values hit the newly added assert in CompressedKlassPointers::initialize() which is the rendezvous of all reservation code.
The problem with the "reserve anywhere" path is that it allows illegal base address to pass (which subsequently crashes vm during generate_stubs). We could check the resulting address after we "reserve anywhere". But I just think the reservation itself is futile anyway since aarch64 imposes a strong constraint which is not easy to satisfy. So I would skip that path and then hit the added assert in CompressedKlassPointers::initialize() |
Thank you. That might also work. We might not need to deliberately check for this develop value though but instead let it hit asserts in more common code (see a comment above). |
Exactly this. Not a bug. |
I think most of your changes are unnecessary, sorry, for the reasons stated in my last answer. In your patch, I dislike the duplication of the assert logic, increasing the MacroAssembler API surface, and the strange return code contract of But lets step back a bit. We worked quite hard to make the class space reservation on Arm64 to work with an extremely high probability. Do you see the "reserve_anywhere" path hit somewhere for real? If so, I'd be interested in the context - which machine (an sbc?), which linux, which kernel, which settings, and so on. Also, it would be a lot nicer to not have to worry about this at all. I took a stab last summer in adding a decoding mode that would just work with any address, similar to how PPC does it ( jdk/src/hotspot/cpu/ppc/assembler_ppc.cpp Line 467 in 3742bc6
decode_klass_not_null() , and it was not clear to me which registers were scratchable (I also did not try very hard, admittedly).
|
I think we should leave this stuff alone. Compressed klass pointer handling has been around the block a few times, and there's little possibility of providing much more benefit to our end users. We've got something that is highly reliable and almost maximally performant. |
Okay. Seeing how rare the failing of reservation is, I came to the same conclusion. |
I think the strangest thing to me is if the reservation fails (admittedly very rare if ever), the code choose to fire the error at stub generation. It's rather random---Maybe in another day, when initialization code changes and something that also decodes klass moves ahead of stub generation, the error could happen there. We would need time to associate all the appearances of the error with the root cause of the error. So why not add assertions right after reservation? You might argue that this nearly never happens in product and not worth the complication. I currently cannot argue with that because I haven't observe one myself, and I will drop the patch. But note that a single assertion would help. Perhaps consider adding one in incoming class-space refactoring?
It returns the number of bits allowed to encode a klass. So 0 means there is no space left for klass encoding. Thanks for the feedbacks though. I understand the frustration of seeing those platform dependent code in shared code. I'll try not to write anything like that again. |
Okay, you convinced me. I'm still against changes to CompressedClassSpaceBaseAddress and the removal of reserve-anywhere patch, though.
Yes, without code duplication.
A single assertion means I still need a way to know when it fires, so its condition needs to guess at the decoding logic that is hidden in MacroAssembler. I don't like that duplication.
Sorry for your frustration. You get strong pushback here because this code, in particular, has been seeing platform ifdefs blooming like mushrooms over the years - it had often been easier to add one extra block than to look at the base structure. Which made the code complex and brittle over the years. We restructured this coding recently with https://bugs.openjdk.org/browse/JDK-8312018, and I would like to keep it somewhat clean and readable. This coding is also rather tricky because it lives at the interjunction of three VM subsystems: metaspace/class space, JIT compiler (with its various CPU-specific idiosyncrasies) and CDS. |
❗ This change is not yet ready to be integrated. |
@linade 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! |
@linade This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the |
Summary:
Add a platform-dependent check for CompressedClassSpaceBaseAddress;
Remove the "reserve anywhere" attempt after the initial mapping attempt failed---this is rarely used and will likely fail anyway, because the accepted mapping is very restricted on aarch64;
Additional assertions after initialization.
Passed hotspot/jtreg/:tier1 on fastdebug
Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/17437/head:pull/17437
$ git checkout pull/17437
Update a local copy of the PR:
$ git checkout pull/17437
$ git pull https://git.openjdk.org/jdk.git pull/17437/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 17437
View PR using the GUI difftool:
$ git pr show -t 17437
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/17437.diff
Webrev
Link to Webrev Comment