RFR: 8316694: Implement relocation of nmethod within CodeCache [v42]

Erik Österlund eosterlund at openjdk.org
Thu Aug 21 13:23:14 UTC 2025


On Tue, 12 Aug 2025 01:17:27 GMT, Chad Rakoczy <duke at openjdk.org> wrote:

>> This PR introduces a new function to replace nmethods, addressing [JDK-8316694](https://bugs.openjdk.org/browse/JDK-8316694). It enables the creation of new nmethods from existing ones, allowing method relocation in the code heap and supporting [JDK-8328186](https://bugs.openjdk.org/browse/JDK-8328186).
>> 
>> When an nmethod is replaced, a deep copy is performed. The corresponding Java method is updated to reference the new nmethod, while the old one is marked as unused. The garbage collector handles final cleanup and deallocation.
>> 
>> This does not modify existing code paths and therefore does not benefit much from existing tests. New tests were created to test the new functionality
>> 
>> Additional Testing:
>> - [x] Linux x64 fastdebug tier 1/2/3/4
>> - [x] Linux aarch64 fastdebug tier 1/2/3/4
>
> Chad Rakoczy has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 107 commits:
> 
>  - Merge remote-tracking branch 'origin/master' into JDK-8316694-Final
>  - Lock nmethod::relocate behind experimental flag
>  - Use CompiledICLocker instead of CompiledIC_lock
>  - Fix spacing
>  - Update NMethod.java with immutable data changes
>  - Rename method to nm
>  - Add assert before freeing immutable data
>  - Reorder is_relocatable checks
>  - Require caller to hold locks
>  - Revert is_always_within_branch_range changes
>  - ... and 97 more: https://git.openjdk.org/jdk/compare/9593730a...24c35689

Okay. Thanks for cleaning up this PR. So if you think we should do this... what is the proposal here? I mean, I get that code relocation can help with iTLB pressure. But how do I use this? I only see the new relocation function accessible through some whitebox API? Maybe I'm missing something? What's the story here? If we check this in now, it seems to me that it won't really help anyone reduce iTLB pressure. There is just a bunch of code for reducing iTLB pressure which isn't used.

Also, do you have any numbers showing if iTLB pressure improved? Or performance improved? Or in general that anything improved? I'm guessing so but I'd like to see some data.

src/hotspot/share/code/nmethod.hpp line 172:

> 170:   friend class DeoptimizationScope;
> 171: 
> 172:   #define ImmutableDataReferencesCounterSize ((int)sizeof(int))

Seems like this is needed mostly because there is immutable data shared between the old and new location, warranting a reference counter to keep track of when neither one of them needs the data any longer. And the reference counter is embedded in one of the byte blob sections of the nmethod, where it needs extra alignment. Did I get that right? If so, here are some thoughts:

1. This seems like a memory optimization which is only useful when we bloat memory. We want to free up the old nmethod because it will likely become dead weight very soon. In fact, it might make sense to make it not entrant instead of not used to that end, so the GC understands this should be nuked. If we actually free up the old nmethod, there is not much of a sharing opportunity here.

2. Even if we want this micro optimization, is there any reason it wouldn't just be a normal field so we can get rid of this special handling in the byte blobs?

src/hotspot/share/gc/z/zUnload.cpp line 103:

> 101: 
> 102:   virtual bool is_safe(nmethod* nm) {
> 103:     if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || nm->is_not_installed()) {

Why is this change needed?

src/hotspot/share/prims/whitebox.cpp line 1659:

> 1657:   ResourceMark rm(THREAD);
> 1658:   CHECK_JNI_EXCEPTION(env);
> 1659:   nmethod* code = (nmethod*) addr;

Hmm this might corrupt the code heap and cause crashes. The nmethod could have been freed and had something random else allocated across the same memory, and then casted nmethod even though it is some random instructions there now. Can't really do that.

src/hotspot/share/runtime/globals.hpp line 1567:

> 1565:           range(0, 100)                                                     \
> 1566:                                                                             \
> 1567:   product(bool, NMethodRelocation, false, EXPERIMENTAL,                     \

Why is this only available behind an experimental JVM flag?

-------------

PR Review: https://git.openjdk.org/jdk/pull/23573#pullrequestreview-3140379328
PR Review Comment: https://git.openjdk.org/jdk/pull/23573#discussion_r2290859039
PR Review Comment: https://git.openjdk.org/jdk/pull/23573#discussion_r2290975974
PR Review Comment: https://git.openjdk.org/jdk/pull/23573#discussion_r2290901579
PR Review Comment: https://git.openjdk.org/jdk/pull/23573#discussion_r2291028471


More information about the hotspot-compiler-dev mailing list