From 4e44bb0aac7457bb383027a49498669ab940fb9e Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 7 Jan 2025 23:23:04 +0000 Subject: [PATCH 001/103] Add replace nmethod function --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 1 - .../cpu/aarch64/sharedRuntime_aarch64.cpp | 4 + src/hotspot/share/code/codeCache.hpp | 2 +- src/hotspot/share/code/nmethod.cpp | 197 +++++++++++++++++- src/hotspot/share/code/nmethod.hpp | 12 ++ src/hotspot/share/code/relocInfo.cpp | 2 + src/hotspot/share/compiler/oopMap.cpp | 6 + src/hotspot/share/compiler/oopMap.hpp | 2 + .../share/gc/shared/barrierSetNMethod.cpp | 4 + src/hotspot/share/gc/shared/gcBehaviours.cpp | 5 + src/hotspot/share/oops/method.cpp | 5 + src/hotspot/share/oops/method.hpp | 4 +- src/hotspot/share/prims/whitebox.cpp | 74 +++++++ .../whitebox/CompilerWhiteBoxTest.java | 56 +++-- .../compiler/whitebox/ReplaceAllNMethods.java | 51 +++++ .../compiler/whitebox/ReplaceNMethod.java | 79 +++++++ .../ReplaceNMethodVerifyNoRecomp.java | 156 ++++++++++++++ test/lib/jdk/test/whitebox/WhiteBox.java | 11 + 18 files changed, 652 insertions(+), 19 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java create mode 100644 test/hotspot/jtreg/compiler/whitebox/ReplaceNMethod.java create mode 100644 test/hotspot/jtreg/compiler/whitebox/ReplaceNMethodVerifyNoRecomp.java diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index f5d7d9e4387ec..94694b58d2fae 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -90,7 +90,6 @@ void Relocation::pd_set_call_destination(address x) { void trampoline_stub_Relocation::pd_fix_owner_after_move() { NativeCall* call = nativeCall_at(owner()); - assert(call->raw_destination() == owner(), "destination should be empty"); address trampoline = addr(); address dest = nativeCallTrampolineStub_at(trampoline)->destination(); if (!Assembler::reachable_from_branch_at(owner(), dest)) { diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index b0b299876018a..f4cd1d087781a 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1377,6 +1377,10 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, int stack_slots = -1; int interpreted_entry_offset = -1; int vep_offset = -1; + + // First instruction must be a nop as it may need to be patched after relocation + __ nop(); + if (method->is_continuation_enter_intrinsic()) { gen_continuation_enter(masm, method, diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 3e446ab8430fe..23fc1b84bac6c 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -117,7 +117,6 @@ class CodeCache : AllStatic { // Creates a new heap with the given name and size, containing CodeBlobs of the given type static void add_heap(ReservedSpace rs, const char* name, CodeBlobType code_blob_type); - static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr static CodeHeap* get_code_heap(const void* cb); // Returns the CodeHeap for the given CodeBlob static CodeHeap* get_code_heap(CodeBlobType code_blob_type); // Returns the CodeHeap for the given CodeBlobType // Returns the name of the VM option to set the size of the corresponding CodeHeap @@ -161,6 +160,7 @@ class CodeCache : AllStatic { static void metadata_do(MetadataClosure* f); // iterates over metadata in alive nmethods // Lookup + static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr static CodeBlob* find_blob(void* start); // Returns the CodeBlob containing the given address static CodeBlob* find_blob_fast(void* start); // Returns the CodeBlob containing the given address static CodeBlob* find_blob_and_oopmap(void* start, int& slot); // Returns the CodeBlob containing the given address diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 4f72c193d7ff0..58b50c55f8e72 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1381,6 +1381,197 @@ nmethod::nmethod( } } +nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.size(), nm.header_size()) +{ + debug_only(NoSafepointVerifier nsv;) + assert_locked_or_safepoint(CodeCache_lock); + + // CodeBlob data + if (nm.oop_maps() == nullptr) { + _oop_maps = nullptr; + } else { + _oop_maps = nm.oop_maps()->clone(); + } + _relocation_size = nm._relocation_size; + _content_offset = nm._content_offset; + _code_offset = nm._code_offset; + _data_offset = nm._data_offset; + _frame_size = nm._frame_size; + _frame_complete_offset = nm._frame_complete_offset; + _caller_must_gc_arguments = nm._caller_must_gc_arguments; + + // nmethod data + _deoptimization_generation = nm._deoptimization_generation; + + _gc_epoch = nm._gc_epoch; + + _osr_link = nm._osr_link; + _native_receiver_sp_offset = nm._native_receiver_sp_offset; + _native_basic_lock_sp_offset = nm._native_basic_lock_sp_offset; + + // nmethod's read-only data + if (nm.immutable_data_size() > 0) { + _immutable_data = (address)os::malloc(nm.immutable_data_size(), mtCode); + memcpy(immutable_data_begin(), nm.immutable_data_begin(), nm.immutable_data_size()); + } else { + _immutable_data = data_end(); + } + + _exception_cache = nullptr; + + _gc_data = nullptr; + + _oops_do_mark_nmethods = nm._oops_do_mark_nmethods; + + _oops_do_mark_link = nm._oops_do_mark_link; + + _compiled_ic_data = nullptr; + + _osr_entry_point = code_begin() + (nm._osr_entry_point - nm.code_begin()); + _entry_offset = nm._entry_offset; + _verified_entry_offset = nm._verified_entry_offset; + _entry_bci = nm._entry_bci; + _immutable_data_size = nm._immutable_data_size; + + _skipped_instructions_size = nm._skipped_instructions_size; + + _stub_offset = nm._stub_offset; + + _exception_offset = nm._exception_offset; + + _deopt_handler_offset = nm._deopt_handler_offset; + _deopt_mh_handler_offset = nm._deopt_mh_handler_offset; + _unwind_handler_offset = nm._unwind_handler_offset; + + _num_stack_arg_slots = nm._num_stack_arg_slots; + + _metadata_offset = nm._metadata_offset; + +#if INCLUDE_JVMCI + _jvmci_data_offset = nm._jvmci_data_offset; +#endif + + _nul_chk_table_offset = nm._nul_chk_table_offset; + _handler_table_offset = nm._handler_table_offset; + _scopes_pcs_offset = nm._scopes_pcs_offset; + _scopes_data_offset = nm._scopes_data_offset; + + if (nm._pc_desc_container == nullptr) { + _pc_desc_container = nullptr; + } else { + _pc_desc_container = new PcDescContainer(scopes_pcs_begin()); + } + +#if INCLUDE_JVMCI + _speculations_offset = nm._speculations_offset; +#endif + + _orig_pc_offset = nm._orig_pc_offset; + + _compile_id = nm._compile_id; + _comp_level = nm._comp_level; + _compiler_type = nm._compiler_type; + + _is_unloading_state = nm._is_unloading_state; + + _state = nm._state; + + _has_unsafe_access = nm._has_method_handle_invokes; + _has_method_handle_invokes = nm._has_method_handle_invokes; + _has_wide_vectors = nm._has_wide_vectors; + _has_monitors = nm._has_monitors; + _has_scoped_access = nm._has_scoped_access; + _has_flushed_dependencies = nm._has_flushed_dependencies; + _is_unlinked = nm._is_unlinked; + _load_reported = nm._load_reported; + + _deoptimization_status = nm._deoptimization_status; + + memcpy(relocation_begin(), nm.relocation_begin(), nm.relocation_size()); + memcpy(consts_begin(), nm.consts_begin(), nm.consts_size()); + memcpy(insts_begin(), nm.insts_begin(), nm.insts_size()); + memcpy(stub_begin(), nm.stub_begin(), nm.stub_size()); + memcpy((void*) oops_begin(), (void*) nm.oops_begin(), nm.oops_size()); + memcpy(metadata_begin(), nm.metadata_begin(), nm.metadata_size()); + + RelocIterator iter(this); + CodeBuffer src((CodeBlob *)&nm); + CodeBuffer dst(this); + while (iter.next()) { + iter.reloc()->fix_relocation_after_move(&src, &dst); + } + + ICache::invalidate_range(code_begin(), code_size()); + + post_init(); + + // Update corresponding Java method to point to this nmethod + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); + _method = nm._method; + nm._method = nullptr; + if (_method != nullptr) { + methodHandle mh(Thread::current(), _method); + _method->clear_code(); + _method->clear_entry_points(); + _method->set_code(mh, this); + } +} + +nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { + if (nm == nullptr || nm->is_marked_for_deoptimization()) { + return nullptr; + } + + // TODO Add check for already in correct heap + + nmethod* nm_copy = nullptr; + + { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + nm_copy = new (nm->size(), code_blob_type) nmethod(*nm); + + if (nm_copy != nullptr) { + // To make dependency checking during class loading fast, record + // the nmethod dependencies in the classes it is dependent on. + // This allows the dependency checking code to simply walk the + // class hierarchy above the loaded class, checking only nmethods + // which are dependent on those classes. The slow way is to + // check every nmethod for dependencies which makes it linear in + // the number of methods compiled. For applications with a lot + // classes the slow way is too slow. + for (Dependencies::DepStream deps(nm_copy); deps.next(); ) { + if (deps.type() == Dependencies::call_site_target_value) { + // CallSite dependencies are managed on per-CallSite instance basis. + oop call_site = deps.argument_oop(0); + MethodHandles::add_dependent_nmethod(call_site, nm_copy); + } else { + InstanceKlass* ik = deps.context_type(); + if (ik == nullptr) { + continue; // ignore things like evol_method + } + // record this nmethod as dependent on this klass + ik->add_dependent_nmethod(nm_copy); + } + } + } + } + // Do verification and logging outside CodeCache_lock. + if (nm_copy != nullptr) { + NOT_PRODUCT(note_java_nmethod(nm_copy)); + // Safepoints in nmethod::verify aren't allowed because nm_copy hasn't been installed yet. + DEBUG_ONLY(nm_copy->verify();) + nm_copy->log_new_nmethod(); + } + + nm->make_not_used(); + + return nm_copy; +} + +void* nmethod::operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw () { + return CodeCache::allocate(nmethod_size, code_blob_type); +} + void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () { return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } @@ -2238,7 +2429,11 @@ void nmethod::post_compiled_method_load_event(JvmtiThreadState* state) { } void nmethod::post_compiled_method_unload() { - assert(_method != nullptr, "just checking"); + // Don't post if method was relocated + if (_method == nullptr) { + return; + } + DTRACE_METHOD_UNLOAD_PROBE(method()); // If a JVMTI agent has enabled the CompiledMethodUnload event then diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index ac9b1a7098f8d..dca42b20d79db 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -333,6 +333,11 @@ class nmethod : public CodeBlob { #endif ); + nmethod(nmethod& nm); + + // Create nmethod in a specific code heap + void* operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw(); + // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); @@ -491,6 +496,13 @@ class nmethod : public CodeBlob { #endif ); + + // Relocate the nmethod to the code heap identified by code_blob_type. + // Returns nullptr if the code heap does not have enough space, otherwise + // the relocated nmethod. The original nmethod will be invalidated. + // If nm is already in the needed code heap, it is not relocated and the function returns it. + static nmethod* relocate_to(nmethod* nm, CodeBlobType code_blob_type); + static nmethod* new_native_nmethod(const methodHandle& method, int compile_id, CodeBuffer *code_buffer, diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 9dc4eced9662b..c156904eae1db 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -376,6 +376,8 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { // Finalize owner destination only for nmethods if (dest->blob() != nullptr) return; + // We either relocate a nmethod residing in CodeCache or just generated code from CodeBuffer + assert(src->blob() == nullptr || nativeCall_at(owner())->raw_destination() == owner(), "destination should be empty"); pd_fix_owner_after_move(); } #endif diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index ea2c770d66f74..3981b2a6ddc52 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -864,6 +864,12 @@ ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) return builder.build(); } +ImmutableOopMapSet* ImmutableOopMapSet::clone() const { + address buffer = NEW_C_HEAP_ARRAY(unsigned char, _size, mtCode); + memcpy(buffer, (address)this, _size); + return (ImmutableOopMapSet*)buffer; +} + void ImmutableOopMapSet::operator delete(void* p) { FREE_C_HEAP_ARRAY(unsigned char, p); } diff --git a/src/hotspot/share/compiler/oopMap.hpp b/src/hotspot/share/compiler/oopMap.hpp index 634fb8b0bfae7..f91240bb28854 100644 --- a/src/hotspot/share/compiler/oopMap.hpp +++ b/src/hotspot/share/compiler/oopMap.hpp @@ -350,6 +350,8 @@ class ImmutableOopMapSet { static ImmutableOopMapSet* build_from(const OopMapSet* oopmap_set); + ImmutableOopMapSet* clone() const; + int find_slot_for_offset(int pc_offset) const; const ImmutableOopMap* find_map_at_offset(int pc_offset) const; const ImmutableOopMap* find_map_at_slot(int slot, int pc_offset) const; diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index c5d8a7e54015f..6ae5abce24201 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -47,6 +47,10 @@ int BarrierSetNMethod::disarmed_guard_value() const { } bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) { + if (nm->method() == nullptr) { + return false; + } + if (nm->method()->is_method_handle_intrinsic()) { return false; } diff --git a/src/hotspot/share/gc/shared/gcBehaviours.cpp b/src/hotspot/share/gc/shared/gcBehaviours.cpp index 02971943874bd..b0251538a54fb 100644 --- a/src/hotspot/share/gc/shared/gcBehaviours.cpp +++ b/src/hotspot/share/gc/shared/gcBehaviours.cpp @@ -28,6 +28,11 @@ IsUnloadingBehaviour* IsUnloadingBehaviour::_current = nullptr; bool IsUnloadingBehaviour::is_unloading(nmethod* nm) { + // If the nmethod no longer has a corresponding method it should be unloaded + if (nm->method() == nullptr) { + return true; + } + if (nm->method()->can_be_allocated_in_NonNMethod_space()) { // When the nmethod is in NonNMethod space, we may reach here without IsUnloadingBehaviour. // However, we only allow this for special methods which never get unloaded. diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 1a3b908434f1d..cd76c37fc4351 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1132,6 +1132,11 @@ void Method::unlink_code() { clear_code(); } +void Method::clear_entry_points() { + _from_compiled_entry = nullptr; + _from_interpreted_entry = nullptr; +} + #if INCLUDE_CDS // Called by class data sharing to remove any entry points (which are not shared) void Method::unlink_method() { diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 5daa572a46ccf..f11b9c04498db 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -364,10 +364,12 @@ class Method : public Metadata { // Locks NMethodState_lock if not held. void unlink_code(); -private: + void clear_entry_points(); + // Either called with NMethodState_lock held or from constructor. void clear_code(); +private: void clear_method_data() { _method_data = nullptr; } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index a612a3d55a9fc..ad688d3cd5b92 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1625,6 +1625,74 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo return result; WB_END +WB_ENTRY(void, WB_ReplaceNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr, jint comp_level_override)) + ResourceMark rm(THREAD); + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION(env); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); + if (code == nullptr) { + return; + } + + nmethod::relocate_to(code, CodeCache::get_code_heap_containing(code)->code_blob_type()); +WB_END + +WB_ENTRY(void, WB_ReplaceAllNMethods(JNIEnv* env)) + ResourceMark rm(THREAD); + + // Get all nmethods in heap + GrowableArray nmethods; + for (int codeBlobTypeIndex = 0; codeBlobTypeIndex < (int) CodeBlobType::NumTypes; codeBlobTypeIndex++) { + CodeHeap* heap; + { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + heap = WhiteBox::get_code_heap(static_cast(codeBlobTypeIndex)); + if (heap == nullptr) { + continue; + } + } + + for (CodeBlob* cb = (CodeBlob*) heap->first(); cb != nullptr; cb = (CodeBlob*) heap->next(cb)) { + if (cb->is_nmethod()) { + nmethod* nm = cb->as_nmethod(); + // TODO Error after relocating MethodHandle functions + if (!nm->method()->is_method_handle_intrinsic()) { + nmethods.append(nm); + } + } + } + } + + // Replace all + for (GrowableArrayIterator it = nmethods.begin(); it != nmethods.end(); ++it) { + nmethod::relocate_to(*it, CodeCache::get_code_heap_containing(*it)->code_blob_type()); + } + +WB_END + +WB_ENTRY(jlong, WB_GetNumNMethods(JNIEnv* env)) + ResourceMark rm(THREAD); + + long num = 0; + for (int codeBlobTypeIndex = 0; codeBlobTypeIndex < (int) CodeBlobType::NumTypes; codeBlobTypeIndex++) { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeHeap* heap = WhiteBox::get_code_heap(static_cast(codeBlobTypeIndex)); + if (heap == nullptr) { + continue; + } + + for (CodeBlob* cb = (CodeBlob*) heap->first(); cb != nullptr; cb = (CodeBlob*) heap->next(cb)) { + if (cb->is_nmethod()) { + num++; + } + } + } + + return num; + +WB_END + CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled"); BufferBlob* blob; @@ -2876,6 +2944,12 @@ static JNINativeMethod methods[] = { {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, + {CC"replaceNMethod0", CC"(Ljava/lang/reflect/Executable;ZI)V", + (void*)&WB_ReplaceNMethod }, + {CC"replaceAllNMethods", CC"()V", + (void*)&WB_ReplaceAllNMethods }, + {CC"getNumNMethods", CC"()J", + (void*)&WB_GetNumNMethods }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, diff --git a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java index f87292be019c0..eb0f70af5c462 100644 --- a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java @@ -221,15 +221,28 @@ protected final void checkNotCompiled() { * compilation level. */ protected final void checkNotCompiled(boolean isOsr) { - if (WHITE_BOX.isMethodQueuedForCompilation(method)) { - throw new RuntimeException(method + " must not be in queue"); + checkNotCompiled(method, isOsr); + } + + /** + * Checks, that the specified executable is not (OSR-)compiled. + * + * @param executable The method or constructor to check. + * @param isOsr Check for OSR compilation if true + * @throws RuntimeException if {@linkplain #method} is in compiler queue or + * is compiled, or if {@linkplain #method} has zero + * compilation level. + */ + protected static final void checkNotCompiled(Executable executable, boolean isOsr) { + if (WHITE_BOX.isMethodQueuedForCompilation(executable)) { + throw new RuntimeException(executable + " must not be in queue"); } - if (WHITE_BOX.isMethodCompiled(method, isOsr)) { - throw new RuntimeException(method + " must not be " + + if (WHITE_BOX.isMethodCompiled(executable, isOsr)) { + throw new RuntimeException(executable + " must not be " + (isOsr ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method, isOsr) != 0) { - throw new RuntimeException(method + (isOsr ? " osr_" : " ") + + if (WHITE_BOX.getMethodCompilationLevel(executable, isOsr) != 0) { + throw new RuntimeException(executable + (isOsr ? " osr_" : " ") + "comp_level must be == 0"); } } @@ -242,21 +255,34 @@ protected final void checkNotCompiled(boolean isOsr) { * has nonzero compilation level */ protected final void checkCompiled() { + checkCompiled(method, testCase.isOsr()); + } + + /** + * Checks, that the specified executable is compiled. + * + * @param executable The method or constructor to check. + * @param isOsr Check for OSR compilation if true + * @throws RuntimeException if {@linkplain #method} isn't in compiler queue + * and isn't compiled, or if {@linkplain #method} + * has nonzero compilation level + */ + protected static final void checkCompiled(Executable executable, boolean isOsr) { final long start = System.currentTimeMillis(); - waitBackgroundCompilation(); - if (WHITE_BOX.isMethodQueuedForCompilation(method)) { + waitBackgroundCompilation(executable); + if (WHITE_BOX.isMethodQueuedForCompilation(executable)) { System.err.printf("Warning: %s is still in queue after %dms%n", - method, System.currentTimeMillis() - start); + executable, System.currentTimeMillis() - start); return; } - if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { - throw new RuntimeException(method + " must be " - + (testCase.isOsr() ? "osr_" : "") + "compiled"); + if (!WHITE_BOX.isMethodCompiled(executable, isOsr)) { + throw new RuntimeException(executable + " must be " + + (isOsr ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()) + if (WHITE_BOX.getMethodCompilationLevel(executable, isOsr) == 0) { - throw new RuntimeException(method - + (testCase.isOsr() ? " osr_" : " ") + throw new RuntimeException(executable + + (isOsr ? " osr_" : " ") + "comp_level must be != 0"); } } diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java new file mode 100644 index 0000000000000..5c8a54abbe98c --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test ReplaceAllNMethods + * @bug 8316694 + * @summary TODO + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch + * -XX:+TieredCompilation -XX:TieredStopAtLevel=3 compiler.whitebox.ReplaceAllNMethods + */ + +package compiler.whitebox; + +import jdk.test.whitebox.WhiteBox; + +public class ReplaceAllNMethods { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + public static void main(String [] args) throws Exception { + WHITE_BOX.replaceAllNMethods(); + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethod.java b/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethod.java new file mode 100644 index 0000000000000..92f2154cfb0b9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethod.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test ReplaceNMethod + * @bug 8316694 + * @summary test that WB::replaceNMethod() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch compiler.whitebox.ReplaceNMethod + */ + +package compiler.whitebox; + +import java.lang.reflect.Method; +import jdk.test.whitebox.code.NMethod; +import jdk.test.whitebox.WhiteBox; + +import compiler.whitebox.CompilerWhiteBoxTest; + +public class ReplaceNMethod extends CompilerWhiteBoxTest { + + public static void main(String[] args) throws Exception { + CompilerWhiteBoxTest.main(ReplaceNMethod::new, args); + } + + private ReplaceNMethod(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + @Override + protected void test() throws Exception { + checkNotCompiled(); + + compile(); + + checkCompiled(); + NMethod origNmethod = NMethod.get(method, false); + + WHITE_BOX.replaceNMethod(method, false); + + WHITE_BOX.fullGC(); + + checkCompiled(); + + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethodVerifyNoRecomp.java b/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethodVerifyNoRecomp.java new file mode 100644 index 0000000000000..d0bc5acbce9f8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethodVerifyNoRecomp.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test ReplaceNMethodVerifyNoRecomp + * @bug 8316694 + * @summary test that WB::replaceNMethod() correctly creates a new nmethod and can be used without recompiling + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm compiler.whitebox.ReplaceNMethodVerifyNoRecomp + */ + +package compiler.whitebox; + +import compiler.whitebox.CompilerWhiteBoxTest; +import java.lang.reflect.Method; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.NMethod; + +public class ReplaceNMethodVerifyNoRecomp { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-Xbootclasspath/a:.", "-Xbatch", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintCompilation", + "-XX:+WhiteBoxAPI", ReplaceNMethodVerifyNoRecomp.ReplaceNMethod.class.getName() + ); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(0); + + verifyOutput(output.getOutput()); + } + + // Matches output for function being compiled. Does not match to deoptimization outputs for that function + // Example: 4 compiler.whitebox.ReplaceNMethodVerifyNoRecomp$ReplaceNMethod::function (20 bytes) + private static String methodCompiledRegex = "^4\\s+compiler\\.whitebox\\.ReplaceNMethodVerifyNoRecomp\\$ReplaceNMethod::function\\s+\\(\\d+\\s+bytes\\)\\\n$"; + + public static void verifyOutput(String text) { + int notCompiled = text.indexOf("Should not be compiled"); + if (notCompiled == -1) { + throw new RuntimeException("Output does not include required out"); + } + + int functionCompiled = text.indexOf("4 compiler.whitebox.ReplaceNMethodVerifyNoRecomp$ReplaceNMethod::function"); + if (functionCompiled == -1) { + throw new RuntimeException("Function was never compiled"); + } + + // Confirm that the function was not compiled when it was not supposed to be + if (functionCompiled < notCompiled) { + throw new RuntimeException("Function was compiled before it should be"); + } + + int isCompiled = text.indexOf("Should be compiled"); + if (isCompiled == -1) { + throw new RuntimeException("Output does not include required out"); + } + + // Confirm that the function was compled when it was supposed to be + if (functionCompiled > isCompiled) { + throw new RuntimeException("Function was not compiled after it should be"); + } + + // Confirm that the function never gets recompiled + String remainingOutput = text.substring(functionCompiled + 1); + + // Confirm that the function never gets recompiled + boolean functionRecompiled = remainingOutput.matches(methodCompiledRegex); + if (functionRecompiled) { + throw new RuntimeException("Function was recompiled when it should not be"); + } + } + + private static class ReplaceNMethod { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + public static double FUNCTION_RESULT = 0; + + public static void main(String [] args) throws Exception { + // Get method that will be relocated + Method method = ReplaceNMethodVerifyNoRecomp.ReplaceNMethod.class.getMethod("function"); + WHITE_BOX.testSetDontInlineMethod(method, true); + + // Verify not initially compiled + System.out.println("Should not be compiled"); + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call function enough to compile + callFunction(); + + // Verify now compiled + System.out.println("Should be compiled"); + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get newly created nmethod + NMethod origNmethod = NMethod.get(method, false); + + // Relocate nmethod and mark old for cleanup + WHITE_BOX.replaceNMethod(method, false); + + // Trigger GC to clean up old nmethod + WHITE_BOX.fullGC(); + + // Verify function still compiled after old was cleaned up + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get new nmethod and verify it's actually new + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + + // Call function again to verify it does not get recompiled + callFunction(); + CompilerWhiteBoxTest.checkCompiled(method, false); + } + + // Call function multiple times to trigger compilation + private static void callFunction() { + for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { + function(); + } + } + + public static void function() { + FUNCTION_RESULT = Math.random(); + } + } +} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 7222c6fedcf8c..bb96e8a1d4e51 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -486,6 +486,17 @@ public Object[] getNMethod(Executable method, boolean isOsr) { Objects.requireNonNull(method); return getNMethod0(method, isOsr); } + private native void replaceNMethod0(Executable method, boolean isOsr, int comp_level_override); + public void replaceNMethod(Executable method, boolean isOsr, int comp_level_override) { + Objects.requireNonNull(method); + replaceNMethod0(method, isOsr, comp_level_override); + } + public void replaceNMethod(Executable method, boolean isOsr) { + Objects.requireNonNull(method); + replaceNMethod0(method, isOsr, -1); + } + public native void replaceAllNMethods(); + public native long getNumNMethods(); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; From e8ecbc315d3f63a67bcaacdd721582deea0d4cab Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 4 Mar 2025 21:42:38 +0000 Subject: [PATCH 002/103] Clear inline caches --- src/hotspot/share/code/nmethod.cpp | 4 ++++ src/hotspot/share/prims/whitebox.cpp | 16 ++++++++++++---- src/hotspot/share/runtime/vmOperation.hpp | 1 + src/hotspot/share/runtime/vmOperations.cpp | 4 ++++ src/hotspot/share/runtime/vmOperations.hpp | 9 +++++++++ .../compiler/whitebox/ReplaceAllNMethods.java | 2 ++ 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 58b50c55f8e72..d8c4602bf49ba 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1527,6 +1527,10 @@ nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { nmethod* nm_copy = nullptr; { + // Clear inline caches before acquiring any locks + VM_ClearNMethodICs clear_nmethod_ics(nm); + VMThread::execute(&clear_nmethod_ics); + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); nm_copy = new (nm->size(), code_blob_type) nmethod(*nm); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index ad688d3cd5b92..cfea90bf3b921 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1656,12 +1656,16 @@ WB_ENTRY(void, WB_ReplaceAllNMethods(JNIEnv* env)) for (CodeBlob* cb = (CodeBlob*) heap->first(); cb != nullptr; cb = (CodeBlob*) heap->next(cb)) { if (cb->is_nmethod()) { nmethod* nm = cb->as_nmethod(); - // TODO Error after relocating MethodHandle functions - if (!nm->method()->is_method_handle_intrinsic()) { - nmethods.append(nm); - } + // TODO Error after relocating MethodHandle functions + if (!nm->method()->is_method_handle_intrinsic()) { + nmethods.append(nm); + } } } + + if (!SegmentedCodeCache) { + break; + } } // Replace all @@ -1687,6 +1691,10 @@ WB_ENTRY(jlong, WB_GetNumNMethods(JNIEnv* env)) num++; } } + + if (!SegmentedCodeCache) { + break; + } } return num; diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index 50d859444858d..92213bda1626c 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -41,6 +41,7 @@ template(PrintThreads) \ template(FindDeadlocks) \ template(ClearICs) \ + template(ClearNMethodICs) \ template(ForceSafepoint) \ template(DeoptimizeFrame) \ template(DeoptimizeAll) \ diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index da833150d746e..4f6f6817369be 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -100,6 +100,10 @@ void VM_ClearICs::doit() { } } +void VM_ClearNMethodICs::doit() { + _nm->clear_inline_caches(); +} + void VM_CleanClassLoaderDataMetaspaces::doit() { ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces(); } diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index baeea722dcef2..bc99e695bd9ba 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -81,6 +81,15 @@ class VM_ClearICs: public VM_Operation { VMOp_Type type() const { return VMOp_ClearICs; } }; +class VM_ClearNMethodICs: public VM_Operation { + private: + nmethod* _nm; + public: + VM_ClearNMethodICs(nmethod* nm) { _nm = nm; } + void doit(); + VMOp_Type type() const { return VMOp_ClearNMethodICs; } + }; + // Base class for invoking parts of a gtest in a safepoint. // Derived classes provide the doit method. // Typically also need to transition the gtest thread from native to VM. diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java index 5c8a54abbe98c..0b2c3e1c81c3f 100644 --- a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java +++ b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java @@ -47,5 +47,7 @@ public class ReplaceAllNMethods { public static void main(String [] args) throws Exception { WHITE_BOX.replaceAllNMethods(); + + WHITE_BOX.fullGC(); } } From f6755f6becc3c0afb1c8f0124c2a7f9f37e8f7ee Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 6 Mar 2025 19:42:34 +0000 Subject: [PATCH 003/103] Fix bug when updating method pointer --- src/hotspot/share/ci/ciEnv.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 20 ++++++++++++------- src/hotspot/share/code/nmethod.hpp | 2 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 2 +- src/hotspot/share/oops/method.cpp | 4 ++-- src/hotspot/share/oops/method.hpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 6 +----- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- .../compiler/whitebox/ReplaceAllNMethods.java | 5 ++--- 9 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index e87c5ba08e95e..5191389185085 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1103,7 +1103,7 @@ void ciEnv::register_method(ciMethod* target, // Allow the code to be executed MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { - method->set_code(method, nm); + method->set_code(method, nm, false); } } else { LogTarget(Info, nmethod, install) lt; diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index d8c4602bf49ba..59f5aaa1e2b83 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1381,7 +1381,7 @@ nmethod::nmethod( } } -nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.size(), nm.header_size()) +nmethod::nmethod(const nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.size(), nm.header_size()) { debug_only(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); @@ -1508,17 +1508,23 @@ nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.si // Update corresponding Java method to point to this nmethod MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); _method = nm._method; - nm._method = nullptr; - if (_method != nullptr) { + if (_method != nullptr && _method->code() == &nm) { methodHandle mh(Thread::current(), _method); - _method->clear_code(); - _method->clear_entry_points(); - _method->set_code(mh, this); + _method->set_code(mh, this, true); } } nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { - if (nm == nullptr || nm->is_marked_for_deoptimization()) { + if (nm == nullptr) { + return nullptr; + } + + // Unsupported nmethods + if (nm->is_not_entrant()) { + return nullptr; + } + + if (nm->method() != nullptr && nm->method()->is_method_handle_intrinsic()) { return nullptr; } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index dca42b20d79db..2d931652843fa 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -333,7 +333,7 @@ class nmethod : public CodeBlob { #endif ); - nmethod(nmethod& nm); + nmethod(const nmethod& nm); // Create nmethod in a specific code heap void* operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw(); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c88a4390590d0..ef1cac2300b41 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -2209,7 +2209,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, // Allow the code to be executed MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { - method->set_code(method, nm); + method->set_code(method, nm, false); } else { result = JVMCI::nmethod_reclaimed; } diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index cd76c37fc4351..ca2e6dda9591c 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1276,7 +1276,7 @@ bool Method::check_code() const { } // Install compiled code. Instantly it can execute. -void Method::set_code(const methodHandle& mh, nmethod *code) { +void Method::set_code(const methodHandle& mh, nmethod *code, bool isRelocation) { assert_lock_strong(NMethodState_lock); assert( code, "use clear_code to remove code" ); assert( mh->check_code(), "" ); @@ -1300,7 +1300,7 @@ void Method::set_code(const methodHandle& mh, nmethod *code) { OrderAccess::storestore(); if (mh->is_continuation_native_intrinsic()) { - assert(mh->_from_interpreted_entry == nullptr, "initialized incorrectly"); // see link_method + assert(mh->_from_interpreted_entry == nullptr || isRelocation, "initialized incorrectly"); // see link_method if (mh->is_continuation_enter_intrinsic()) { // This is the entry used when we're in interpreter-only mode; see InterpreterMacroAssembler::jump_from_interpreted diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index f11b9c04498db..226fe1dfd7ecd 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -375,7 +375,7 @@ class Method : public Metadata { } public: - static void set_code(const methodHandle& mh, nmethod* code); + static void set_code(const methodHandle& mh, nmethod* code, bool isRelocation); void set_adapter_entry(AdapterHandlerEntry* adapter) { _adapter = adapter; } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index cfea90bf3b921..d4c8cac07e9ba 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1655,11 +1655,7 @@ WB_ENTRY(void, WB_ReplaceAllNMethods(JNIEnv* env)) for (CodeBlob* cb = (CodeBlob*) heap->first(); cb != nullptr; cb = (CodeBlob*) heap->next(cb)) { if (cb->is_nmethod()) { - nmethod* nm = cb->as_nmethod(); - // TODO Error after relocating MethodHandle functions - if (!nm->method()->is_method_handle_intrinsic()) { - nmethods.append(nm); - } + nmethods.append(cb->as_nmethod()); } } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 53bff3bc7addf..3736771f52c4c 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2850,7 +2850,7 @@ void AdapterHandlerLibrary::create_native_wrapper(const methodHandle& method) { { MutexLocker pl(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { - method->set_code(method, nm); + method->set_code(method, nm, false); } } diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java index 0b2c3e1c81c3f..2870fbc2c561a 100644 --- a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java +++ b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java @@ -24,7 +24,7 @@ /* * @test ReplaceAllNMethods * @bug 8316694 - * @summary TODO + * @summary Relocates all nmethods and runs garbage collector to cleanup old versions * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management @@ -33,8 +33,7 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch - * -XX:+TieredCompilation -XX:TieredStopAtLevel=3 compiler.whitebox.ReplaceAllNMethods + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.whitebox.ReplaceAllNMethods */ package compiler.whitebox; From daf41690cda96ba36943722892c0574ad3fb3b23 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 6 Mar 2025 19:44:49 +0000 Subject: [PATCH 004/103] Remove getNumNMethods --- src/hotspot/share/prims/whitebox.cpp | 31 +----------------------- test/lib/jdk/test/whitebox/WhiteBox.java | 1 - 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index d4c8cac07e9ba..fb7a14783e82c 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1671,32 +1671,6 @@ WB_ENTRY(void, WB_ReplaceAllNMethods(JNIEnv* env)) WB_END -WB_ENTRY(jlong, WB_GetNumNMethods(JNIEnv* env)) - ResourceMark rm(THREAD); - - long num = 0; - for (int codeBlobTypeIndex = 0; codeBlobTypeIndex < (int) CodeBlobType::NumTypes; codeBlobTypeIndex++) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - CodeHeap* heap = WhiteBox::get_code_heap(static_cast(codeBlobTypeIndex)); - if (heap == nullptr) { - continue; - } - - for (CodeBlob* cb = (CodeBlob*) heap->first(); cb != nullptr; cb = (CodeBlob*) heap->next(cb)) { - if (cb->is_nmethod()) { - num++; - } - } - - if (!SegmentedCodeCache) { - break; - } - } - - return num; - -WB_END - CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled"); BufferBlob* blob; @@ -2950,10 +2924,7 @@ static JNINativeMethod methods[] = { (void*)&WB_GetNMethod }, {CC"replaceNMethod0", CC"(Ljava/lang/reflect/Executable;ZI)V", (void*)&WB_ReplaceNMethod }, - {CC"replaceAllNMethods", CC"()V", - (void*)&WB_ReplaceAllNMethods }, - {CC"getNumNMethods", CC"()J", - (void*)&WB_GetNumNMethods }, + {CC"replaceAllNMethods", CC"()V", (void*)&WB_ReplaceAllNMethods }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index bb96e8a1d4e51..49380396f2599 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -496,7 +496,6 @@ public void replaceNMethod(Executable method, boolean isOsr) { replaceNMethod0(method, isOsr, -1); } public native void replaceAllNMethods(); - public native long getNumNMethods(); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; From 887c4e23b88197edbcbea1ac58d796a2b875daec Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 6 Mar 2025 20:29:47 +0000 Subject: [PATCH 005/103] Rename replaceNMethod to relocateNMethod --- src/hotspot/share/prims/whitebox.cpp | 10 ++++---- ...placeNMethod.java => RelocateNMethod.java} | 15 ++++++------ ...ava => RelocateNMethodVerifyNoRecomp.java} | 23 ++++++++++--------- test/lib/jdk/test/whitebox/WhiteBox.java | 10 +++----- 4 files changed, 28 insertions(+), 30 deletions(-) rename test/hotspot/jtreg/compiler/whitebox/{ReplaceNMethod.java => RelocateNMethod.java} (83%) rename test/hotspot/jtreg/compiler/whitebox/{ReplaceNMethodVerifyNoRecomp.java => RelocateNMethodVerifyNoRecomp.java} (85%) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index fb7a14783e82c..f3f65244b10ea 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1625,17 +1625,17 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo return result; WB_END -WB_ENTRY(void, WB_ReplaceNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr, jint comp_level_override)) +WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint blob_type)) ResourceMark rm(THREAD); jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION(env); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); + nmethod* code = mh->code(); if (code == nullptr) { return; } - nmethod::relocate_to(code, CodeCache::get_code_heap_containing(code)->code_blob_type()); + nmethod::relocate_to(code, static_cast(blob_type)); WB_END WB_ENTRY(void, WB_ReplaceAllNMethods(JNIEnv* env)) @@ -2922,8 +2922,8 @@ static JNINativeMethod methods[] = { {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, - {CC"replaceNMethod0", CC"(Ljava/lang/reflect/Executable;ZI)V", - (void*)&WB_ReplaceNMethod }, + {CC"relocateNMethodTo0", CC"(Ljava/lang/reflect/Executable;I)V", + (void*)&WB_RelocateNMethodTo }, {CC"replaceAllNMethods", CC"()V", (void*)&WB_ReplaceAllNMethods }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java similarity index 83% rename from test/hotspot/jtreg/compiler/whitebox/ReplaceNMethod.java rename to test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java index 92f2154cfb0b9..4c0acd80acbd3 100644 --- a/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -22,9 +22,9 @@ */ /* - * @test ReplaceNMethod + * @test RelocateNMethod * @bug 8316694 - * @summary test that WB::replaceNMethod() correctly creates a new nmethod + * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management @@ -33,24 +33,25 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch compiler.whitebox.ReplaceNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch compiler.whitebox.RelocateNMethod */ package compiler.whitebox; import java.lang.reflect.Method; +import jdk.test.whitebox.code.BlobType; import jdk.test.whitebox.code.NMethod; import jdk.test.whitebox.WhiteBox; import compiler.whitebox.CompilerWhiteBoxTest; -public class ReplaceNMethod extends CompilerWhiteBoxTest { +public class RelocateNMethod extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { - CompilerWhiteBoxTest.main(ReplaceNMethod::new, args); + CompilerWhiteBoxTest.main(RelocateNMethod::new, args); } - private ReplaceNMethod(TestCase testCase) { + private RelocateNMethod(TestCase testCase) { super(testCase); // to prevent inlining of #method WHITE_BOX.testSetDontInlineMethod(method, true); @@ -65,7 +66,7 @@ protected void test() throws Exception { checkCompiled(); NMethod origNmethod = NMethod.get(method, false); - WHITE_BOX.replaceNMethod(method, false); + WHITE_BOX.relocateNMethodTo(method, BlobType.MethodNonProfiled.id); WHITE_BOX.fullGC(); diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethodVerifyNoRecomp.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java similarity index 85% rename from test/hotspot/jtreg/compiler/whitebox/ReplaceNMethodVerifyNoRecomp.java rename to test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java index d0bc5acbce9f8..35a6ae41c2299 100644 --- a/test/hotspot/jtreg/compiler/whitebox/ReplaceNMethodVerifyNoRecomp.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java @@ -22,9 +22,9 @@ */ /* - * @test ReplaceNMethodVerifyNoRecomp + * @test RelocateNMethodVerifyNoRecomp * @bug 8316694 - * @summary test that WB::replaceNMethod() correctly creates a new nmethod and can be used without recompiling + * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod and can be used without recompiling * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management @@ -33,7 +33,7 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm compiler.whitebox.ReplaceNMethodVerifyNoRecomp + * @run main/othervm compiler.whitebox.RelocateNMethodVerifyNoRecomp */ package compiler.whitebox; @@ -43,14 +43,15 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; import jdk.test.whitebox.code.NMethod; -public class ReplaceNMethodVerifyNoRecomp { +public class RelocateNMethodVerifyNoRecomp { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-Xbootclasspath/a:.", "-Xbatch", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintCompilation", - "-XX:+WhiteBoxAPI", ReplaceNMethodVerifyNoRecomp.ReplaceNMethod.class.getName() + "-XX:+WhiteBoxAPI", RelocateNMethodVerifyNoRecomp.RelocateNMethod.class.getName() ); OutputAnalyzer output = new OutputAnalyzer(pb.start()); @@ -60,8 +61,8 @@ public static void main(String[] args) throws Exception { } // Matches output for function being compiled. Does not match to deoptimization outputs for that function - // Example: 4 compiler.whitebox.ReplaceNMethodVerifyNoRecomp$ReplaceNMethod::function (20 bytes) - private static String methodCompiledRegex = "^4\\s+compiler\\.whitebox\\.ReplaceNMethodVerifyNoRecomp\\$ReplaceNMethod::function\\s+\\(\\d+\\s+bytes\\)\\\n$"; + // Example: 4 compiler.whitebox.RelocateNMethodVerifyNoRecomp$RelocateNMethod::function (20 bytes) + private static String methodCompiledRegex = "^4\\s+compiler\\.whitebox\\.RelocateNMethodVerifyNoRecomp\\$RelocateNMethod::function\\s+\\(\\d+\\s+bytes\\)\\\n$"; public static void verifyOutput(String text) { int notCompiled = text.indexOf("Should not be compiled"); @@ -69,7 +70,7 @@ public static void verifyOutput(String text) { throw new RuntimeException("Output does not include required out"); } - int functionCompiled = text.indexOf("4 compiler.whitebox.ReplaceNMethodVerifyNoRecomp$ReplaceNMethod::function"); + int functionCompiled = text.indexOf("4 compiler.whitebox.RelocateNMethodVerifyNoRecomp$RelocateNMethod::function"); if (functionCompiled == -1) { throw new RuntimeException("Function was never compiled"); } @@ -99,13 +100,13 @@ public static void verifyOutput(String text) { } } - private static class ReplaceNMethod { + private static class RelocateNMethod { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); public static double FUNCTION_RESULT = 0; public static void main(String [] args) throws Exception { // Get method that will be relocated - Method method = ReplaceNMethodVerifyNoRecomp.ReplaceNMethod.class.getMethod("function"); + Method method = RelocateNMethodVerifyNoRecomp.RelocateNMethod.class.getMethod("function"); WHITE_BOX.testSetDontInlineMethod(method, true); // Verify not initially compiled @@ -123,7 +124,7 @@ public static void main(String [] args) throws Exception { NMethod origNmethod = NMethod.get(method, false); // Relocate nmethod and mark old for cleanup - WHITE_BOX.replaceNMethod(method, false); + WHITE_BOX.relocateNMethodTo(method, BlobType.MethodNonProfiled.id); // Trigger GC to clean up old nmethod WHITE_BOX.fullGC(); diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 49380396f2599..e7a450d48922e 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -486,14 +486,10 @@ public Object[] getNMethod(Executable method, boolean isOsr) { Objects.requireNonNull(method); return getNMethod0(method, isOsr); } - private native void replaceNMethod0(Executable method, boolean isOsr, int comp_level_override); - public void replaceNMethod(Executable method, boolean isOsr, int comp_level_override) { + private native void relocateNMethodTo0(Executable method, int type); + public void relocateNMethodTo(Executable method, int type) { Objects.requireNonNull(method); - replaceNMethod0(method, isOsr, comp_level_override); - } - public void replaceNMethod(Executable method, boolean isOsr) { - Objects.requireNonNull(method); - replaceNMethod0(method, isOsr, -1); + relocateNMethodTo0(method, type); } public native void replaceAllNMethods(); public native long allocateCodeBlob(int size, int type); From a62c7b0e68aa01dc9c545da51518aef07bf8b1b9 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 6 Mar 2025 22:28:13 +0000 Subject: [PATCH 006/103] Clean up --- src/hotspot/share/code/nmethod.cpp | 6 +----- src/hotspot/share/gc/shared/barrierSetNMethod.cpp | 4 ---- src/hotspot/share/gc/shared/gcBehaviours.cpp | 5 ----- src/hotspot/share/oops/method.cpp | 5 ----- src/hotspot/share/oops/method.hpp | 4 +--- 5 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 59f5aaa1e2b83..b205da67e7b72 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -2439,11 +2439,7 @@ void nmethod::post_compiled_method_load_event(JvmtiThreadState* state) { } void nmethod::post_compiled_method_unload() { - // Don't post if method was relocated - if (_method == nullptr) { - return; - } - + assert(_method != nullptr, "just checking"); DTRACE_METHOD_UNLOAD_PROBE(method()); // If a JVMTI agent has enabled the CompiledMethodUnload event then diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index 6ae5abce24201..c5d8a7e54015f 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -47,10 +47,6 @@ int BarrierSetNMethod::disarmed_guard_value() const { } bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) { - if (nm->method() == nullptr) { - return false; - } - if (nm->method()->is_method_handle_intrinsic()) { return false; } diff --git a/src/hotspot/share/gc/shared/gcBehaviours.cpp b/src/hotspot/share/gc/shared/gcBehaviours.cpp index b0251538a54fb..02971943874bd 100644 --- a/src/hotspot/share/gc/shared/gcBehaviours.cpp +++ b/src/hotspot/share/gc/shared/gcBehaviours.cpp @@ -28,11 +28,6 @@ IsUnloadingBehaviour* IsUnloadingBehaviour::_current = nullptr; bool IsUnloadingBehaviour::is_unloading(nmethod* nm) { - // If the nmethod no longer has a corresponding method it should be unloaded - if (nm->method() == nullptr) { - return true; - } - if (nm->method()->can_be_allocated_in_NonNMethod_space()) { // When the nmethod is in NonNMethod space, we may reach here without IsUnloadingBehaviour. // However, we only allow this for special methods which never get unloaded. diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index ca2e6dda9591c..7137405d7426f 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1132,11 +1132,6 @@ void Method::unlink_code() { clear_code(); } -void Method::clear_entry_points() { - _from_compiled_entry = nullptr; - _from_interpreted_entry = nullptr; -} - #if INCLUDE_CDS // Called by class data sharing to remove any entry points (which are not shared) void Method::unlink_method() { diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 226fe1dfd7ecd..f033eda1e57c1 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -364,12 +364,10 @@ class Method : public Metadata { // Locks NMethodState_lock if not held. void unlink_code(); - void clear_entry_points(); - +private: // Either called with NMethodState_lock held or from constructor. void clear_code(); -private: void clear_method_data() { _method_data = nullptr; } From b659ddf5854e836df1b7047d32269af987ef4dad Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 7 Mar 2025 00:03:47 +0000 Subject: [PATCH 007/103] Add nmethod::is_relocatable() --- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 4 --- src/hotspot/share/code/nmethod.cpp | 27 ++++++++++++------- src/hotspot/share/code/nmethod.hpp | 2 ++ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index f4cd1d087781a..b0b299876018a 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1377,10 +1377,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, int stack_slots = -1; int interpreted_entry_offset = -1; int vep_offset = -1; - - // First instruction must be a nop as it may need to be patched after relocation - __ nop(); - if (method->is_continuation_enter_intrinsic()) { gen_continuation_enter(masm, method, diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index b205da67e7b72..bd502d35b0ae6 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1515,16 +1515,7 @@ nmethod::nmethod(const nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, } nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { - if (nm == nullptr) { - return nullptr; - } - - // Unsupported nmethods - if (nm->is_not_entrant()) { - return nullptr; - } - - if (nm->method() != nullptr && nm->method()->is_method_handle_intrinsic()) { + if (nm == nullptr || !nm->is_relocatable()) { return nullptr; } @@ -1578,6 +1569,22 @@ nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { return nm_copy; } +bool nmethod::is_relocatable() const { + if (is_not_entrant()) { + return false; + } + + if (method()->is_method_handle_intrinsic()) { + return false; + } + + if (method()->is_continuation_native_intrinsic()) { + return false; + } + + return true; +} + void* nmethod::operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw () { return CodeCache::allocate(nmethod_size, code_blob_type); } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 2d931652843fa..0f2008160768c 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -519,6 +519,8 @@ class nmethod : public CodeBlob { bool is_java_method () const { return _method != nullptr && !_method->is_native(); } bool is_osr_method () const { return _entry_bci != InvocationEntryBci; } + bool is_relocatable() const; + // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, // and native method wrappers are also numbered independently if From 925ce03958f5886bc19c82cb1b507f4dc78640ca Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 7 Mar 2025 22:46:54 +0000 Subject: [PATCH 008/103] Add check for already in correct heap --- src/hotspot/share/code/nmethod.cpp | 9 ++++++++- src/hotspot/share/code/nmethod.hpp | 2 ++ src/hotspot/share/prims/whitebox.cpp | 4 +++- .../hotspot/jtreg/compiler/whitebox/RelocateNMethod.java | 4 ++-- .../compiler/whitebox/RelocateNMethodVerifyNoRecomp.java | 4 ++-- .../jtreg/compiler/whitebox/ReplaceAllNMethods.java | 2 +- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index bd502d35b0ae6..741cfff2fa7af 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1519,7 +1519,10 @@ nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { return nullptr; } - // TODO Add check for already in correct heap + // No need to relocate if already in correct code heap + if (nm->lookup_code_blob_type() == code_blob_type) { + return nm; + } nmethod* nm_copy = nullptr; @@ -1585,6 +1588,10 @@ bool nmethod::is_relocatable() const { return true; } +CodeBlobType nmethod::lookup_code_blob_type() { + return CodeCache::get_code_heap_containing(this)->code_blob_type(); +} + void* nmethod::operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw () { return CodeCache::allocate(nmethod_size, code_blob_type); } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 0f2008160768c..b8abf1298ed98 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -521,6 +521,8 @@ class nmethod : public CodeBlob { bool is_relocatable() const; + CodeBlobType lookup_code_blob_type(); + // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, // and native method wrappers are also numbered independently if diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index f3f65244b10ea..60e9da4d15cc4 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1666,7 +1666,9 @@ WB_ENTRY(void, WB_ReplaceAllNMethods(JNIEnv* env)) // Replace all for (GrowableArrayIterator it = nmethods.begin(); it != nmethods.end(); ++it) { - nmethod::relocate_to(*it, CodeCache::get_code_heap_containing(*it)->code_blob_type()); + // Destination should be different than current location + CodeBlobType code_cache_dest = (*it)->lookup_code_blob_type() == CodeBlobType::MethodNonProfiled ? CodeBlobType::MethodProfiled : CodeBlobType::MethodNonProfiled; + nmethod::relocate_to(*it, code_cache_dest); } WB_END diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java index 4c0acd80acbd3..d540458eb837a 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -33,7 +33,7 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch compiler.whitebox.RelocateNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache compiler.whitebox.RelocateNMethod */ package compiler.whitebox; @@ -66,7 +66,7 @@ protected void test() throws Exception { checkCompiled(); NMethod origNmethod = NMethod.get(method, false); - WHITE_BOX.relocateNMethodTo(method, BlobType.MethodNonProfiled.id); + WHITE_BOX.relocateNMethodTo(method, BlobType.MethodProfiled.id); WHITE_BOX.fullGC(); diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java index 35a6ae41c2299..151e3ea461427 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java @@ -51,7 +51,7 @@ public class RelocateNMethodVerifyNoRecomp { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-Xbootclasspath/a:.", "-Xbatch", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintCompilation", - "-XX:+WhiteBoxAPI", RelocateNMethodVerifyNoRecomp.RelocateNMethod.class.getName() + "-XX:+WhiteBoxAPI", "-XX:+SegmentedCodeCache", RelocateNMethodVerifyNoRecomp.RelocateNMethod.class.getName() ); OutputAnalyzer output = new OutputAnalyzer(pb.start()); @@ -124,7 +124,7 @@ public static void main(String [] args) throws Exception { NMethod origNmethod = NMethod.get(method, false); // Relocate nmethod and mark old for cleanup - WHITE_BOX.relocateNMethodTo(method, BlobType.MethodNonProfiled.id); + WHITE_BOX.relocateNMethodTo(method, BlobType.MethodProfiled.id); // Trigger GC to clean up old nmethod WHITE_BOX.fullGC(); diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java index 2870fbc2c561a..4b4e18391378e 100644 --- a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java +++ b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java @@ -33,7 +33,7 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.whitebox.ReplaceAllNMethods + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache compiler.whitebox.ReplaceAllNMethods */ package compiler.whitebox; From bc69b571a2516e5cd118c637b385458a61e2db1f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 10 Mar 2025 22:12:35 +0000 Subject: [PATCH 009/103] Run tests with all GCs --- src/hotspot/share/code/nmethod.cpp | 5 +- src/hotspot/share/code/nmethod.hpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 4 +- .../whitebox/DeoptimizeRelocatedNMethod.java | 143 ++++++++++++++++ .../whitebox/RelocateAllNMethods.java | 107 ++++++++++++ .../RelocateAndDeoptmizeAllNMethods.java | 111 ++++++++++++ .../RelocateNMethodMultiplePaths.java | 158 ++++++++++++++++++ .../RelocateNMethodVerifyNoRecomp.java | 157 ----------------- .../compiler/whitebox/ReplaceAllNMethods.java | 52 ------ test/lib/jdk/test/whitebox/WhiteBox.java | 2 +- 10 files changed, 526 insertions(+), 215 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java create mode 100644 test/hotspot/jtreg/compiler/whitebox/RelocateAllNMethods.java create mode 100644 test/hotspot/jtreg/compiler/whitebox/RelocateAndDeoptmizeAllNMethods.java create mode 100644 test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java delete mode 100644 test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java delete mode 100644 test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 741cfff2fa7af..ea12fd0615eb8 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1381,7 +1381,7 @@ nmethod::nmethod( } } -nmethod::nmethod(const nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.size(), nm.header_size()) +nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.size(), nm.header_size()) { debug_only(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); @@ -1503,11 +1503,12 @@ nmethod::nmethod(const nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, ICache::invalidate_range(code_begin(), code_size()); + _method = nm._method; + post_init(); // Update corresponding Java method to point to this nmethod MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); - _method = nm._method; if (_method != nullptr && _method->code() == &nm) { methodHandle mh(Thread::current(), _method); _method->set_code(mh, this, true); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index b8abf1298ed98..7c4d8def25f5f 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -333,7 +333,7 @@ class nmethod : public CodeBlob { #endif ); - nmethod(const nmethod& nm); + nmethod(nmethod& nm); // Create nmethod in a specific code heap void* operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw(); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 60e9da4d15cc4..b683bd2dc9df3 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1638,7 +1638,7 @@ WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint nmethod::relocate_to(code, static_cast(blob_type)); WB_END -WB_ENTRY(void, WB_ReplaceAllNMethods(JNIEnv* env)) +WB_ENTRY(void, WB_RelocateAllNMethods(JNIEnv* env)) ResourceMark rm(THREAD); // Get all nmethods in heap @@ -2926,7 +2926,7 @@ static JNINativeMethod methods[] = { (void*)&WB_GetNMethod }, {CC"relocateNMethodTo0", CC"(Ljava/lang/reflect/Executable;I)V", (void*)&WB_RelocateNMethodTo }, - {CC"replaceAllNMethods", CC"()V", (void*)&WB_ReplaceAllNMethods }, + {CC"relocateAllNMethods", CC"()V", (void*)&WB_RelocateAllNMethods}, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java new file mode 100644 index 0000000000000..a988e167e832d --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=Serial + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=G1 + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +package compiler.whitebox; + +import compiler.whitebox.CompilerWhiteBoxTest; +import java.lang.reflect.Method; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + +public class DeoptimizeRelocatedNMethod { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + public static double FUNCTION_RESULT = 0; + + public static void main(String [] args) throws Exception { + // Get method that will be relocated + Method method = DeoptimizeRelocatedNMethod.class.getMethod("function"); + WHITE_BOX.testSetDontInlineMethod(method, true); + + // Verify not initially compiled + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call function enough to compile + callFunction(); + + // Verify now compiled + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get newly created nmethod + NMethod origNmethod = NMethod.get(method, false); + + // Relocate nmethod and mark old for cleanup + WHITE_BOX.relocateNMethodTo(method, BlobType.MethodProfiled.id); + + // Trigger GC to clean up old nmethod + WHITE_BOX.fullGC(); + + // Verify function still compiled after old was cleaned up + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get new nmethod and verify it's actually new + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + + // Deoptimized method + WHITE_BOX.deoptimizeMethod(method); + + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call to verify everything still works + function(); + } + + // Call function multiple times to trigger compilation + private static void callFunction() { + for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { + function(); + } + } + + public static void function() { + FUNCTION_RESULT = Math.random(); + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/RelocateAllNMethods.java new file mode 100644 index 0000000000000..d85ed6ed9e878 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateAllNMethods.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=Serial + * @bug 8316694 + * @summary Relocates all nmethods and runs garbage collector to cleanup old versions + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.RelocateAllNMethods + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @summary Relocates all nmethods and runs garbage collector to cleanup old versions + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.RelocateAllNMethods + */ + +/* + * @test id=G1 + * @bug 8316694 + * @summary Relocates all nmethods and runs garbage collector to cleanup old versions + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.RelocateAllNMethods + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @summary Relocates all nmethods and runs garbage collector to cleanup old versions + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.RelocateAllNMethods + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @summary Relocates all nmethods and runs garbage collector to cleanup old versions + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.RelocateAllNMethods + */ + +package compiler.whitebox; + +import jdk.test.whitebox.WhiteBox; + +public class RelocateAllNMethods { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + public static void main(String [] args) throws Exception { + WHITE_BOX.relocateAllNMethods(); + + WHITE_BOX.fullGC(); + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateAndDeoptmizeAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/RelocateAndDeoptmizeAllNMethods.java new file mode 100644 index 0000000000000..36a4776eaccef --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateAndDeoptmizeAllNMethods.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=Serial + * @bug 8316694 + * @summary Relocates all nmethods and also deoptimizes to confirm no crashes + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.RelocateAndDeoptmizeAllNMethods + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @summary Relocates all nmethods and also deoptimizes to confirm no crashes + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.RelocateAndDeoptmizeAllNMethods + */ + +/* + * @test id=G1 + * @bug 8316694 + * @summary Relocates all nmethods and also deoptimizes to confirm no crashes + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.RelocateAndDeoptmizeAllNMethods + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @summary Relocates all nmethods and also deoptimizes to confirm no crashes + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.RelocateAndDeoptmizeAllNMethods + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @summary Relocates all nmethods and also deoptimizes to confirm no crashes + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.RelocateAndDeoptmizeAllNMethods + */ + +package compiler.whitebox; + +import jdk.test.whitebox.WhiteBox; + +public class RelocateAndDeoptmizeAllNMethods { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + public static void main(String [] args) throws Exception { + WHITE_BOX.relocateAllNMethods(); + + WHITE_BOX.fullGC(); + + WHITE_BOX.deoptimizeAll(); + + WHITE_BOX.fullGC(); + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java new file mode 100644 index 0000000000000..72f4f9d56861f --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=Serial + * @bug 8316694 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=G1 + * @bug 8316694 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +package compiler.whitebox; + +import compiler.whitebox.CompilerWhiteBoxTest; +import java.lang.reflect.Method; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + +public class RelocateNMethodMultiplePaths { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + public static double FUNCTION_RESULT = 0; + + public static void main(String [] args) throws Exception { + // Get method that will be relocated + Method method = RelocateNMethodMultiplePaths.class.getMethod("function", boolean.class); + WHITE_BOX.testSetDontInlineMethod(method, true); + + // Verify not initially compiled + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call function enough to compile + callFunction(true); + + // Verify now compiled + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get newly created nmethod + NMethod origNmethod = NMethod.get(method, false); + + // Relocate nmethod and mark old for cleanup + WHITE_BOX.relocateNMethodTo(method, BlobType.MethodProfiled.id); + + // Trigger GC to clean up old nmethod + WHITE_BOX.fullGC(); + + // Verify function still compiled after old was cleaned up + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get new nmethod and verify it's actually new + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + + // Call function again with different path so it gets deoptimized + function(false); + + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call both paths to verify everything still works + function(true); + function(false); + } + + // Call function multiple times to trigger compilation + private static void callFunction(boolean pathOne) { + for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { + function(pathOne); + } + } + + public static void function(boolean pathOne) { + if (pathOne) { + FUNCTION_RESULT = 1; + } else { + FUNCTION_RESULT = 2; + } + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java deleted file mode 100644 index 151e3ea461427..0000000000000 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodVerifyNoRecomp.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test RelocateNMethodVerifyNoRecomp - * @bug 8316694 - * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod and can be used without recompiling - * @library /test/lib / - * @modules java.base/jdk.internal.misc - * java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm compiler.whitebox.RelocateNMethodVerifyNoRecomp - */ - -package compiler.whitebox; - -import compiler.whitebox.CompilerWhiteBoxTest; -import java.lang.reflect.Method; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; -import jdk.test.whitebox.WhiteBox; -import jdk.test.whitebox.code.BlobType; -import jdk.test.whitebox.code.NMethod; - -public class RelocateNMethodVerifyNoRecomp { - - public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-Xbootclasspath/a:.", "-Xbatch", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintCompilation", - "-XX:+WhiteBoxAPI", "-XX:+SegmentedCodeCache", RelocateNMethodVerifyNoRecomp.RelocateNMethod.class.getName() - ); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - output.shouldHaveExitValue(0); - - verifyOutput(output.getOutput()); - } - - // Matches output for function being compiled. Does not match to deoptimization outputs for that function - // Example: 4 compiler.whitebox.RelocateNMethodVerifyNoRecomp$RelocateNMethod::function (20 bytes) - private static String methodCompiledRegex = "^4\\s+compiler\\.whitebox\\.RelocateNMethodVerifyNoRecomp\\$RelocateNMethod::function\\s+\\(\\d+\\s+bytes\\)\\\n$"; - - public static void verifyOutput(String text) { - int notCompiled = text.indexOf("Should not be compiled"); - if (notCompiled == -1) { - throw new RuntimeException("Output does not include required out"); - } - - int functionCompiled = text.indexOf("4 compiler.whitebox.RelocateNMethodVerifyNoRecomp$RelocateNMethod::function"); - if (functionCompiled == -1) { - throw new RuntimeException("Function was never compiled"); - } - - // Confirm that the function was not compiled when it was not supposed to be - if (functionCompiled < notCompiled) { - throw new RuntimeException("Function was compiled before it should be"); - } - - int isCompiled = text.indexOf("Should be compiled"); - if (isCompiled == -1) { - throw new RuntimeException("Output does not include required out"); - } - - // Confirm that the function was compled when it was supposed to be - if (functionCompiled > isCompiled) { - throw new RuntimeException("Function was not compiled after it should be"); - } - - // Confirm that the function never gets recompiled - String remainingOutput = text.substring(functionCompiled + 1); - - // Confirm that the function never gets recompiled - boolean functionRecompiled = remainingOutput.matches(methodCompiledRegex); - if (functionRecompiled) { - throw new RuntimeException("Function was recompiled when it should not be"); - } - } - - private static class RelocateNMethod { - private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - public static double FUNCTION_RESULT = 0; - - public static void main(String [] args) throws Exception { - // Get method that will be relocated - Method method = RelocateNMethodVerifyNoRecomp.RelocateNMethod.class.getMethod("function"); - WHITE_BOX.testSetDontInlineMethod(method, true); - - // Verify not initially compiled - System.out.println("Should not be compiled"); - CompilerWhiteBoxTest.checkNotCompiled(method, false); - - // Call function enough to compile - callFunction(); - - // Verify now compiled - System.out.println("Should be compiled"); - CompilerWhiteBoxTest.checkCompiled(method, false); - - // Get newly created nmethod - NMethod origNmethod = NMethod.get(method, false); - - // Relocate nmethod and mark old for cleanup - WHITE_BOX.relocateNMethodTo(method, BlobType.MethodProfiled.id); - - // Trigger GC to clean up old nmethod - WHITE_BOX.fullGC(); - - // Verify function still compiled after old was cleaned up - CompilerWhiteBoxTest.checkCompiled(method, false); - - // Get new nmethod and verify it's actually new - NMethod newNmethod = NMethod.get(method, false); - if (origNmethod.entry_point == newNmethod.entry_point) { - throw new RuntimeException("Did not create new nmethod"); - } - - // Call function again to verify it does not get recompiled - callFunction(); - CompilerWhiteBoxTest.checkCompiled(method, false); - } - - // Call function multiple times to trigger compilation - private static void callFunction() { - for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { - function(); - } - } - - public static void function() { - FUNCTION_RESULT = Math.random(); - } - } -} diff --git a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java deleted file mode 100644 index 4b4e18391378e..0000000000000 --- a/test/hotspot/jtreg/compiler/whitebox/ReplaceAllNMethods.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test ReplaceAllNMethods - * @bug 8316694 - * @summary Relocates all nmethods and runs garbage collector to cleanup old versions - * @library /test/lib / - * @modules java.base/jdk.internal.misc - * java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache compiler.whitebox.ReplaceAllNMethods - */ - -package compiler.whitebox; - -import jdk.test.whitebox.WhiteBox; - -public class ReplaceAllNMethods { - - private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - - public static void main(String [] args) throws Exception { - WHITE_BOX.replaceAllNMethods(); - - WHITE_BOX.fullGC(); - } -} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index e7a450d48922e..99f801bd3d904 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -491,7 +491,7 @@ public void relocateNMethodTo(Executable method, int type) { Objects.requireNonNull(method); relocateNMethodTo0(method, type); } - public native void replaceAllNMethods(); + public native void relocateAllNMethods(); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; From 54c43fba76b6a685e823122d9c1b64a52b47a35c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 10 Mar 2025 22:43:52 +0000 Subject: [PATCH 010/103] Run RelocateNMethod.java with all GCs --- .../compiler/whitebox/RelocateNMethod.java | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java index d540458eb837a..48d4cc2f578d1 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -22,18 +22,73 @@ */ /* - * @test RelocateNMethod + * @test id=Serial * @bug 8316694 * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod * @library /test/lib / - * @modules java.base/jdk.internal.misc - * java.management + * @modules java.base/jdk.internal.misc java.management * * @requires vm.opt.DeoptimizeALot != true * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache compiler.whitebox.RelocateNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=G1 + * @bug 8316694 + * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.RelocateNMethod */ package compiler.whitebox; From 566c37ad31bbb3f38845a121e8eca9731af3fa1f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 11 Mar 2025 21:44:18 +0000 Subject: [PATCH 011/103] Updates after JDK-8343789 --- src/hotspot/share/code/nmethod.cpp | 113 +++++++++++++++-------------- 1 file changed, 60 insertions(+), 53 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5b34debb5376f..f605cff299ee0 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1398,7 +1398,6 @@ nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.si debug_only(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - // CodeBlob data if (nm.oop_maps() == nullptr) { _oop_maps = nullptr; } else { @@ -1412,7 +1411,6 @@ nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.si _frame_complete_offset = nm._frame_complete_offset; _caller_must_gc_arguments = nm._caller_must_gc_arguments; - // nmethod data _deoptimization_generation = nm._deoptimization_generation; _gc_epoch = nm._gc_epoch; @@ -1421,90 +1419,99 @@ nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.si _native_receiver_sp_offset = nm._native_receiver_sp_offset; _native_basic_lock_sp_offset = nm._native_basic_lock_sp_offset; - // nmethod's read-only data + // Allocate memory and copy immutable data from C heap if (nm.immutable_data_size() > 0) { - _immutable_data = (address)os::malloc(nm.immutable_data_size(), mtCode); + _immutable_data = (address)os::malloc(nm.immutable_data_size(), mtCode); + if (_immutable_data == nullptr) { + vm_exit_out_of_memory(nm.immutable_data_size(), OOM_MALLOC_ERROR, "nmethod: no space for immutable data"); + } memcpy(immutable_data_begin(), nm.immutable_data_begin(), nm.immutable_data_size()); } else { - _immutable_data = data_end(); + _immutable_data = data_end(); } - _exception_cache = nullptr; + _exception_cache = nullptr; - _gc_data = nullptr; + _gc_data = nullptr; - _oops_do_mark_nmethods = nm._oops_do_mark_nmethods; + _oops_do_mark_nmethods = nm._oops_do_mark_nmethods; - _oops_do_mark_link = nm._oops_do_mark_link; + _oops_do_mark_link = nm._oops_do_mark_link; - _compiled_ic_data = nullptr; + _compiled_ic_data = nullptr; - _osr_entry_point = code_begin() + (nm._osr_entry_point - nm.code_begin()); - _entry_offset = nm._entry_offset; - _verified_entry_offset = nm._verified_entry_offset; - _entry_bci = nm._entry_bci; - _immutable_data_size = nm._immutable_data_size; + _osr_entry_point = code_begin() + (nm._osr_entry_point - nm.code_begin()); + _entry_offset = nm._entry_offset; + _verified_entry_offset = nm._verified_entry_offset; + _entry_bci = nm._entry_bci; + _immutable_data_size = nm._immutable_data_size; - _skipped_instructions_size = nm._skipped_instructions_size; + _skipped_instructions_size = nm._skipped_instructions_size; - _stub_offset = nm._stub_offset; + _stub_offset = nm._stub_offset; - _exception_offset = nm._exception_offset; + _exception_offset = nm._exception_offset; - _deopt_handler_offset = nm._deopt_handler_offset; - _deopt_mh_handler_offset = nm._deopt_mh_handler_offset; - _unwind_handler_offset = nm._unwind_handler_offset; + _deopt_handler_offset = nm._deopt_handler_offset; + _deopt_mh_handler_offset = nm._deopt_mh_handler_offset; + _unwind_handler_offset = nm._unwind_handler_offset; - _num_stack_arg_slots = nm._num_stack_arg_slots; + _num_stack_arg_slots = nm._num_stack_arg_slots; - _metadata_offset = nm._metadata_offset; + _oops_size = nm._oops_size; #if INCLUDE_JVMCI - _jvmci_data_offset = nm._jvmci_data_offset; + _jvmci_data_size = nm._jvmci_data_size; #endif - _nul_chk_table_offset = nm._nul_chk_table_offset; - _handler_table_offset = nm._handler_table_offset; - _scopes_pcs_offset = nm._scopes_pcs_offset; - _scopes_data_offset = nm._scopes_data_offset; + _nul_chk_table_offset = nm._nul_chk_table_offset; + _handler_table_offset = nm._handler_table_offset; + _scopes_pcs_offset = nm._scopes_pcs_offset; + _scopes_data_offset = nm._scopes_data_offset; if (nm._pc_desc_container == nullptr) { - _pc_desc_container = nullptr; + _pc_desc_container = nullptr; } else { - _pc_desc_container = new PcDescContainer(scopes_pcs_begin()); + _pc_desc_container = new PcDescContainer(scopes_pcs_begin()); } #if INCLUDE_JVMCI - _speculations_offset = nm._speculations_offset; + _speculations_offset = nm._speculations_offset; #endif - _orig_pc_offset = nm._orig_pc_offset; + _orig_pc_offset = nm._orig_pc_offset; - _compile_id = nm._compile_id; - _comp_level = nm._comp_level; - _compiler_type = nm._compiler_type; + _compile_id = nm._compile_id; + _comp_level = nm._comp_level; + _compiler_type = nm._compiler_type; - _is_unloading_state = nm._is_unloading_state; + _is_unloading_state = nm._is_unloading_state; - _state = nm._state; + _state = nm._state; - _has_unsafe_access = nm._has_method_handle_invokes; - _has_method_handle_invokes = nm._has_method_handle_invokes; - _has_wide_vectors = nm._has_wide_vectors; - _has_monitors = nm._has_monitors; - _has_scoped_access = nm._has_scoped_access; - _has_flushed_dependencies = nm._has_flushed_dependencies; - _is_unlinked = nm._is_unlinked; - _load_reported = nm._load_reported; + _has_unsafe_access = nm._has_method_handle_invokes; + _has_method_handle_invokes = nm._has_method_handle_invokes; + _has_wide_vectors = nm._has_wide_vectors; + _has_monitors = nm._has_monitors; + _has_scoped_access = nm._has_scoped_access; + _has_flushed_dependencies = nm._has_flushed_dependencies; + _is_unlinked = nm._is_unlinked; + _load_reported = nm._load_reported; - _deoptimization_status = nm._deoptimization_status; + _deoptimization_status = nm._deoptimization_status; + + // Allocate memory and copy mutable data from C heap + _mutable_data_size = nm._mutable_data_size; + if (_mutable_data_size > 0) { + _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); + if (_mutable_data == nullptr) { + vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "nmethod: no space for mutable data"); + } + memcpy(mutable_data_begin(), nm.mutable_data_begin(), nm.mutable_data_size()); + } - memcpy(relocation_begin(), nm.relocation_begin(), nm.relocation_size()); - memcpy(consts_begin(), nm.consts_begin(), nm.consts_size()); - memcpy(insts_begin(), nm.insts_begin(), nm.insts_size()); - memcpy(stub_begin(), nm.stub_begin(), nm.stub_size()); - memcpy((void*) oops_begin(), (void*) nm.oops_begin(), nm.oops_size()); - memcpy(metadata_begin(), nm.metadata_begin(), nm.metadata_size()); + // Copy all nmethod data outside of header + memcpy(content_begin(), nm.content_begin(), nm.size() - nm.header_size()); RelocIterator iter(this); CodeBuffer src((CodeBlob *)&nm); @@ -1515,7 +1522,7 @@ nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.si ICache::invalidate_range(code_begin(), code_size()); - _method = nm._method; + _method = nm._method; post_init(); From 3a77f48b1d6e7f5dae0907c5b824b2c078eb4a04 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 11 Mar 2025 22:31:06 +0000 Subject: [PATCH 012/103] Only run RelocateNMethodMultiplePaths on debug builds --- .../compiler/whitebox/RelocateNMethodMultiplePaths.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java index 72f4f9d56861f..88111e041570a 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java @@ -24,6 +24,7 @@ /* * @test id=Serial * @bug 8316694 + * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -37,6 +38,7 @@ /* * @test id=Parallel * @bug 8316694 + * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -50,6 +52,7 @@ /* * @test id=G1 * @bug 8316694 + * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -63,6 +66,7 @@ /* * @test id=Shenandoah * @bug 8316694 + * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -76,6 +80,7 @@ /* * @test id=ZGC * @bug 8316694 + * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management From 7137a07fdc34457cec9d0a12791e9afde8e84398 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 11 Mar 2025 23:22:30 +0000 Subject: [PATCH 013/103] Exclude OSR --- src/hotspot/share/code/nmethod.cpp | 4 ++++ test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index f605cff299ee0..4e220732937c2 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1597,6 +1597,10 @@ bool nmethod::is_relocatable() const { return false; } + if (is_osr_method()) { + return false; + } + if (method()->is_method_handle_intrinsic()) { return false; } diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java index 48d4cc2f578d1..be1d825155ad5 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -103,7 +103,7 @@ public class RelocateNMethod extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { - CompilerWhiteBoxTest.main(RelocateNMethod::new, args); + CompilerWhiteBoxTest.main(RelocateNMethod::new, new String[] {"CONSTRUCTOR_TEST", "METHOD_TEST", "STATIC_TEST"}); } private RelocateNMethod(TestCase testCase) { From 10b20798d873d5528655c243c23a5f82c0864959 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 13 Mar 2025 21:43:46 +0000 Subject: [PATCH 014/103] Replace copy constructor with clone function --- src/hotspot/share/asm/codeBuffer.cpp | 107 ++--------------- src/hotspot/share/asm/codeBuffer.hpp | 102 ++++++++++++++++ src/hotspot/share/code/nmethod.cpp | 166 +++++++-------------------- src/hotspot/share/code/nmethod.hpp | 5 +- 4 files changed, 155 insertions(+), 225 deletions(-) diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 2aa77abc5f2e7..5e8a949c32e4b 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -1080,105 +1080,6 @@ void CodeBuffer::print() { } } -// ----- CHeapString ----------------------------------------------------------- - -class CHeapString : public CHeapObj { - public: - CHeapString(const char* str) : _string(os::strdup(str)) {} - ~CHeapString() { - os::free((void*)_string); - _string = nullptr; - } - const char* string() const { return _string; } - - private: - const char* _string; -}; - -// ----- AsmRemarkCollection --------------------------------------------------- - -class AsmRemarkCollection : public CHeapObj { - public: - AsmRemarkCollection() : _ref_cnt(1), _remarks(nullptr), _next(nullptr) {} - ~AsmRemarkCollection() { - assert(is_empty(), "Must 'clear()' before deleting!"); - assert(_ref_cnt == 0, "No uses must remain when deleting!"); - } - AsmRemarkCollection* reuse() { - precond(_ref_cnt > 0); - return _ref_cnt++, this; - } - - const char* insert(uint offset, const char* remark); - const char* lookup(uint offset) const; - const char* next(uint offset) const; - - bool is_empty() const { return _remarks == nullptr; } - uint clear(); - - private: - struct Cell : CHeapString { - Cell(const char* remark, uint offset) : - CHeapString(remark), offset(offset), prev(nullptr), next(nullptr) {} - void push_back(Cell* cell) { - Cell* head = this; - Cell* tail = prev; - tail->next = cell; - cell->next = head; - cell->prev = tail; - prev = cell; - } - uint offset; - Cell* prev; - Cell* next; - }; - uint _ref_cnt; - Cell* _remarks; - // Using a 'mutable' iteration pointer to allow 'const' on lookup/next (that - // does not change the state of the list per se), supportig a simplistic - // iteration scheme. - mutable Cell* _next; -}; - -// ----- DbgStringCollection --------------------------------------------------- - -class DbgStringCollection : public CHeapObj { - public: - DbgStringCollection() : _ref_cnt(1), _strings(nullptr) {} - ~DbgStringCollection() { - assert(is_empty(), "Must 'clear()' before deleting!"); - assert(_ref_cnt == 0, "No uses must remain when deleting!"); - } - DbgStringCollection* reuse() { - precond(_ref_cnt > 0); - return _ref_cnt++, this; - } - - const char* insert(const char* str); - const char* lookup(const char* str) const; - - bool is_empty() const { return _strings == nullptr; } - uint clear(); - - private: - struct Cell : CHeapString { - Cell(const char* dbgstr) : - CHeapString(dbgstr), prev(nullptr), next(nullptr) {} - void push_back(Cell* cell) { - Cell* head = this; - Cell* tail = prev; - tail->next = cell; - cell->next = head; - cell->prev = tail; - prev = cell; - } - Cell* prev; - Cell* next; - }; - uint _ref_cnt; - Cell* _strings; -}; - // ----- AsmRemarks ------------------------------------------------------------ // // Acting as interface to reference counted mapping [offset -> remark], where @@ -1202,6 +1103,10 @@ bool AsmRemarks::is_empty() const { return _remarks->is_empty(); } +void AsmRemarks::reuse() { + _remarks->reuse(); +} + void AsmRemarks::share(const AsmRemarks &src) { precond(is_empty()); clear(); @@ -1254,6 +1159,10 @@ bool DbgStrings::is_empty() const { return _strings->is_empty(); } +void DbgStrings::reuse() { + _strings->reuse(); +} + void DbgStrings::share(const DbgStrings &src) { precond(is_empty()); clear(); diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 025aa641d2c8b..2cfdba40397d4 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -307,6 +307,7 @@ class AsmRemarks { bool is_empty() const; + void reuse(); void share(const AsmRemarks &src); void clear(); uint print(uint offset, outputStream* strm = tty) const; @@ -330,6 +331,7 @@ class DbgStrings { bool is_empty() const; + void reuse(); void share(const DbgStrings &src); void clear(); @@ -339,6 +341,106 @@ class DbgStrings { private: DbgStringCollection* _strings; }; + +// ----- CHeapString ----------------------------------------------------------- + +class CHeapString : public CHeapObj { + public: + CHeapString(const char* str) : _string(os::strdup(str)) {} + ~CHeapString() { + os::free((void*)_string); + _string = nullptr; + } + const char* string() const { return _string; } + + private: + const char* _string; +}; + +// ----- AsmRemarkCollection --------------------------------------------------- + +class AsmRemarkCollection : public CHeapObj { + public: + AsmRemarkCollection() : _ref_cnt(1), _remarks(nullptr), _next(nullptr) {} + ~AsmRemarkCollection() { + assert(is_empty(), "Must 'clear()' before deleting!"); + assert(_ref_cnt == 0, "No uses must remain when deleting!"); + } + AsmRemarkCollection* reuse() { + precond(_ref_cnt > 0); + return _ref_cnt++, this; + } + + const char* insert(uint offset, const char* remark); + const char* lookup(uint offset) const; + const char* next(uint offset) const; + + bool is_empty() const { return _remarks == nullptr; } + uint clear(); + + private: + struct Cell : CHeapString { + Cell(const char* remark, uint offset) : + CHeapString(remark), offset(offset), prev(nullptr), next(nullptr) {} + void push_back(Cell* cell) { + Cell* head = this; + Cell* tail = prev; + tail->next = cell; + cell->next = head; + cell->prev = tail; + prev = cell; + } + uint offset; + Cell* prev; + Cell* next; + }; + uint _ref_cnt; + Cell* _remarks; + // Using a 'mutable' iteration pointer to allow 'const' on lookup/next (that + // does not change the state of the list per se), supportig a simplistic + // iteration scheme. + mutable Cell* _next; +}; + +// ----- DbgStringCollection --------------------------------------------------- + +class DbgStringCollection : public CHeapObj { + public: + DbgStringCollection() : _ref_cnt(1), _strings(nullptr) {} + ~DbgStringCollection() { + assert(is_empty(), "Must 'clear()' before deleting!"); + assert(_ref_cnt == 0, "No uses must remain when deleting!"); + } + DbgStringCollection* reuse() { + precond(_ref_cnt > 0); + return _ref_cnt++, this; + } + + const char* insert(const char* str); + const char* lookup(const char* str) const; + + bool is_empty() const { return _strings == nullptr; } + uint clear(); + + private: + struct Cell : CHeapString { + Cell(const char* dbgstr) : + CHeapString(dbgstr), prev(nullptr), next(nullptr) {} + void push_back(Cell* cell) { + Cell* head = this; + Cell* tail = prev; + tail->next = cell; + cell->next = head; + cell->prev = tail; + prev = cell; + } + Cell* prev; + Cell* next; + }; + uint _ref_cnt; + Cell* _strings; +}; + #endif // not PRODUCT diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 4e220732937c2..89ebc6878c6dc 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1393,145 +1393,63 @@ nmethod::nmethod( } } -nmethod::nmethod(nmethod& nm) : CodeBlob(nm.name(), CodeBlobKind::Nmethod, nm.size(), nm.header_size()) -{ +nmethod* nmethod::clone(CodeBlobType code_blob_type) { debug_only(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - if (nm.oop_maps() == nullptr) { - _oop_maps = nullptr; - } else { - _oop_maps = nm.oop_maps()->clone(); - } - _relocation_size = nm._relocation_size; - _content_offset = nm._content_offset; - _code_offset = nm._code_offset; - _data_offset = nm._data_offset; - _frame_size = nm._frame_size; - _frame_complete_offset = nm._frame_complete_offset; - _caller_must_gc_arguments = nm._caller_must_gc_arguments; - - _deoptimization_generation = nm._deoptimization_generation; - - _gc_epoch = nm._gc_epoch; - - _osr_link = nm._osr_link; - _native_receiver_sp_offset = nm._native_receiver_sp_offset; - _native_basic_lock_sp_offset = nm._native_basic_lock_sp_offset; + // Allocate memory in code heap and copy data from nmethod + nmethod* nm_copy = (nmethod*) CodeCache::allocate(size(), code_blob_type); + memcpy(nm_copy, this, size()); // Allocate memory and copy immutable data from C heap - if (nm.immutable_data_size() > 0) { - _immutable_data = (address)os::malloc(nm.immutable_data_size(), mtCode); - if (_immutable_data == nullptr) { - vm_exit_out_of_memory(nm.immutable_data_size(), OOM_MALLOC_ERROR, "nmethod: no space for immutable data"); + if (immutable_data_size() > 0) { + nm_copy->_immutable_data = (address)os::malloc(immutable_data_size(), mtCode); + if (nm_copy->_immutable_data == nullptr) { + vm_exit_out_of_memory(immutable_data_size(), OOM_MALLOC_ERROR, "nmethod: no space for immutable data"); } - memcpy(immutable_data_begin(), nm.immutable_data_begin(), nm.immutable_data_size()); - } else { - _immutable_data = data_end(); - } - - _exception_cache = nullptr; - - _gc_data = nullptr; - - _oops_do_mark_nmethods = nm._oops_do_mark_nmethods; - - _oops_do_mark_link = nm._oops_do_mark_link; - - _compiled_ic_data = nullptr; - - _osr_entry_point = code_begin() + (nm._osr_entry_point - nm.code_begin()); - _entry_offset = nm._entry_offset; - _verified_entry_offset = nm._verified_entry_offset; - _entry_bci = nm._entry_bci; - _immutable_data_size = nm._immutable_data_size; - - _skipped_instructions_size = nm._skipped_instructions_size; - - _stub_offset = nm._stub_offset; - - _exception_offset = nm._exception_offset; - - _deopt_handler_offset = nm._deopt_handler_offset; - _deopt_mh_handler_offset = nm._deopt_mh_handler_offset; - _unwind_handler_offset = nm._unwind_handler_offset; - - _num_stack_arg_slots = nm._num_stack_arg_slots; - - _oops_size = nm._oops_size; - -#if INCLUDE_JVMCI - _jvmci_data_size = nm._jvmci_data_size; -#endif - - _nul_chk_table_offset = nm._nul_chk_table_offset; - _handler_table_offset = nm._handler_table_offset; - _scopes_pcs_offset = nm._scopes_pcs_offset; - _scopes_data_offset = nm._scopes_data_offset; - - if (nm._pc_desc_container == nullptr) { - _pc_desc_container = nullptr; + memcpy(nm_copy->immutable_data_begin(), immutable_data_begin(), immutable_data_size()); } else { - _pc_desc_container = new PcDescContainer(scopes_pcs_begin()); + nm_copy->_immutable_data = nm_copy->data_end(); } -#if INCLUDE_JVMCI - _speculations_offset = nm._speculations_offset; -#endif - - _orig_pc_offset = nm._orig_pc_offset; - - _compile_id = nm._compile_id; - _comp_level = nm._comp_level; - _compiler_type = nm._compiler_type; - - _is_unloading_state = nm._is_unloading_state; - - _state = nm._state; - - _has_unsafe_access = nm._has_method_handle_invokes; - _has_method_handle_invokes = nm._has_method_handle_invokes; - _has_wide_vectors = nm._has_wide_vectors; - _has_monitors = nm._has_monitors; - _has_scoped_access = nm._has_scoped_access; - _has_flushed_dependencies = nm._has_flushed_dependencies; - _is_unlinked = nm._is_unlinked; - _load_reported = nm._load_reported; - - _deoptimization_status = nm._deoptimization_status; - // Allocate memory and copy mutable data from C heap - _mutable_data_size = nm._mutable_data_size; if (_mutable_data_size > 0) { - _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); + nm_copy->_mutable_data = (address)os::malloc(_mutable_data_size, mtCode); if (_mutable_data == nullptr) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "nmethod: no space for mutable data"); } - memcpy(mutable_data_begin(), nm.mutable_data_begin(), nm.mutable_data_size()); + memcpy(nm_copy->mutable_data_begin(), mutable_data_begin(), mutable_data_size()); + } + + // Fix new nmethod specific data + if (oop_maps() != nullptr) { + nm_copy->_oop_maps = oop_maps()->clone(); } - // Copy all nmethod data outside of header - memcpy(content_begin(), nm.content_begin(), nm.size() - nm.header_size()); + nm_copy->_exception_cache = nullptr; + nm_copy->_gc_data = nullptr; + nm_copy->_compiled_ic_data = nullptr; - RelocIterator iter(this); - CodeBuffer src((CodeBlob *)&nm); - CodeBuffer dst(this); + if (_pc_desc_container != nullptr) { + nm_copy->_pc_desc_container = new PcDescContainer(nm_copy->scopes_pcs_begin()); + } + + _asm_remarks.reuse(); + _dbg_strings.reuse(); + + // Fix relocation + RelocIterator iter(nm_copy); + CodeBuffer src((CodeBlob *)this); + CodeBuffer dst(nm_copy); while (iter.next()) { iter.reloc()->fix_relocation_after_move(&src, &dst); } - ICache::invalidate_range(code_begin(), code_size()); + ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); - _method = nm._method; + nm_copy->post_init(); - post_init(); - - // Update corresponding Java method to point to this nmethod - MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); - if (_method != nullptr && _method->code() == &nm) { - methodHandle mh(Thread::current(), _method); - _method->set_code(mh, this, true); - } + return nm_copy; } nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { @@ -1552,7 +1470,7 @@ nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { VMThread::execute(&clear_nmethod_ics); MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - nm_copy = new (nm->size(), code_blob_type) nmethod(*nm); + nm_copy = nm->clone(code_blob_type); if (nm_copy != nullptr) { // To make dependency checking during class loading fast, record @@ -1577,6 +1495,14 @@ nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { ik->add_dependent_nmethod(nm_copy); } } + + // Update corresponding Java method to point to this nmethod + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); + if (nm_copy->method() != nullptr && nm_copy->method()->code() == nm) { + methodHandle mh(Thread::current(), nm_copy->method()); + nm_copy->method()->set_code(mh, nm_copy, true); + nm->make_not_used(); + } } } // Do verification and logging outside CodeCache_lock. @@ -1587,8 +1513,6 @@ nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { nm_copy->log_new_nmethod(); } - nm->make_not_used(); - return nm_copy; } @@ -1616,10 +1540,6 @@ CodeBlobType nmethod::lookup_code_blob_type() { return CodeCache::get_code_heap_containing(this)->code_blob_type(); } -void* nmethod::operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw () { - return CodeCache::allocate(nmethod_size, code_blob_type); -} - void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () { return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 6b8809996600a..b1e7932b49bc6 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -335,9 +335,6 @@ class nmethod : public CodeBlob { nmethod(nmethod& nm); - // Create nmethod in a specific code heap - void* operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw(); - // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); @@ -346,6 +343,8 @@ class nmethod : public CodeBlob { // findable by nmethod iterators! In particular, they must not contain oops! void* operator new(size_t size, int nmethod_size, bool allow_NonNMethod_space) throw(); + nmethod* clone(CodeBlobType code_blob_type); + const char* reloc_string_for(u_char* begin, u_char* end); bool try_transition(signed char new_state); From 8a2b55bdaff8c826f864c25f788bed13e11a2ff5 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 13 Mar 2025 22:41:23 +0000 Subject: [PATCH 015/103] Remove isRelocation flag --- src/hotspot/share/ci/ciEnv.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 10 +++------- src/hotspot/share/jvmci/jvmciRuntime.cpp | 2 +- src/hotspot/share/oops/method.cpp | 4 ++-- src/hotspot/share/oops/method.hpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 880511a41c910..2a88154faf6c5 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1103,7 +1103,7 @@ void ciEnv::register_method(ciMethod* target, // Allow the code to be executed MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { - method->set_code(method, nm, false); + method->set_code(method, nm); } } else { LogTarget(Info, nmethod, install) lt; diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 89ebc6878c6dc..7789e55410867 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1498,9 +1498,9 @@ nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { // Update corresponding Java method to point to this nmethod MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); - if (nm_copy->method() != nullptr && nm_copy->method()->code() == nm) { + if (nm_copy->method()->code() == nm) { methodHandle mh(Thread::current(), nm_copy->method()); - nm_copy->method()->set_code(mh, nm_copy, true); + nm_copy->method()->set_code(mh, nm_copy); nm->make_not_used(); } } @@ -1525,11 +1525,7 @@ bool nmethod::is_relocatable() const { return false; } - if (method()->is_method_handle_intrinsic()) { - return false; - } - - if (method()->is_continuation_native_intrinsic()) { + if (!is_java_method()) { return false; } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index ef1cac2300b41..c88a4390590d0 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -2209,7 +2209,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, // Allow the code to be executed MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { - method->set_code(method, nm, false); + method->set_code(method, nm); } else { result = JVMCI::nmethod_reclaimed; } diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 7137405d7426f..1a3b908434f1d 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1271,7 +1271,7 @@ bool Method::check_code() const { } // Install compiled code. Instantly it can execute. -void Method::set_code(const methodHandle& mh, nmethod *code, bool isRelocation) { +void Method::set_code(const methodHandle& mh, nmethod *code) { assert_lock_strong(NMethodState_lock); assert( code, "use clear_code to remove code" ); assert( mh->check_code(), "" ); @@ -1295,7 +1295,7 @@ void Method::set_code(const methodHandle& mh, nmethod *code, bool isRelocation) OrderAccess::storestore(); if (mh->is_continuation_native_intrinsic()) { - assert(mh->_from_interpreted_entry == nullptr || isRelocation, "initialized incorrectly"); // see link_method + assert(mh->_from_interpreted_entry == nullptr, "initialized incorrectly"); // see link_method if (mh->is_continuation_enter_intrinsic()) { // This is the entry used when we're in interpreter-only mode; see InterpreterMacroAssembler::jump_from_interpreted diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index f033eda1e57c1..5daa572a46ccf 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -373,7 +373,7 @@ class Method : public Metadata { } public: - static void set_code(const methodHandle& mh, nmethod* code, bool isRelocation); + static void set_code(const methodHandle& mh, nmethod* code); void set_adapter_entry(AdapterHandlerEntry* adapter) { _adapter = adapter; } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 2b14cf771f958..2f29ce9b1fc6d 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2849,7 +2849,7 @@ void AdapterHandlerLibrary::create_native_wrapper(const methodHandle& method) { { MutexLocker pl(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { - method->set_code(method, nm, false); + method->set_code(method, nm); } } From 69d941b41b819eb321bbcda9a2f95443ff146c35 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 13 Mar 2025 22:55:13 +0000 Subject: [PATCH 016/103] Add PRODUCT check --- src/hotspot/share/code/nmethod.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 7789e55410867..2fb0d9f17d0a2 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1434,8 +1434,10 @@ nmethod* nmethod::clone(CodeBlobType code_blob_type) { nm_copy->_pc_desc_container = new PcDescContainer(nm_copy->scopes_pcs_begin()); } +#ifndef PRODUCT _asm_remarks.reuse(); _dbg_strings.reuse(); +#endif // Fix relocation RelocIterator iter(nm_copy); From 80734cd3eed5efe45168fec2b30a4eb92688c162 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 14 Mar 2025 20:42:02 +0000 Subject: [PATCH 017/103] Share immutable data between copied nmethods --- src/hotspot/share/code/nmethod.cpp | 32 ++++++++++++++++++++---------- src/hotspot/share/code/nmethod.hpp | 9 +++++++-- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 2fb0d9f17d0a2..a0930584107dc 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1167,7 +1167,8 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, #if INCLUDE_JVMCI + align_up(speculations_len , oopSize) #endif - + align_up(debug_info->data_size() , oopSize); + + align_up(debug_info->data_size() , oopSize) + + align_up(oopSize , oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -1401,15 +1402,11 @@ nmethod* nmethod::clone(CodeBlobType code_blob_type) { nmethod* nm_copy = (nmethod*) CodeCache::allocate(size(), code_blob_type); memcpy(nm_copy, this, size()); - // Allocate memory and copy immutable data from C heap + // Increment number of references to immutable data to share it between nmethods if (immutable_data_size() > 0) { - nm_copy->_immutable_data = (address)os::malloc(immutable_data_size(), mtCode); - if (nm_copy->_immutable_data == nullptr) { - vm_exit_out_of_memory(immutable_data_size(), OOM_MALLOC_ERROR, "nmethod: no space for immutable data"); - } - memcpy(nm_copy->immutable_data_begin(), immutable_data_begin(), immutable_data_size()); + (*immutable_data_references_begin())++; } else { - nm_copy->_immutable_data = nm_copy->data_end(); + nm_copy->_immutable_data = nm_copy->blob_end(); } // Allocate memory and copy mutable data from C heap @@ -1419,6 +1416,8 @@ nmethod* nmethod::clone(CodeBlobType code_blob_type) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "nmethod: no space for mutable data"); } memcpy(nm_copy->mutable_data_begin(), mutable_data_begin(), mutable_data_size()); + } else { + nm_copy->_mutable_data = nullptr; } // Fix new nmethod specific data @@ -1670,9 +1669,11 @@ nmethod::nmethod( #if INCLUDE_JVMCI _speculations_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize); ) + _immutable_data_references_offset = _speculations_offset + align_up(speculations_len, oopSize); + DEBUG_ONLY( int immutable_data_end_offset = _immutable_data_references_offset + align_up(oopSize, oopSize); ) #else - DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); ) + _immutable_data_references_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); + DEBUG_ONLY( int immutable_data_end_offset = _immutable_data_references_offset + align_up(oopSize, oopSize); ) #endif assert(immutable_data_end_offset <= immutable_data_size, "wrong read-only data size: %d > %d", immutable_data_end_offset, immutable_data_size); @@ -1705,6 +1706,7 @@ nmethod::nmethod( memcpy(speculations_begin(), speculations, speculations_len); } #endif + memset(immutable_data_references_begin(), 1, oopSize); post_init(); @@ -2284,7 +2286,15 @@ void nmethod::purge(bool unregister_nmethod) { delete[] _compiled_ic_data; if (_immutable_data != blob_end()) { - os::free(_immutable_data); + long _immutable_data_references = *immutable_data_references_begin(); + + // Free memory if this is the last nmethod referencing immutable data + if (_immutable_data_references == 1) { + os::free(_immutable_data); + } else { + (*immutable_data_references_begin())--; + } + _immutable_data = blob_end(); // Valid not null address } if (unregister_nmethod) { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index b1e7932b49bc6..c2c4ff507e000 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -155,6 +155,7 @@ class PcDescContainer : public CHeapObj { // - Scopes data array // - Scopes pcs array // - JVMCI speculations array +// - Nmethod reference counter #if INCLUDE_JVMCI class FailedSpeculation; @@ -249,6 +250,7 @@ class nmethod : public CodeBlob { #if INCLUDE_JVMCI int _speculations_offset; #endif + int _immutable_data_references_offset; // location in frame (offset for sp) that deopt can store the original // pc during a deopt. @@ -575,11 +577,14 @@ class nmethod : public CodeBlob { #if INCLUDE_JVMCI address scopes_data_end () const { return _immutable_data + _speculations_offset ; } address speculations_begin () const { return _immutable_data + _speculations_offset ; } - address speculations_end () const { return immutable_data_end(); } + address speculations_end () const { return _immutable_data + _immutable_data_references_offset ; } #else - address scopes_data_end () const { return immutable_data_end(); } + address scopes_data_end () const { return _immutable_data + _immutable_data_references_offset ; } #endif + address immutable_data_references_begin () const { return _immutable_data + _immutable_data_references_offset ; } + address immutable_data_references_end () const { return immutable_data_end(); } + // Sizes int immutable_data_size() const { return _immutable_data_size; } int consts_size () const { return int( consts_end () - consts_begin ()); } From 7b448c6cd4994924cdc36fa14f709e1672ebf13c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 14 Mar 2025 21:53:45 +0000 Subject: [PATCH 018/103] Fix build issues --- make/hotspot/lib/CompileJvm.gmk | 1 + src/hotspot/share/asm/codeBuffer.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index 6b5edc85b2369..57c9e386ed61b 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -198,6 +198,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \ DISABLED_WARNINGS_gcc_jvmFlag.cpp := unused-const-variable, \ DISABLED_WARNINGS_gcc_jvmtiTagMap.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_macroAssembler_ppc_sha.cpp := unused-const-variable, \ + DISABLED_WARNINGS_gcc_nmethod.cpp := class-memaccess, \ DISABLED_WARNINGS_gcc_postaloc.cpp := address, \ DISABLED_WARNINGS_gcc_shenandoahLock.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_stubGenerator_s390.cpp := unused-const-variable, \ diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 2cfdba40397d4..ea6126d5664d8 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -28,6 +28,7 @@ #include "code/oopRecorder.hpp" #include "code/relocInfo.hpp" #include "compiler/compiler_globals.hpp" +#include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" #include "utilities/growableArray.hpp" From 54e698828c190282dc5295ea175d8c60e1dfc4b8 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 17 Mar 2025 17:51:18 +0000 Subject: [PATCH 019/103] Remove relocate all --- src/hotspot/share/prims/whitebox.cpp | 36 ------ .../whitebox/RelocateAllNMethods.java | 107 ----------------- .../RelocateAndDeoptmizeAllNMethods.java | 111 ------------------ test/lib/jdk/test/whitebox/WhiteBox.java | 1 - 4 files changed, 255 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/whitebox/RelocateAllNMethods.java delete mode 100644 test/hotspot/jtreg/compiler/whitebox/RelocateAndDeoptmizeAllNMethods.java diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 92b8000c3d186..d7c636944ec5a 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1637,41 +1637,6 @@ WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint nmethod::relocate_to(code, static_cast(blob_type)); WB_END -WB_ENTRY(void, WB_RelocateAllNMethods(JNIEnv* env)) - ResourceMark rm(THREAD); - - // Get all nmethods in heap - GrowableArray nmethods; - for (int codeBlobTypeIndex = 0; codeBlobTypeIndex < (int) CodeBlobType::NumTypes; codeBlobTypeIndex++) { - CodeHeap* heap; - { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - heap = WhiteBox::get_code_heap(static_cast(codeBlobTypeIndex)); - if (heap == nullptr) { - continue; - } - } - - for (CodeBlob* cb = (CodeBlob*) heap->first(); cb != nullptr; cb = (CodeBlob*) heap->next(cb)) { - if (cb->is_nmethod()) { - nmethods.append(cb->as_nmethod()); - } - } - - if (!SegmentedCodeCache) { - break; - } - } - - // Replace all - for (GrowableArrayIterator it = nmethods.begin(); it != nmethods.end(); ++it) { - // Destination should be different than current location - CodeBlobType code_cache_dest = (*it)->lookup_code_blob_type() == CodeBlobType::MethodNonProfiled ? CodeBlobType::MethodProfiled : CodeBlobType::MethodNonProfiled; - nmethod::relocate_to(*it, code_cache_dest); - } - -WB_END - CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled"); BufferBlob* blob; @@ -2917,7 +2882,6 @@ static JNINativeMethod methods[] = { (void*)&WB_GetNMethod }, {CC"relocateNMethodTo0", CC"(Ljava/lang/reflect/Executable;I)V", (void*)&WB_RelocateNMethodTo }, - {CC"relocateAllNMethods", CC"()V", (void*)&WB_RelocateAllNMethods}, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/RelocateAllNMethods.java deleted file mode 100644 index d85ed6ed9e878..0000000000000 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateAllNMethods.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test id=Serial - * @bug 8316694 - * @summary Relocates all nmethods and runs garbage collector to cleanup old versions - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.RelocateAllNMethods - */ - -/* - * @test id=Parallel - * @bug 8316694 - * @summary Relocates all nmethods and runs garbage collector to cleanup old versions - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.RelocateAllNMethods - */ - -/* - * @test id=G1 - * @bug 8316694 - * @summary Relocates all nmethods and runs garbage collector to cleanup old versions - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.RelocateAllNMethods - */ - -/* - * @test id=Shenandoah - * @bug 8316694 - * @summary Relocates all nmethods and runs garbage collector to cleanup old versions - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.RelocateAllNMethods - */ - -/* - * @test id=ZGC - * @bug 8316694 - * @summary Relocates all nmethods and runs garbage collector to cleanup old versions - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.RelocateAllNMethods - */ - -package compiler.whitebox; - -import jdk.test.whitebox.WhiteBox; - -public class RelocateAllNMethods { - - private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - - public static void main(String [] args) throws Exception { - WHITE_BOX.relocateAllNMethods(); - - WHITE_BOX.fullGC(); - } -} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateAndDeoptmizeAllNMethods.java b/test/hotspot/jtreg/compiler/whitebox/RelocateAndDeoptmizeAllNMethods.java deleted file mode 100644 index 36a4776eaccef..0000000000000 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateAndDeoptmizeAllNMethods.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test id=Serial - * @bug 8316694 - * @summary Relocates all nmethods and also deoptimizes to confirm no crashes - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.RelocateAndDeoptmizeAllNMethods - */ - -/* - * @test id=Parallel - * @bug 8316694 - * @summary Relocates all nmethods and also deoptimizes to confirm no crashes - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.RelocateAndDeoptmizeAllNMethods - */ - -/* - * @test id=G1 - * @bug 8316694 - * @summary Relocates all nmethods and also deoptimizes to confirm no crashes - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.RelocateAndDeoptmizeAllNMethods - */ - -/* - * @test id=Shenandoah - * @bug 8316694 - * @summary Relocates all nmethods and also deoptimizes to confirm no crashes - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.RelocateAndDeoptmizeAllNMethods - */ - -/* - * @test id=ZGC - * @bug 8316694 - * @summary Relocates all nmethods and also deoptimizes to confirm no crashes - * @library /test/lib / - * @modules java.base/jdk.internal.misc java.management - * - * @requires vm.opt.DeoptimizeALot != true - * - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.RelocateAndDeoptmizeAllNMethods - */ - -package compiler.whitebox; - -import jdk.test.whitebox.WhiteBox; - -public class RelocateAndDeoptmizeAllNMethods { - - private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - - public static void main(String [] args) throws Exception { - WHITE_BOX.relocateAllNMethods(); - - WHITE_BOX.fullGC(); - - WHITE_BOX.deoptimizeAll(); - - WHITE_BOX.fullGC(); - } -} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index d656122e26d7a..4fbc4772ab915 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -491,7 +491,6 @@ public void relocateNMethodTo(Executable method, int type) { Objects.requireNonNull(method); relocateNMethodTo0(method, type); } - public native void relocateAllNMethods(); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; From 899707e695b3873493b5c3317dc8bd033e4c9610 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 17 Mar 2025 17:54:11 +0000 Subject: [PATCH 020/103] Remove old copy constructor from header file --- src/hotspot/share/code/nmethod.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index c2c4ff507e000..d2c5294c00f24 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -335,8 +335,6 @@ class nmethod : public CodeBlob { #endif ); - nmethod(nmethod& nm); - // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); From 354ba3b8ed968eb17ebad2187d31ca0e4cfdc22f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 17 Mar 2025 17:58:36 +0000 Subject: [PATCH 021/103] Remove current code heap check --- src/hotspot/share/code/codeCache.hpp | 2 +- src/hotspot/share/code/nmethod.cpp | 9 --------- src/hotspot/share/code/nmethod.hpp | 3 --- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 23fc1b84bac6c..a70200863485e 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -144,6 +144,7 @@ class CodeCache : AllStatic { static int code_heap_compare(CodeHeap* const &lhs, CodeHeap* const &rhs); static void add_heap(CodeHeap* heap); + static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr static const GrowableArray* heaps() { return _heaps; } static const GrowableArray* nmethod_heaps() { return _nmethod_heaps; } @@ -160,7 +161,6 @@ class CodeCache : AllStatic { static void metadata_do(MetadataClosure* f); // iterates over metadata in alive nmethods // Lookup - static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr static CodeBlob* find_blob(void* start); // Returns the CodeBlob containing the given address static CodeBlob* find_blob_fast(void* start); // Returns the CodeBlob containing the given address static CodeBlob* find_blob_and_oopmap(void* start, int& slot); // Returns the CodeBlob containing the given address diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index a0930584107dc..5e06cab049637 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1458,11 +1458,6 @@ nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { return nullptr; } - // No need to relocate if already in correct code heap - if (nm->lookup_code_blob_type() == code_blob_type) { - return nm; - } - nmethod* nm_copy = nullptr; { @@ -1533,10 +1528,6 @@ bool nmethod::is_relocatable() const { return true; } -CodeBlobType nmethod::lookup_code_blob_type() { - return CodeCache::get_code_heap_containing(this)->code_blob_type(); -} - void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () { return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index d2c5294c00f24..8a5e20aa401e3 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -499,7 +499,6 @@ class nmethod : public CodeBlob { // Relocate the nmethod to the code heap identified by code_blob_type. // Returns nullptr if the code heap does not have enough space, otherwise // the relocated nmethod. The original nmethod will be invalidated. - // If nm is already in the needed code heap, it is not relocated and the function returns it. static nmethod* relocate_to(nmethod* nm, CodeBlobType code_blob_type); static nmethod* new_native_nmethod(const methodHandle& method, @@ -520,8 +519,6 @@ class nmethod : public CodeBlob { bool is_relocatable() const; - CodeBlobType lookup_code_blob_type(); - // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, // and native method wrappers are also numbered independently if From 328c5f67c9899d21de1ac494343d9a84b0b9830b Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 17 Mar 2025 18:44:41 +0000 Subject: [PATCH 022/103] Immutable data references updates --- src/hotspot/share/code/nmethod.cpp | 18 +++++++----------- src/hotspot/share/code/nmethod.hpp | 11 ++++++----- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5e06cab049637..03336aa01acb6 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1168,7 +1168,7 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, + align_up(speculations_len , oopSize) #endif + align_up(debug_info->data_size() , oopSize) - + align_up(oopSize , oopSize); + + align_up(sizeof(int) , oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -1404,7 +1404,7 @@ nmethod* nmethod::clone(CodeBlobType code_blob_type) { // Increment number of references to immutable data to share it between nmethods if (immutable_data_size() > 0) { - (*immutable_data_references_begin())++; + set_immutable_data_references(get_immutable_data_references() + 1); } else { nm_copy->_immutable_data = nm_copy->blob_end(); } @@ -1660,11 +1660,9 @@ nmethod::nmethod( #if INCLUDE_JVMCI _speculations_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - _immutable_data_references_offset = _speculations_offset + align_up(speculations_len, oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _immutable_data_references_offset + align_up(oopSize, oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up(sizeof(int), oopSize); ) #else - _immutable_data_references_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _immutable_data_references_offset + align_up(oopSize, oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up(sizeof(int), oopSize); ) #endif assert(immutable_data_end_offset <= immutable_data_size, "wrong read-only data size: %d > %d", immutable_data_end_offset, immutable_data_size); @@ -1697,7 +1695,7 @@ nmethod::nmethod( memcpy(speculations_begin(), speculations, speculations_len); } #endif - memset(immutable_data_references_begin(), 1, oopSize); + set_immutable_data_references(1); post_init(); @@ -2277,13 +2275,11 @@ void nmethod::purge(bool unregister_nmethod) { delete[] _compiled_ic_data; if (_immutable_data != blob_end()) { - long _immutable_data_references = *immutable_data_references_begin(); - // Free memory if this is the last nmethod referencing immutable data - if (_immutable_data_references == 1) { + if (get_immutable_data_references() == 1) { os::free(_immutable_data); } else { - (*immutable_data_references_begin())--; + set_immutable_data_references(get_immutable_data_references() - 1); } _immutable_data = blob_end(); // Valid not null address diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 8a5e20aa401e3..7eb1ac75fc162 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -250,7 +250,6 @@ class nmethod : public CodeBlob { #if INCLUDE_JVMCI int _speculations_offset; #endif - int _immutable_data_references_offset; // location in frame (offset for sp) that deopt can store the original // pc during a deopt. @@ -572,13 +571,12 @@ class nmethod : public CodeBlob { #if INCLUDE_JVMCI address scopes_data_end () const { return _immutable_data + _speculations_offset ; } address speculations_begin () const { return _immutable_data + _speculations_offset ; } - address speculations_end () const { return _immutable_data + _immutable_data_references_offset ; } + address speculations_end () const { return immutable_data_end() - sizeof(int) ; } #else - address scopes_data_end () const { return _immutable_data + _immutable_data_references_offset ; } + address scopes_data_end () const { return immutable_data_end() - sizeof(int) ; } #endif - address immutable_data_references_begin () const { return _immutable_data + _immutable_data_references_offset ; } - address immutable_data_references_end () const { return immutable_data_end(); } + address immutable_data_references_begin () const { return immutable_data_end() - sizeof(int) ; } // Sizes int immutable_data_size() const { return _immutable_data_size; } @@ -892,6 +890,9 @@ class nmethod : public CodeBlob { bool load_reported() const { return _load_reported; } void set_load_reported() { _load_reported = true; } + inline int get_immutable_data_references() { return *immutable_data_references_begin(); } + inline void set_immutable_data_references(int count) { (*immutable_data_references_begin()) = count; } + public: // ScopeDesc retrieval operation PcDesc* pc_desc_at(address pc) { return find_pc_desc(pc, false); } From 9391eaf2b793f4f7c0a0d13b21f107aecad5da27 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 17 Mar 2025 21:51:46 +0000 Subject: [PATCH 023/103] Update tests --- .../compiler/whitebox/RelocateNMethod.java | 3 +- .../RelocateNMethodMultiplePaths.java | 132 ++++++++++++++---- 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java index be1d825155ad5..258a121d5bd4f 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,6 +19,7 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. + * */ /* diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java index 88111e041570a..3a7971b9fbe22 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,10 +19,25 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. + * + */ + +/* + * @test id=SerialC1 + * @bug 8316694 + * @requires vm.debug == true + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC compiler.whitebox.RelocateNMethodMultiplePaths */ /* - * @test id=Serial + * @test id=SerialC2 * @bug 8316694 * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized @@ -31,12 +46,12 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache - * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC compiler.whitebox.RelocateNMethodMultiplePaths + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC compiler.whitebox.RelocateNMethodMultiplePaths */ /* - * @test id=Parallel + * @test id=ParallelC1 * @bug 8316694 * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized @@ -45,12 +60,12 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache - * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC compiler.whitebox.RelocateNMethodMultiplePaths + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC compiler.whitebox.RelocateNMethodMultiplePaths */ /* - * @test id=G1 + * @test id=ParallelC2 * @bug 8316694 * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized @@ -59,12 +74,12 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache - * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC compiler.whitebox.RelocateNMethodMultiplePaths + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC compiler.whitebox.RelocateNMethodMultiplePaths */ /* - * @test id=Shenandoah + * @test id=G1C1 * @bug 8316694 * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized @@ -73,12 +88,12 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache - * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC compiler.whitebox.RelocateNMethodMultiplePaths + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC compiler.whitebox.RelocateNMethodMultiplePaths */ /* - * @test id=ZGC + * @test id=G1C2 * @bug 8316694 * @requires vm.debug == true * @summary test that relocated nmethod is correctly deoptimized @@ -87,8 +102,64 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache - * -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC compiler.whitebox.RelocateNMethodMultiplePaths + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ShenandoahC1 + * @bug 8316694 + * @requires vm.debug == true + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ShenandoahC2 + * @bug 8316694 + * @requires vm.debug == true + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ZGCC1 + * @bug 8316694 + * @requires vm.debug == true + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ZGCC2 + * @bug 8316694 + * @requires vm.debug == true + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC compiler.whitebox.RelocateNMethodMultiplePaths */ package compiler.whitebox; @@ -102,7 +173,9 @@ public class RelocateNMethodMultiplePaths { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - public static double FUNCTION_RESULT = 0; + + private static final int PATH_ONE_RESULT = 1; + private static final int PATH_TWO_RESULT = 2; public static void main(String [] args) throws Exception { // Get method that will be relocated @@ -122,7 +195,7 @@ public static void main(String [] args) throws Exception { NMethod origNmethod = NMethod.get(method, false); // Relocate nmethod and mark old for cleanup - WHITE_BOX.relocateNMethodTo(method, BlobType.MethodProfiled.id); + WHITE_BOX.relocateNMethodTo(method, BlobType.MethodNonProfiled.id); // Trigger GC to clean up old nmethod WHITE_BOX.fullGC(); @@ -136,14 +209,19 @@ public static void main(String [] args) throws Exception { throw new RuntimeException("Did not create new nmethod"); } - // Call function again with different path so it gets deoptimized - function(false); + // Verify function still produces correct result + if (function(true) != PATH_ONE_RESULT) { + throw new RuntimeException("Relocated function produced incorrect result in path one"); + } - CompilerWhiteBoxTest.checkNotCompiled(method, false); + // Call function again with different path and verify result + if (function(false) != PATH_TWO_RESULT) { + throw new RuntimeException("Relocated function produced incorrect result in path two"); + } - // Call both paths to verify everything still works - function(true); - function(false); + // Verify function can be correctly deoptimized + WHITE_BOX.deoptimizeMethod(method); + CompilerWhiteBoxTest.checkNotCompiled(method, false); } // Call function multiple times to trigger compilation @@ -153,11 +231,11 @@ private static void callFunction(boolean pathOne) { } } - public static void function(boolean pathOne) { + public static int function(boolean pathOne) { if (pathOne) { - FUNCTION_RESULT = 1; + return PATH_ONE_RESULT; } else { - FUNCTION_RESULT = 2; + return PATH_TWO_RESULT; } } } From 8f12fd3d41a2a4a83e7c03e294645e00ff14e14c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 17 Mar 2025 22:29:29 +0000 Subject: [PATCH 024/103] Cast dest to void star --- src/hotspot/share/code/nmethod.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 03336aa01acb6..870ee9089d500 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1400,7 +1400,7 @@ nmethod* nmethod::clone(CodeBlobType code_blob_type) { // Allocate memory in code heap and copy data from nmethod nmethod* nm_copy = (nmethod*) CodeCache::allocate(size(), code_blob_type); - memcpy(nm_copy, this, size()); + memcpy((void*) nm_copy, this, size()); // Increment number of references to immutable data to share it between nmethods if (immutable_data_size() > 0) { From 917046bb4759a45b4d40fbf9fdcfd438c92a917d Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 17 Mar 2025 23:58:08 +0000 Subject: [PATCH 025/103] Remove DISABLED_WARNINGS --- make/hotspot/lib/CompileJvm.gmk | 1 - 1 file changed, 1 deletion(-) diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index 57c9e386ed61b..6b5edc85b2369 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -198,7 +198,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \ DISABLED_WARNINGS_gcc_jvmFlag.cpp := unused-const-variable, \ DISABLED_WARNINGS_gcc_jvmtiTagMap.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_macroAssembler_ppc_sha.cpp := unused-const-variable, \ - DISABLED_WARNINGS_gcc_nmethod.cpp := class-memaccess, \ DISABLED_WARNINGS_gcc_postaloc.cpp := address, \ DISABLED_WARNINGS_gcc_shenandoahLock.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_stubGenerator_s390.cpp := unused-const-variable, \ From 3b8d09305a3d098f06c9a13e4931768d93397c5f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 18 Mar 2025 00:01:44 +0000 Subject: [PATCH 026/103] revert --- src/hotspot/share/code/codeCache.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index a70200863485e..3e446ab8430fe 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -117,6 +117,7 @@ class CodeCache : AllStatic { // Creates a new heap with the given name and size, containing CodeBlobs of the given type static void add_heap(ReservedSpace rs, const char* name, CodeBlobType code_blob_type); + static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr static CodeHeap* get_code_heap(const void* cb); // Returns the CodeHeap for the given CodeBlob static CodeHeap* get_code_heap(CodeBlobType code_blob_type); // Returns the CodeHeap for the given CodeBlobType // Returns the name of the VM option to set the size of the corresponding CodeHeap @@ -144,7 +145,6 @@ class CodeCache : AllStatic { static int code_heap_compare(CodeHeap* const &lhs, CodeHeap* const &rhs); static void add_heap(CodeHeap* heap); - static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr static const GrowableArray* heaps() { return _heaps; } static const GrowableArray* nmethod_heaps() { return _nmethod_heaps; } From c8827627152554b1f3784e44af6a29be5d809686 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 18 Mar 2025 00:01:53 +0000 Subject: [PATCH 027/103] Fix copywrite --- .../jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java index a988e167e832d..3bd581485867b 100644 --- a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,6 +19,7 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. + * */ /* From 053133547999fc83ef816f2d1a3b6d15f425c544 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 19 Mar 2025 18:59:25 +0000 Subject: [PATCH 028/103] Fix windows build --- src/hotspot/share/code/nmethod.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 870ee9089d500..076396c31240c 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1168,7 +1168,7 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, + align_up(speculations_len , oopSize) #endif + align_up(debug_info->data_size() , oopSize) - + align_up(sizeof(int) , oopSize); + + align_up((int)sizeof(int) , oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -1660,9 +1660,9 @@ nmethod::nmethod( #if INCLUDE_JVMCI _speculations_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up(sizeof(int), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up((int)sizeof(int), oopSize); ) #else - DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up(sizeof(int), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up((int)sizeof(int), oopSize); ) #endif assert(immutable_data_end_offset <= immutable_data_size, "wrong read-only data size: %d > %d", immutable_data_end_offset, immutable_data_size); From a7f32409ab949c10be0bb203206e78c8321a8f9c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 24 Mar 2025 22:10:44 +0000 Subject: [PATCH 029/103] Relocate nmethod at safepoint --- src/hotspot/share/code/nmethod.cpp | 90 ++++++++++------------ src/hotspot/share/code/nmethod.hpp | 3 +- src/hotspot/share/runtime/vmOperation.hpp | 2 +- src/hotspot/share/runtime/vmOperations.cpp | 7 +- src/hotspot/share/runtime/vmOperations.hpp | 12 ++- 5 files changed, 56 insertions(+), 58 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 076396c31240c..a9e8f07af09ac 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1395,8 +1395,7 @@ nmethod::nmethod( } nmethod* nmethod::clone(CodeBlobType code_blob_type) { - debug_only(NoSafepointVerifier nsv;) - assert_locked_or_safepoint(CodeCache_lock); + assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); // Allocate memory in code heap and copy data from nmethod nmethod* nm_copy = (nmethod*) CodeCache::allocate(size(), code_blob_type); @@ -1448,63 +1447,54 @@ nmethod* nmethod::clone(CodeBlobType code_blob_type) { ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); + nm_copy->clear_inline_caches(); + + // Update corresponding Java method to point to this nmethod + if (nm_copy->method()->code() == this) { + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); + methodHandle mh(Thread::current(), nm_copy->method()); + nm_copy->method()->set_code(mh, nm_copy); + } + + // To make dependency checking during class loading fast, record + // the nmethod dependencies in the classes it is dependent on. + // This allows the dependency checking code to simply walk the + // class hierarchy above the loaded class, checking only nmethods + // which are dependent on those classes. The slow way is to + // check every nmethod for dependencies which makes it linear in + // the number of methods compiled. For applications with a lot + // classes the slow way is too slow. + for (Dependencies::DepStream deps(nm_copy); deps.next(); ) { + if (deps.type() == Dependencies::call_site_target_value) { + // CallSite dependencies are managed on per-CallSite instance basis. + oop call_site = deps.argument_oop(0); + MethodHandles::add_dependent_nmethod(call_site, nm_copy); + } else { + InstanceKlass* ik = deps.context_type(); + if (ik == nullptr) { + continue; // ignore things like evol_method + } + // record this nmethod as dependent on this klass + ik->add_dependent_nmethod(nm_copy); + } + } + nm_copy->post_init(); + make_not_used(); + return nm_copy; } nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { - if (nm == nullptr || !nm->is_relocatable()) { - return nullptr; - } - - nmethod* nm_copy = nullptr; - - { - // Clear inline caches before acquiring any locks - VM_ClearNMethodICs clear_nmethod_ics(nm); - VMThread::execute(&clear_nmethod_ics); - - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - nm_copy = nm->clone(code_blob_type); - - if (nm_copy != nullptr) { - // To make dependency checking during class loading fast, record - // the nmethod dependencies in the classes it is dependent on. - // This allows the dependency checking code to simply walk the - // class hierarchy above the loaded class, checking only nmethods - // which are dependent on those classes. The slow way is to - // check every nmethod for dependencies which makes it linear in - // the number of methods compiled. For applications with a lot - // classes the slow way is too slow. - for (Dependencies::DepStream deps(nm_copy); deps.next(); ) { - if (deps.type() == Dependencies::call_site_target_value) { - // CallSite dependencies are managed on per-CallSite instance basis. - oop call_site = deps.argument_oop(0); - MethodHandles::add_dependent_nmethod(call_site, nm_copy); - } else { - InstanceKlass* ik = deps.context_type(); - if (ik == nullptr) { - continue; // ignore things like evol_method - } - // record this nmethod as dependent on this klass - ik->add_dependent_nmethod(nm_copy); - } - } + // Relocate nmethod at safepoint + VM_RelocateNMethod relocate_nmethod(nm, code_blob_type); + VMThread::execute(&relocate_nmethod); + nmethod* nm_copy = relocate_nmethod.getRelocatedNMethod(); - // Update corresponding Java method to point to this nmethod - MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); - if (nm_copy->method()->code() == nm) { - methodHandle mh(Thread::current(), nm_copy->method()); - nm_copy->method()->set_code(mh, nm_copy); - nm->make_not_used(); - } - } - } - // Do verification and logging outside CodeCache_lock. + // Do verification and logging outside safepoint if (nm_copy != nullptr) { NOT_PRODUCT(note_java_nmethod(nm_copy)); - // Safepoints in nmethod::verify aren't allowed because nm_copy hasn't been installed yet. DEBUG_ONLY(nm_copy->verify();) nm_copy->log_new_nmethod(); } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 7eb1ac75fc162..fcd2c232b1df3 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -342,8 +342,6 @@ class nmethod : public CodeBlob { // findable by nmethod iterators! In particular, they must not contain oops! void* operator new(size_t size, int nmethod_size, bool allow_NonNMethod_space) throw(); - nmethod* clone(CodeBlobType code_blob_type); - const char* reloc_string_for(u_char* begin, u_char* end); bool try_transition(signed char new_state); @@ -494,6 +492,7 @@ class nmethod : public CodeBlob { #endif ); + nmethod* clone(CodeBlobType code_blob_type); // Relocate the nmethod to the code heap identified by code_blob_type. // Returns nullptr if the code heap does not have enough space, otherwise diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index 92213bda1626c..3f9e4b7d8107a 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -41,7 +41,7 @@ template(PrintThreads) \ template(FindDeadlocks) \ template(ClearICs) \ - template(ClearNMethodICs) \ + template(RelocateNMethod) \ template(ForceSafepoint) \ template(DeoptimizeFrame) \ template(DeoptimizeAll) \ diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index 4f6f6817369be..7419513c73720 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -100,8 +100,11 @@ void VM_ClearICs::doit() { } } -void VM_ClearNMethodICs::doit() { - _nm->clear_inline_caches(); +void VM_RelocateNMethod::doit() { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + if (_nm != nullptr && _nm->is_relocatable()) { + _nm_copy = _nm->clone(_code_blob_type); + } } void VM_CleanClassLoaderDataMetaspaces::doit() { diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index bc99e695bd9ba..8b931cdde07e6 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_RUNTIME_VMOPERATIONS_HPP #define SHARE_RUNTIME_VMOPERATIONS_HPP +#include "code/codeBlob.hpp" #include "oops/oop.hpp" #include "runtime/javaThread.hpp" #include "runtime/vmOperation.hpp" @@ -81,13 +82,18 @@ class VM_ClearICs: public VM_Operation { VMOp_Type type() const { return VMOp_ClearICs; } }; -class VM_ClearNMethodICs: public VM_Operation { +class VM_RelocateNMethod: public VM_Operation { private: nmethod* _nm; + nmethod* _nm_copy; + CodeBlobType _code_blob_type; public: - VM_ClearNMethodICs(nmethod* nm) { _nm = nm; } + VM_RelocateNMethod(nmethod* nm, CodeBlobType code_blob_type) + : _nm(nm), _nm_copy(nullptr), _code_blob_type(code_blob_type) + {} void doit(); - VMOp_Type type() const { return VMOp_ClearNMethodICs; } + VMOp_Type type() const { return VMOp_RelocateNMethod; } + nmethod* getRelocatedNMethod() { return _nm_copy; } }; // Base class for invoking parts of a gtest in a safepoint. From e12e2c18c521c2789f6ba34173e95b4cd4396a23 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 2 Apr 2025 21:48:22 +0000 Subject: [PATCH 030/103] Fix call sites and change relocation to opt in --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 3 + src/hotspot/share/ci/ciEnv.cpp | 24 ++- src/hotspot/share/code/nmethod.cpp | 187 +++++++++++++----- src/hotspot/share/code/nmethod.hpp | 13 +- src/hotspot/share/code/relocInfo.cpp | 13 +- .../share/compiler/compiler_globals.hpp | 3 + src/hotspot/share/prims/whitebox.cpp | 3 +- src/hotspot/share/runtime/vmOperations.cpp | 5 +- 8 files changed, 180 insertions(+), 71 deletions(-) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 94694b58d2fae..2a20634659ed7 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -81,6 +81,9 @@ void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { NativeCall* call = nativeCall_at(addr()); + if (!Assembler::reachable_from_branch_at(addr(), x)) { + x = call->get_trampoline(); + } call->set_destination(x); } else { MacroAssembler::pd_patch_instruction(addr(), x); diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 2a88154faf6c5..f26764333b907 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1121,17 +1121,23 @@ void ciEnv::register_method(ciMethod* target, } } - NoSafepointVerifier nsv; - if (nm != nullptr) { - // Compilation succeeded, post what we know about it - nm->post_compiled_method(task()); - task()->set_num_inlined_bytecodes(num_inlined_bytecodes()); - } else { - // The CodeCache is full. - record_failure("code cache is full"); + { + NoSafepointVerifier nsv; + if (nm != nullptr) { + // Compilation succeeded, post what we know about it + nm->post_compiled_method(task()); + task()->set_num_inlined_bytecodes(num_inlined_bytecodes()); + } else { + // The CodeCache is full. + record_failure("code cache is full"); + } } - // safepoints are allowed again + + if (StressNMethodRelocation) { + VM_RelocateNMethod relocate(nm, CodeBlobType::MethodNonProfiled); + VMThread::execute(&relocate); + } } // ------------------------------------------------------------------ diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index a9e8f07af09ac..74b8bc7ef9952 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1394,68 +1394,150 @@ nmethod::nmethod( } } -nmethod* nmethod::clone(CodeBlobType code_blob_type) { - assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); - // Allocate memory in code heap and copy data from nmethod - nmethod* nm_copy = (nmethod*) CodeCache::allocate(size(), code_blob_type); - memcpy((void*) nm_copy, this, size()); +nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_header_size) +{ - // Increment number of references to immutable data to share it between nmethods - if (immutable_data_size() > 0) { - set_immutable_data_references(get_immutable_data_references() + 1); + if (nm->_oop_maps != nullptr) { + _oop_maps = nm->_oop_maps->clone(); } else { - nm_copy->_immutable_data = nm_copy->blob_end(); + _oop_maps = nullptr; } - // Allocate memory and copy mutable data from C heap + _size = nm->_size; + _relocation_size = nm->_relocation_size; + _content_offset = nm->_content_offset; + _code_offset = nm->_code_offset; + _data_offset = nm->_data_offset; + _frame_size = nm->_frame_size; + + S390_ONLY( _ctable_offset = nm->_ctable_offset; ) + + _header_size = nm->_header_size; + _frame_complete_offset = nm->_frame_complete_offset; + + _kind = nm->_kind; + + _caller_must_gc_arguments = nm->_caller_must_gc_arguments; + +#ifndef PRODUCT + _asm_remarks.share(nm->_asm_remarks); + _dbg_strings.share(nm->_dbg_strings); +#endif + + // Allocate memory and copy mutable data to C heap + _mutable_data_size = nm->_mutable_data_size; if (_mutable_data_size > 0) { - nm_copy->_mutable_data = (address)os::malloc(_mutable_data_size, mtCode); + _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); if (_mutable_data == nullptr) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "nmethod: no space for mutable data"); } - memcpy(nm_copy->mutable_data_begin(), mutable_data_begin(), mutable_data_size()); + memcpy(mutable_data_begin(), nm->mutable_data_begin(), nm->mutable_data_size()); } else { - nm_copy->_mutable_data = nullptr; + _mutable_data = nullptr; } - // Fix new nmethod specific data - if (oop_maps() != nullptr) { - nm_copy->_oop_maps = oop_maps()->clone(); + _deoptimization_generation = 0; + _gc_epoch = CodeCache::gc_epoch(); + _method = nm->_method; + _osr_link = nullptr; + + // Increment number of references to immutable data to share it between nmethods + _immutable_data_size = nm->_immutable_data_size; + if (_immutable_data_size > 0) { + _immutable_data = nm->_immutable_data; + set_immutable_data_references(get_immutable_data_references() + 1); + } else { + _immutable_data = blob_end(); } - nm_copy->_exception_cache = nullptr; - nm_copy->_gc_data = nullptr; - nm_copy->_compiled_ic_data = nullptr; + _exception_cache = nullptr; + _gc_data = nullptr; + _oops_do_mark_nmethods = nullptr; + _oops_do_mark_link = nullptr; + _compiled_ic_data = nullptr; + + if (nm->_osr_entry_point != nullptr) { + _osr_entry_point = (nm->_osr_entry_point - (address) nm) + (address) this; + } else { + _osr_entry_point = nullptr; + } + + _entry_offset = nm->_entry_offset; + _verified_entry_offset = nm->_verified_entry_offset; + _entry_bci = nm->_entry_bci; + + _skipped_instructions_size = nm->_skipped_instructions_size; + _stub_offset = nm->_stub_offset; + _exception_offset = nm->_exception_offset; + _deopt_handler_offset = nm->_deopt_handler_offset; + _deopt_mh_handler_offset = nm->_deopt_mh_handler_offset; + _unwind_handler_offset = nm->_unwind_handler_offset; + _num_stack_arg_slots = nm->_num_stack_arg_slots; + _oops_size = nm->_oops_size; +#if INCLUDE_JVMCI + _jvmci_data_size = nm->_jvmci_data_size; +#endif + _nul_chk_table_offset = nm->_nul_chk_table_offset; + _handler_table_offset = nm->_handler_table_offset; + _scopes_pcs_offset = nm->_scopes_pcs_offset; + _scopes_data_offset = nm->_scopes_data_offset; +#if INCLUDE_JVMCI + _speculations_offset = nm->_speculations_offset; +#endif - if (_pc_desc_container != nullptr) { - nm_copy->_pc_desc_container = new PcDescContainer(nm_copy->scopes_pcs_begin()); + _orig_pc_offset = nm->_orig_pc_offset; + _compile_id = nm->_compile_id; + _comp_level = nm->_comp_level; + _compiler_type = nm->_compiler_type; + _is_unloading_state = nm->_is_unloading_state; + _state = not_installed; + + _has_unsafe_access = nm->_has_unsafe_access; + _has_method_handle_invokes = nm->_has_method_handle_invokes; + _has_wide_vectors = nm->_has_wide_vectors; + _has_monitors = nm->_has_monitors; + _has_scoped_access = nm->_has_scoped_access; + _has_flushed_dependencies = nm->_has_flushed_dependencies; + _is_unlinked = nm->_is_unlinked; + _load_reported = nm->_load_reported; + + _deoptimization_status = nm->_deoptimization_status; + + if (nm->_pc_desc_container != nullptr) { + _pc_desc_container = new PcDescContainer(scopes_pcs_begin()); + } else { + _pc_desc_container = nullptr; } -#ifndef PRODUCT - _asm_remarks.reuse(); - _dbg_strings.reuse(); -#endif + // Copy nmethod contents excluding header + // - Constant part (doubles, longs and floats used in nmethod) + // - Code part: + // - Code body + // - Exception handler + // - Stub code + // - OOP table + memcpy(consts_begin(), nm->consts_begin(), nm->data_end() - nm->consts_begin()); +} + +nmethod* nmethod::relocate(CodeBlobType code_blob_type) { + assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); + assert_lock_strong(CodeCache_lock); + assert_lock_strong(NMethodState_lock); + + run_nmethod_entry_barrier(); + nmethod* nm_copy = new (size(), code_blob_type) nmethod(this); // Fix relocation RelocIterator iter(nm_copy); - CodeBuffer src((CodeBlob *)this); + CodeBuffer src(this); CodeBuffer dst(nm_copy); while (iter.next()) { iter.reloc()->fix_relocation_after_move(&src, &dst); } - ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); - nm_copy->clear_inline_caches(); - // Update corresponding Java method to point to this nmethod - if (nm_copy->method()->code() == this) { - MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); - methodHandle mh(Thread::current(), nm_copy->method()); - nm_copy->method()->set_code(mh, nm_copy); - } - // To make dependency checking during class loading fast, record // the nmethod dependencies in the classes it is dependent on. // This allows the dependency checking code to simply walk the @@ -1479,31 +1561,30 @@ nmethod* nmethod::clone(CodeBlobType code_blob_type) { } } + ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); + nm_copy->post_init(); - make_not_used(); + // Update corresponding Java method to point to this nmethod + if (nm_copy->method() != nullptr && nm_copy->method()->code() == this && nm_copy->make_in_use()) { + methodHandle mh(Thread::current(), nm_copy->method()); + nm_copy->method()->set_code(mh, nm_copy); + make_not_used(); + } return nm_copy; } -nmethod* nmethod::relocate_to(nmethod* nm, CodeBlobType code_blob_type) { - // Relocate nmethod at safepoint - VM_RelocateNMethod relocate_nmethod(nm, code_blob_type); - VMThread::execute(&relocate_nmethod); - nmethod* nm_copy = relocate_nmethod.getRelocatedNMethod(); - - // Do verification and logging outside safepoint - if (nm_copy != nullptr) { - NOT_PRODUCT(note_java_nmethod(nm_copy)); - DEBUG_ONLY(nm_copy->verify();) - nm_copy->log_new_nmethod(); +bool nmethod::is_relocatable() { + if (is_not_entrant()) { + return false; } - return nm_copy; -} + if (is_marked_for_deoptimization()) { + return false; + } -bool nmethod::is_relocatable() const { - if (is_not_entrant()) { + if (is_unloading()) { return false; } @@ -1522,6 +1603,10 @@ void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } +void* nmethod::operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw () { + return CodeCache::allocate(nmethod_size, code_blob_type); +} + void* nmethod::operator new(size_t size, int nmethod_size, bool allow_NonNMethod_space) throw () { // Try MethodNonProfiled and MethodProfiled. void* return_value = CodeCache::allocate(nmethod_size, CodeBlobType::MethodNonProfiled); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index fcd2c232b1df3..3fc7acb8bfc29 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -334,8 +334,11 @@ class nmethod : public CodeBlob { #endif ); + nmethod(nmethod* nm); + // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); + void* operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw(); // For method handle intrinsics: Try MethodNonProfiled, MethodProfiled and NonNMethod. // Attention: Only allow NonNMethod space for special nmethods which don't need to be @@ -492,12 +495,10 @@ class nmethod : public CodeBlob { #endif ); - nmethod* clone(CodeBlobType code_blob_type); - // Relocate the nmethod to the code heap identified by code_blob_type. // Returns nullptr if the code heap does not have enough space, otherwise // the relocated nmethod. The original nmethod will be invalidated. - static nmethod* relocate_to(nmethod* nm, CodeBlobType code_blob_type); + nmethod* relocate(CodeBlobType code_blob_type); static nmethod* new_native_nmethod(const methodHandle& method, int compile_id, @@ -515,7 +516,7 @@ class nmethod : public CodeBlob { bool is_java_method () const { return _method != nullptr && !_method->is_native(); } bool is_osr_method () const { return _entry_bci != InvocationEntryBci; } - bool is_relocatable() const; + bool is_relocatable(); // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, @@ -889,8 +890,8 @@ class nmethod : public CodeBlob { bool load_reported() const { return _load_reported; } void set_load_reported() { _load_reported = true; } - inline int get_immutable_data_references() { return *immutable_data_references_begin(); } - inline void set_immutable_data_references(int count) { (*immutable_data_references_begin()) = count; } + inline int get_immutable_data_references() { return *((int*)immutable_data_references_begin()); } + inline void set_immutable_data_references(int count) { *((int*)immutable_data_references_begin()) = count; } public: // ScopeDesc retrieval operation diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 833d98b390ed6..d695bb596d860 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -367,8 +367,17 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer // The enhanced use of pd_call_destination sorts this all out. address orig_addr = old_addr_for(addr(), src, dest); address callee = pd_call_destination(orig_addr); - // Reassert the callee address, this time in the new copy of the code. - pd_set_call_destination(callee); + + if (src->contains(callee)) { + // If the original call is to an address in the src CodeBuffer (such as a stub call) + // the updated call should be to the corresponding address in dest CodeBuffer + int offset = callee - orig_addr; + address new_addr = addr() + offset; + pd_set_call_destination(new_addr); + } else { + // Reassert the callee address, this time in the new copy of the code. + pd_set_call_destination(callee); + } } diff --git a/src/hotspot/share/compiler/compiler_globals.hpp b/src/hotspot/share/compiler/compiler_globals.hpp index a811cd8b3bae6..36c9775b27c79 100644 --- a/src/hotspot/share/compiler/compiler_globals.hpp +++ b/src/hotspot/share/compiler/compiler_globals.hpp @@ -137,6 +137,9 @@ "and the value of the per-method flag.") \ range(0.0, DBL_MAX) \ \ + product(bool, StressNMethodRelocation, false, \ + "Stress relocation nmethods") \ + \ product(intx, Tier0InvokeNotifyFreqLog, 7, \ "Interpreter (tier 0) invocation notification frequency") \ range(0, 30) \ diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index d7c636944ec5a..5d8b182c5f77e 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1634,7 +1634,8 @@ WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint return; } - nmethod::relocate_to(code, static_cast(blob_type)); + VM_RelocateNMethod relocate(code, static_cast(blob_type)); + VMThread::execute(&relocate); WB_END CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index 7419513c73720..b8cfedd0418e0 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -101,9 +101,10 @@ void VM_ClearICs::doit() { } void VM_RelocateNMethod::doit() { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (_nm != nullptr && _nm->is_relocatable()) { - _nm_copy = _nm->clone(_code_blob_type); + _nm_copy = _nm->relocate(_code_blob_type); } } From 8e53ed1cbae54b68498ff2caf6ab102d42f184b9 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 17 Apr 2025 22:23:53 +0000 Subject: [PATCH 031/103] Undo AsmRemarks and DbgStrings reuse --- src/hotspot/share/asm/codeBuffer.cpp | 107 +++++++++++++++++++++++++-- src/hotspot/share/asm/codeBuffer.hpp | 100 ------------------------- 2 files changed, 99 insertions(+), 108 deletions(-) diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 5e8a949c32e4b..9c75777752f8f 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -1080,6 +1080,105 @@ void CodeBuffer::print() { } } +// ----- CHeapString ----------------------------------------------------------- + +class CHeapString : public CHeapObj { + public: + CHeapString(const char* str) : _string(os::strdup(str)) {} + ~CHeapString() { + os::free((void*)_string); + _string = nullptr; + } + const char* string() const { return _string; } + + private: + const char* _string; + }; + + // ----- AsmRemarkCollection --------------------------------------------------- + +class AsmRemarkCollection : public CHeapObj { +public: + AsmRemarkCollection() : _ref_cnt(1), _remarks(nullptr), _next(nullptr) {} +~AsmRemarkCollection() { + assert(is_empty(), "Must 'clear()' before deleting!"); + assert(_ref_cnt == 0, "No uses must remain when deleting!"); + } + AsmRemarkCollection* reuse() { + precond(_ref_cnt > 0); + return _ref_cnt++, this; + } + + const char* insert(uint offset, const char* remark); + const char* lookup(uint offset) const; + const char* next(uint offset) const; + + bool is_empty() const { return _remarks == nullptr; } + uint clear(); + +private: + struct Cell : CHeapString { + Cell(const char* remark, uint offset) : + CHeapString(remark), offset(offset), prev(nullptr), next(nullptr) {} + void push_back(Cell* cell) { + Cell* head = this; + Cell* tail = prev; + tail->next = cell; + cell->next = head; + cell->prev = tail; + prev = cell; + } + uint offset; + Cell* prev; + Cell* next; + }; + uint _ref_cnt; + Cell* _remarks; + // Using a 'mutable' iteration pointer to allow 'const' on lookup/next (that + // does not change the state of the list per se), supportig a simplistic + // iteration scheme. + mutable Cell* _next; +}; + +// ----- DbgStringCollection --------------------------------------------------- + +class DbgStringCollection : public CHeapObj { +public: + DbgStringCollection() : _ref_cnt(1), _strings(nullptr) {} +~DbgStringCollection() { + assert(is_empty(), "Must 'clear()' before deleting!"); + assert(_ref_cnt == 0, "No uses must remain when deleting!"); + } + DbgStringCollection* reuse() { + precond(_ref_cnt > 0); + return _ref_cnt++, this; + } + + const char* insert(const char* str); + const char* lookup(const char* str) const; + + bool is_empty() const { return _strings == nullptr; } + uint clear(); + +private: + struct Cell : CHeapString { + Cell(const char* dbgstr) : + CHeapString(dbgstr), prev(nullptr), next(nullptr) {} + void push_back(Cell* cell) { + Cell* head = this; + Cell* tail = prev; + tail->next = cell; + cell->next = head; + cell->prev = tail; + prev = cell; + } + Cell* prev; + Cell* next; + }; + uint _ref_cnt; + Cell* _strings; +}; + // ----- AsmRemarks ------------------------------------------------------------ // // Acting as interface to reference counted mapping [offset -> remark], where @@ -1103,10 +1202,6 @@ bool AsmRemarks::is_empty() const { return _remarks->is_empty(); } -void AsmRemarks::reuse() { - _remarks->reuse(); -} - void AsmRemarks::share(const AsmRemarks &src) { precond(is_empty()); clear(); @@ -1159,10 +1254,6 @@ bool DbgStrings::is_empty() const { return _strings->is_empty(); } -void DbgStrings::reuse() { - _strings->reuse(); -} - void DbgStrings::share(const DbgStrings &src) { precond(is_empty()); clear(); diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index ea6126d5664d8..b6a46e20f5898 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -308,7 +308,6 @@ class AsmRemarks { bool is_empty() const; - void reuse(); void share(const AsmRemarks &src); void clear(); uint print(uint offset, outputStream* strm = tty) const; @@ -332,7 +331,6 @@ class DbgStrings { bool is_empty() const; - void reuse(); void share(const DbgStrings &src); void clear(); @@ -343,104 +341,6 @@ class DbgStrings { DbgStringCollection* _strings; }; -// ----- CHeapString ----------------------------------------------------------- - -class CHeapString : public CHeapObj { - public: - CHeapString(const char* str) : _string(os::strdup(str)) {} - ~CHeapString() { - os::free((void*)_string); - _string = nullptr; - } - const char* string() const { return _string; } - - private: - const char* _string; -}; - -// ----- AsmRemarkCollection --------------------------------------------------- - -class AsmRemarkCollection : public CHeapObj { - public: - AsmRemarkCollection() : _ref_cnt(1), _remarks(nullptr), _next(nullptr) {} - ~AsmRemarkCollection() { - assert(is_empty(), "Must 'clear()' before deleting!"); - assert(_ref_cnt == 0, "No uses must remain when deleting!"); - } - AsmRemarkCollection* reuse() { - precond(_ref_cnt > 0); - return _ref_cnt++, this; - } - - const char* insert(uint offset, const char* remark); - const char* lookup(uint offset) const; - const char* next(uint offset) const; - - bool is_empty() const { return _remarks == nullptr; } - uint clear(); - - private: - struct Cell : CHeapString { - Cell(const char* remark, uint offset) : - CHeapString(remark), offset(offset), prev(nullptr), next(nullptr) {} - void push_back(Cell* cell) { - Cell* head = this; - Cell* tail = prev; - tail->next = cell; - cell->next = head; - cell->prev = tail; - prev = cell; - } - uint offset; - Cell* prev; - Cell* next; - }; - uint _ref_cnt; - Cell* _remarks; - // Using a 'mutable' iteration pointer to allow 'const' on lookup/next (that - // does not change the state of the list per se), supportig a simplistic - // iteration scheme. - mutable Cell* _next; -}; - -// ----- DbgStringCollection --------------------------------------------------- - -class DbgStringCollection : public CHeapObj { - public: - DbgStringCollection() : _ref_cnt(1), _strings(nullptr) {} - ~DbgStringCollection() { - assert(is_empty(), "Must 'clear()' before deleting!"); - assert(_ref_cnt == 0, "No uses must remain when deleting!"); - } - DbgStringCollection* reuse() { - precond(_ref_cnt > 0); - return _ref_cnt++, this; - } - - const char* insert(const char* str); - const char* lookup(const char* str) const; - - bool is_empty() const { return _strings == nullptr; } - uint clear(); - - private: - struct Cell : CHeapString { - Cell(const char* dbgstr) : - CHeapString(dbgstr), prev(nullptr), next(nullptr) {} - void push_back(Cell* cell) { - Cell* head = this; - Cell* tail = prev; - tail->next = cell; - cell->next = head; - cell->prev = tail; - prev = cell; - } - Cell* prev; - Cell* next; - }; - uint _ref_cnt; - Cell* _strings; -}; #endif // not PRODUCT From 412176865630890d48ad06ce2127f643f4e65e1c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 17 Apr 2025 22:30:04 +0000 Subject: [PATCH 032/103] Style --- src/hotspot/share/asm/codeBuffer.cpp | 40 ++++++++++++++-------------- src/hotspot/share/asm/codeBuffer.hpp | 3 --- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 9c75777752f8f..2aa77abc5f2e7 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -1083,24 +1083,24 @@ void CodeBuffer::print() { // ----- CHeapString ----------------------------------------------------------- class CHeapString : public CHeapObj { - public: - CHeapString(const char* str) : _string(os::strdup(str)) {} - ~CHeapString() { - os::free((void*)_string); - _string = nullptr; - } - const char* string() const { return _string; } - - private: - const char* _string; - }; - - // ----- AsmRemarkCollection --------------------------------------------------- - + public: + CHeapString(const char* str) : _string(os::strdup(str)) {} + ~CHeapString() { + os::free((void*)_string); + _string = nullptr; + } + const char* string() const { return _string; } + + private: + const char* _string; +}; + +// ----- AsmRemarkCollection --------------------------------------------------- + class AsmRemarkCollection : public CHeapObj { -public: + public: AsmRemarkCollection() : _ref_cnt(1), _remarks(nullptr), _next(nullptr) {} -~AsmRemarkCollection() { + ~AsmRemarkCollection() { assert(is_empty(), "Must 'clear()' before deleting!"); assert(_ref_cnt == 0, "No uses must remain when deleting!"); } @@ -1116,7 +1116,7 @@ class AsmRemarkCollection : public CHeapObj { bool is_empty() const { return _remarks == nullptr; } uint clear(); -private: + private: struct Cell : CHeapString { Cell(const char* remark, uint offset) : CHeapString(remark), offset(offset), prev(nullptr), next(nullptr) {} @@ -1143,9 +1143,9 @@ class AsmRemarkCollection : public CHeapObj { // ----- DbgStringCollection --------------------------------------------------- class DbgStringCollection : public CHeapObj { -public: + public: DbgStringCollection() : _ref_cnt(1), _strings(nullptr) {} -~DbgStringCollection() { + ~DbgStringCollection() { assert(is_empty(), "Must 'clear()' before deleting!"); assert(_ref_cnt == 0, "No uses must remain when deleting!"); } @@ -1160,7 +1160,7 @@ class DbgStringCollection : public CHeapObj { bool is_empty() const { return _strings == nullptr; } uint clear(); -private: + private: struct Cell : CHeapString { Cell(const char* dbgstr) : CHeapString(dbgstr), prev(nullptr), next(nullptr) {} diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index b6a46e20f5898..025aa641d2c8b 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -28,7 +28,6 @@ #include "code/oopRecorder.hpp" #include "code/relocInfo.hpp" #include "compiler/compiler_globals.hpp" -#include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" #include "utilities/growableArray.hpp" @@ -340,8 +339,6 @@ class DbgStrings { private: DbgStringCollection* _strings; }; - - #endif // not PRODUCT From 27e41510c61ee2f46eaedd274df7030813da6e33 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 17 Apr 2025 22:37:07 +0000 Subject: [PATCH 033/103] Remove whitespace --- src/hotspot/share/code/nmethod.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 74b8bc7ef9952..974e7e171e13d 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1441,7 +1441,7 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h _gc_epoch = CodeCache::gc_epoch(); _method = nm->_method; _osr_link = nullptr; - + // Increment number of references to immutable data to share it between nmethods _immutable_data_size = nm->_immutable_data_size; if (_immutable_data_size > 0) { @@ -1456,17 +1456,17 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h _oops_do_mark_nmethods = nullptr; _oops_do_mark_link = nullptr; _compiled_ic_data = nullptr; - + if (nm->_osr_entry_point != nullptr) { _osr_entry_point = (nm->_osr_entry_point - (address) nm) + (address) this; } else { _osr_entry_point = nullptr; } - + _entry_offset = nm->_entry_offset; _verified_entry_offset = nm->_verified_entry_offset; _entry_bci = nm->_entry_bci; - + _skipped_instructions_size = nm->_skipped_instructions_size; _stub_offset = nm->_stub_offset; _exception_offset = nm->_exception_offset; @@ -1492,7 +1492,7 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h _compiler_type = nm->_compiler_type; _is_unloading_state = nm->_is_unloading_state; _state = not_installed; - + _has_unsafe_access = nm->_has_unsafe_access; _has_method_handle_invokes = nm->_has_method_handle_invokes; _has_wide_vectors = nm->_has_wide_vectors; @@ -1501,7 +1501,7 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h _has_flushed_dependencies = nm->_has_flushed_dependencies; _is_unlinked = nm->_is_unlinked; _load_reported = nm->_load_reported; - + _deoptimization_status = nm->_deoptimization_status; if (nm->_pc_desc_container != nullptr) { From 61ed0558ac7b818c584c20ca1b13d2c6a4fe1ff7 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 21 Apr 2025 20:58:20 +0000 Subject: [PATCH 034/103] Use methodHandle for VM_Operation so pointer is not stale --- src/hotspot/share/ci/ciEnv.cpp | 3 ++- src/hotspot/share/prims/whitebox.cpp | 7 +------ src/hotspot/share/runtime/vmOperations.cpp | 7 +++++-- src/hotspot/share/runtime/vmOperations.hpp | 8 ++++---- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index f26764333b907..6eb92de1ea148 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1135,7 +1135,8 @@ void ciEnv::register_method(ciMethod* target, // safepoints are allowed again if (StressNMethodRelocation) { - VM_RelocateNMethod relocate(nm, CodeBlobType::MethodNonProfiled); + methodHandle mh(Thread::current(), nm->method()); + VM_RelocateNMethod relocate(&mh, CodeBlobType::MethodNonProfiled); VMThread::execute(&relocate); } } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 5d8b182c5f77e..801926f19eecc 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1629,12 +1629,7 @@ WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION(env); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - nmethod* code = mh->code(); - if (code == nullptr) { - return; - } - - VM_RelocateNMethod relocate(code, static_cast(blob_type)); + VM_RelocateNMethod relocate(&mh, static_cast(blob_type)); VMThread::execute(&relocate); WB_END diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index b8cfedd0418e0..6c533cf4ee602 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -103,8 +103,11 @@ void VM_ClearICs::doit() { void VM_RelocateNMethod::doit() { MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); - if (_nm != nullptr && _nm->is_relocatable()) { - _nm_copy = _nm->relocate(_code_blob_type); + if (_mh != nullptr) { + nmethod* nm = (*_mh)()->code(); + if (nm != nullptr && nm->is_relocatable()) { + _nm_copy = nm->relocate(_code_blob_type); + } } } diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index 8b931cdde07e6..de6c9f8db0289 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -84,13 +84,13 @@ class VM_ClearICs: public VM_Operation { class VM_RelocateNMethod: public VM_Operation { private: - nmethod* _nm; + methodHandle* _mh; nmethod* _nm_copy; CodeBlobType _code_blob_type; public: - VM_RelocateNMethod(nmethod* nm, CodeBlobType code_blob_type) - : _nm(nm), _nm_copy(nullptr), _code_blob_type(code_blob_type) - {} + VM_RelocateNMethod(methodHandle* mh, CodeBlobType code_blob_type) + : _mh(mh), _nm_copy(nullptr), _code_blob_type(code_blob_type) { + } void doit(); VMOp_Type type() const { return VMOp_RelocateNMethod; } nmethod* getRelocatedNMethod() { return _nm_copy; } From 0d4d31fcda46121c03ab72aa1bfc94e611d343e4 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 21 Apr 2025 22:47:53 +0000 Subject: [PATCH 035/103] Hold Compile_lock --- src/hotspot/share/runtime/vmOperations.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index de6c9f8db0289..5523e6c74b62c 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -89,7 +89,12 @@ class VM_RelocateNMethod: public VM_Operation { CodeBlobType _code_blob_type; public: VM_RelocateNMethod(methodHandle* mh, CodeBlobType code_blob_type) - : _mh(mh), _nm_copy(nullptr), _code_blob_type(code_blob_type) { + : _mh(mh), _nm_copy(nullptr), _code_blob_type(code_blob_type) + { + Compile_lock->lock(); + } + ~VM_RelocateNMethod() { + Compile_lock->unlock(); } void doit(); VMOp_Type type() const { return VMOp_RelocateNMethod; } From 5552a8603d5da273b2db551ab8500d27611225eb Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 21 Apr 2025 23:07:01 +0000 Subject: [PATCH 036/103] Add null check in StressNMethodRelocation --- src/hotspot/share/ci/ciEnv.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 6eb92de1ea148..4283a166d691e 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1135,9 +1135,11 @@ void ciEnv::register_method(ciMethod* target, // safepoints are allowed again if (StressNMethodRelocation) { - methodHandle mh(Thread::current(), nm->method()); - VM_RelocateNMethod relocate(&mh, CodeBlobType::MethodNonProfiled); - VMThread::execute(&relocate); + if (nm != nullptr) { + methodHandle mh(Thread::current(), nm->method()); + VM_RelocateNMethod relocate(&mh, CodeBlobType::MethodNonProfiled); + VMThread::execute(&relocate); + } } } From 1c6db6c685e4f1b9d7e085a4c93742d4acf6b48c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 24 Apr 2025 19:02:45 +0000 Subject: [PATCH 037/103] Fix branch range check --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 11 ++++++++--- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index c91a136e7d558..2e02b833fb197 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -925,14 +925,19 @@ class Assembler : public AbstractAssembler { #undef INSN + // The maximum range of a branch is fixed for the AArch64 + // architecture. Max branch range is the largest value + // that will fit in the instruction + static const uint64_t max_branch_range = 128 * M; + // The maximum range of a branch is fixed for the AArch64 // architecture. In debug mode we shrink it in order to test // trampolines, but not so small that branches in the interpreter // are out of range. - static const uint64_t branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M); + static const uint64_t branch_range = NOT_DEBUG(max_branch_range) DEBUG_ONLY(2 * M); - static bool reachable_from_branch_at(address branch, address target) { - return uabs(target - branch) < branch_range; + static bool reachable_from_branch_at(address branch, address target, bool use_max=false) { + return uabs(target - branch) < (use_max ? max_branch_range : branch_range); } // Unconditional branch (immediate) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 2a20634659ed7..31542916146d2 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -81,7 +81,9 @@ void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { NativeCall* call = nativeCall_at(addr()); - if (!Assembler::reachable_from_branch_at(addr(), x)) { + if (!Assembler::reachable_from_branch_at(addr(), x, true)) { + address trampoline = call->get_trampoline(); + assert(trampoline != nullptr, "branch is too large with no available trampoline"); x = call->get_trampoline(); } call->set_destination(x); From 027f5245a6829e79bd8624c1cca542c4c24ace5c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 25 Apr 2025 20:32:44 +0000 Subject: [PATCH 038/103] Move post init and remove no entrant check --- src/hotspot/share/code/nmethod.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 974e7e171e13d..f589dcd6b98af 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1518,6 +1518,8 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h // - Stub code // - OOP table memcpy(consts_begin(), nm->consts_begin(), nm->data_end() - nm->consts_begin()); + + post_init(); } nmethod* nmethod::relocate(CodeBlobType code_blob_type) { @@ -1563,8 +1565,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); - nm_copy->post_init(); - // Update corresponding Java method to point to this nmethod if (nm_copy->method() != nullptr && nm_copy->method()->code() == this && nm_copy->make_in_use()) { methodHandle mh(Thread::current(), nm_copy->method()); @@ -1576,10 +1576,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } bool nmethod::is_relocatable() { - if (is_not_entrant()) { - return false; - } - if (is_marked_for_deoptimization()) { return false; } From bd143f55949e2abd5aff54dbc466e872082241e4 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 28 Apr 2025 16:41:03 +0000 Subject: [PATCH 039/103] Relocate without safepoint --- src/hotspot/share/ci/ciEnv.cpp | 4 +--- src/hotspot/share/code/codeBehaviours.cpp | 3 ++- src/hotspot/share/code/nmethod.cpp | 15 +++++++++++---- src/hotspot/share/code/relocInfo.cpp | 9 ++++----- src/hotspot/share/prims/whitebox.cpp | 6 ++++-- src/hotspot/share/runtime/vmOperation.hpp | 1 - src/hotspot/share/runtime/vmOperations.cpp | 11 ----------- src/hotspot/share/runtime/vmOperations.hpp | 19 ------------------- 8 files changed, 22 insertions(+), 46 deletions(-) diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 4283a166d691e..f508cddb075ca 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1136,9 +1136,7 @@ void ciEnv::register_method(ciMethod* target, if (StressNMethodRelocation) { if (nm != nullptr) { - methodHandle mh(Thread::current(), nm->method()); - VM_RelocateNMethod relocate(&mh, CodeBlobType::MethodNonProfiled); - VMThread::execute(&relocate); + nm = nm->relocate(CodeBlobType::MethodNonProfiled); } } } diff --git a/src/hotspot/share/code/codeBehaviours.cpp b/src/hotspot/share/code/codeBehaviours.cpp index 1f9eb0e29141d..99e7f19ff9ba7 100644 --- a/src/hotspot/share/code/codeBehaviours.cpp +++ b/src/hotspot/share/code/codeBehaviours.cpp @@ -23,6 +23,7 @@ */ #include "code/codeBehaviours.hpp" +#include "code/nmethod.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" @@ -41,5 +42,5 @@ void DefaultICProtectionBehaviour::unlock(nmethod* method) { } bool DefaultICProtectionBehaviour::is_safe(nmethod* method) { - return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self(); + return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self() || method->is_not_installed(); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index f589dcd6b98af..1204ee6e1128f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -771,7 +771,7 @@ Method* nmethod::attached_method_before_pc(address pc) { } void nmethod::clear_inline_caches() { - assert(SafepointSynchronize::is_at_safepoint(), "clearing of IC's only allowed at safepoint"); + assert(SafepointSynchronize::is_at_safepoint() || is_not_installed(), "clearing of IC's only allowed at safepoint"); RelocIterator iter(this); while (iter.next()) { iter.reloc()->clear_inline_cache(); @@ -1523,9 +1523,16 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h } nmethod* nmethod::relocate(CodeBlobType code_blob_type) { - assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); - assert_lock_strong(CodeCache_lock); - assert_lock_strong(NMethodState_lock); + if (!is_relocatable()) { + return nullptr; + } + + // Check if memory should be freed before allocation + CodeCache::gc_on_allocation(); + + MutexLocker ml(Compile_lock); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); run_nmethod_entry_barrier(); nmethod* nm_copy = new (size(), code_blob_type) nmethod(this); diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index d695bb596d860..a101d303976ea 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -372,12 +372,11 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer // If the original call is to an address in the src CodeBuffer (such as a stub call) // the updated call should be to the corresponding address in dest CodeBuffer int offset = callee - orig_addr; - address new_addr = addr() + offset; - pd_set_call_destination(new_addr); - } else { - // Reassert the callee address, this time in the new copy of the code. - pd_set_call_destination(callee); + callee = addr() + offset; } + + // Reassert the callee address, this time in the new copy of the code. + pd_set_call_destination(callee); } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 801926f19eecc..248b73f97e1a5 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1629,8 +1629,10 @@ WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION(env); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - VM_RelocateNMethod relocate(&mh, static_cast(blob_type)); - VMThread::execute(&relocate); + nmethod* code = mh->code(); + if (code != nullptr) { + code->relocate(static_cast(blob_type)); + } WB_END CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index 3f9e4b7d8107a..50d859444858d 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -41,7 +41,6 @@ template(PrintThreads) \ template(FindDeadlocks) \ template(ClearICs) \ - template(RelocateNMethod) \ template(ForceSafepoint) \ template(DeoptimizeFrame) \ template(DeoptimizeAll) \ diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index 6c533cf4ee602..da833150d746e 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -100,17 +100,6 @@ void VM_ClearICs::doit() { } } -void VM_RelocateNMethod::doit() { - MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); - MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); - if (_mh != nullptr) { - nmethod* nm = (*_mh)()->code(); - if (nm != nullptr && nm->is_relocatable()) { - _nm_copy = nm->relocate(_code_blob_type); - } - } -} - void VM_CleanClassLoaderDataMetaspaces::doit() { ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces(); } diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index 5523e6c74b62c..de4c7738f31a7 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -82,25 +82,6 @@ class VM_ClearICs: public VM_Operation { VMOp_Type type() const { return VMOp_ClearICs; } }; -class VM_RelocateNMethod: public VM_Operation { - private: - methodHandle* _mh; - nmethod* _nm_copy; - CodeBlobType _code_blob_type; - public: - VM_RelocateNMethod(methodHandle* mh, CodeBlobType code_blob_type) - : _mh(mh), _nm_copy(nullptr), _code_blob_type(code_blob_type) - { - Compile_lock->lock(); - } - ~VM_RelocateNMethod() { - Compile_lock->unlock(); - } - void doit(); - VMOp_Type type() const { return VMOp_RelocateNMethod; } - nmethod* getRelocatedNMethod() { return _nm_copy; } - }; - // Base class for invoking parts of a gtest in a safepoint. // Derived classes provide the doit method. // Typically also need to transition the gtest thread from native to VM. From 077369b5118fc71b71ee480f617a832fce3be9fa Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 28 Apr 2025 19:39:40 +0000 Subject: [PATCH 040/103] Add additional is_relocatable checks --- src/hotspot/share/code/nmethod.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 1204ee6e1128f..d8be869a4ff86 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1599,6 +1599,17 @@ bool nmethod::is_relocatable() { return false; } + if (!is_in_use()) { + return false; + } + + { + CompiledICLocker ic_locker(this); + if (has_evol_metadata()) { + return false; + } + } + return true; } From c78a811566e66ec113cb5ad1160243d218e9411f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 1 May 2025 18:10:10 +0000 Subject: [PATCH 041/103] Remove max branch range patch --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 9 ++------- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 2e02b833fb197..b3509701a5305 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -925,19 +925,14 @@ class Assembler : public AbstractAssembler { #undef INSN - // The maximum range of a branch is fixed for the AArch64 - // architecture. Max branch range is the largest value - // that will fit in the instruction - static const uint64_t max_branch_range = 128 * M; - // The maximum range of a branch is fixed for the AArch64 // architecture. In debug mode we shrink it in order to test // trampolines, but not so small that branches in the interpreter // are out of range. static const uint64_t branch_range = NOT_DEBUG(max_branch_range) DEBUG_ONLY(2 * M); - static bool reachable_from_branch_at(address branch, address target, bool use_max=false) { - return uabs(target - branch) < (use_max ? max_branch_range : branch_range); + static bool reachable_from_branch_at(address branch, address target) { + return uabs(target - branch) < branch_range; } // Unconditional branch (immediate) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 31542916146d2..1a08e6545f69b 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -81,7 +81,7 @@ void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { NativeCall* call = nativeCall_at(addr()); - if (!Assembler::reachable_from_branch_at(addr(), x, true)) { + if (!Assembler::reachable_from_branch_at(addr(), x)) { address trampoline = call->get_trampoline(); assert(trampoline != nullptr, "branch is too large with no available trampoline"); x = call->get_trampoline(); From 97b9d7688bf9fc9c97645b99b3d2075579674ec6 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 6 May 2025 17:49:34 +0000 Subject: [PATCH 042/103] Remove set call dest assert --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 1a08e6545f69b..e37a42f0ee847 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -83,8 +83,9 @@ void Relocation::pd_set_call_destination(address x) { NativeCall* call = nativeCall_at(addr()); if (!Assembler::reachable_from_branch_at(addr(), x)) { address trampoline = call->get_trampoline(); - assert(trampoline != nullptr, "branch is too large with no available trampoline"); - x = call->get_trampoline(); + if (trampoline != nullptr) { + x = call->get_trampoline(); + } } call->set_destination(x); } else { From e18be51e36f24f5f8aa2309222cc1fb6706cc8f7 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 6 May 2025 18:01:57 +0000 Subject: [PATCH 043/103] Fix branch_range revert --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 07bce85325c2d..5c02e30963eaa 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -929,7 +929,7 @@ class Assembler : public AbstractAssembler { // architecture. In debug mode we shrink it in order to test // trampolines, but not so small that branches in the interpreter // are out of range. - static const uint64_t branch_range = NOT_DEBUG(max_branch_range) DEBUG_ONLY(2 * M); + static const uint64_t branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M); static bool reachable_from_branch_at(address branch, address target) { return uabs(target - branch) < branch_range; From 10b58dfd66df5fea7e089006dedd5e851c440886 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 6 May 2025 18:05:11 +0000 Subject: [PATCH 044/103] Remove StressNMethodRelocation --- src/hotspot/share/ci/ciEnv.cpp | 25 +++++++------------ .../share/compiler/compiler_globals.hpp | 3 --- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index ffc5c2b50625f..3991773d86fa3 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1121,24 +1121,17 @@ void ciEnv::register_method(ciMethod* target, } } - { - NoSafepointVerifier nsv; - if (nm != nullptr) { - // Compilation succeeded, post what we know about it - nm->post_compiled_method(task()); - task()->set_num_inlined_bytecodes(num_inlined_bytecodes()); - } else { - // The CodeCache is full. - record_failure("code cache is full"); - } + NoSafepointVerifier nsv; + if (nm != nullptr) { + // Compilation succeeded, post what we know about it + nm->post_compiled_method(task()); + task()->set_num_inlined_bytecodes(num_inlined_bytecodes()); + } else { + // The CodeCache is full. + record_failure("code cache is full"); } - // safepoints are allowed again - if (StressNMethodRelocation) { - if (nm != nullptr) { - nm = nm->relocate(CodeBlobType::MethodNonProfiled); - } - } + // safepoints are allowed again } // ------------------------------------------------------------------ diff --git a/src/hotspot/share/compiler/compiler_globals.hpp b/src/hotspot/share/compiler/compiler_globals.hpp index 36c9775b27c79..a811cd8b3bae6 100644 --- a/src/hotspot/share/compiler/compiler_globals.hpp +++ b/src/hotspot/share/compiler/compiler_globals.hpp @@ -137,9 +137,6 @@ "and the value of the per-method flag.") \ range(0.0, DBL_MAX) \ \ - product(bool, StressNMethodRelocation, false, \ - "Stress relocation nmethods") \ - \ product(intx, Tier0InvokeNotifyFreqLog, 7, \ "Interpreter (tier 0) invocation notification frequency") \ range(0, 30) \ From a1a2bdaa537c2c9958cc136cd20e8acdefb213e9 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 6 May 2025 18:39:32 +0000 Subject: [PATCH 045/103] Exclude JVMCI nmethods --- src/hotspot/share/code/nmethod.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 3761cca9037e3..d574d94af64ba 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1579,6 +1579,10 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } bool nmethod::is_relocatable() { + if (is_compiled_by_jvmci()) { + return false; + } + if (is_marked_for_deoptimization()) { return false; } From 2610a0ed901e2cdaeba02b41db4b82d21dc1d27a Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 6 May 2025 19:35:35 +0000 Subject: [PATCH 046/103] Only hold NMethodState_lock when needed --- src/hotspot/share/code/nmethod.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index d574d94af64ba..bf7b33e5aebd7 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1526,9 +1526,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { // Check if memory should be freed before allocation CodeCache::gc_on_allocation(); - MutexLocker ml(Compile_lock); + MutexLocker ml_Compile_lock(Compile_lock); MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); - MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); run_nmethod_entry_barrier(); nmethod* nm_copy = new (size(), code_blob_type) nmethod(this); @@ -1569,6 +1568,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); // Update corresponding Java method to point to this nmethod + MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm_copy->method() != nullptr && nm_copy->method()->code() == this && nm_copy->make_in_use()) { methodHandle mh(Thread::current(), nm_copy->method()); nm_copy->method()->set_code(mh, nm_copy); From 21a86e67e5ff0f0af034b7a24d099cd51e03a7d7 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 7 May 2025 23:27:59 +0000 Subject: [PATCH 047/103] Add relocate_nmethod_mirror --- src/hotspot/share/jvmci/jvmciRuntime.cpp | 14 ++++++++++++++ src/hotspot/share/jvmci/jvmciRuntime.hpp | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 6f1fa52576e41..f95847b683430 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -844,6 +844,20 @@ void JVMCINMethodData::invalidate_nmethod_mirror(nmethod* nm) { } } +void JVMCINMethodData::relocate_nmethod_mirror(nmethod* nm) { + oop nmethod_mirror = get_nmethod_mirror(nm, /* phantom_ref */ false); + if (nmethod_mirror == nullptr) { + return; + } + + JVMCIEnv* jvmciEnv = nullptr; + HotSpotJVMCI::InstalledCode::set_address(jvmciEnv, nmethod_mirror, (jlong)(nm)); + HotSpotJVMCI::InstalledCode::set_entryPoint(jvmciEnv, nmethod_mirror, (jlong)(nm->entry_point())); + HotSpotJVMCI::HotSpotInstalledCode::set_size(jvmciEnv, nmethod_mirror, (jlong)(nm->size())); + HotSpotJVMCI::HotSpotInstalledCode::set_codeStart(jvmciEnv, nmethod_mirror, (jlong)(nm->code_begin())); + HotSpotJVMCI::HotSpotInstalledCode::set_codeSize(jvmciEnv, nmethod_mirror, (jlong)(nm->code_size())); +} + // Handles to objects in the Hotspot heap. static OopStorage* object_handles() { return Universe::vm_global(); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index 884d11f792e2a..620339efef81e 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -121,6 +121,9 @@ class JVMCINMethodData : public ResourceObj { // is dead, the HotSpotNmethod.entryPoint field is also cleared. void invalidate_nmethod_mirror(nmethod* nm); + // Updates the HotSpotNmethod fields after nmethod relocation + void relocate_nmethod_mirror(nmethod* nm); + // Gets the mirror from nm's oops table. oop get_nmethod_mirror(nmethod* nm, bool phantom_ref); From c6361196cba1e3c3e1f8566f3deccaf6f28ac0b0 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 7 May 2025 23:30:16 +0000 Subject: [PATCH 048/103] Unexclude JVMCI methods --- src/hotspot/share/code/nmethod.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index bf7b33e5aebd7..5771873f0b87c 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1579,10 +1579,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } bool nmethod::is_relocatable() { - if (is_compiled_by_jvmci()) { - return false; - } - if (is_marked_for_deoptimization()) { return false; } From a1dfc477fb0d34732e8845a04cf2fc111afa8ffd Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 8 May 2025 17:18:41 +0000 Subject: [PATCH 049/103] Fix JVMCI nmethod data --- src/hotspot/share/code/nmethod.cpp | 8 ++++++++ src/hotspot/share/jvmci/jvmciRuntime.cpp | 4 ++++ src/hotspot/share/jvmci/jvmciRuntime.hpp | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5771873f0b87c..d89eefd271e4f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1572,6 +1572,14 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { if (nm_copy->method() != nullptr && nm_copy->method()->code() == this && nm_copy->make_in_use()) { methodHandle mh(Thread::current(), nm_copy->method()); nm_copy->method()->set_code(mh, nm_copy); + +#if INCLUDE_JVMCI + if (jvmci_nmethod_data() != nullptr) { + nm_copy->jvmci_nmethod_data()->relocate_nmethod_mirror(nm_copy); + jvmci_nmethod_data()->clear_nmethod_mirror_index(); + } +#endif + make_not_used(); } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index f95847b683430..c92c6e344fe99 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -844,6 +844,10 @@ void JVMCINMethodData::invalidate_nmethod_mirror(nmethod* nm) { } } +void JVMCINMethodData::clear_nmethod_mirror_index() { + _nmethod_mirror_index = -1; +} + void JVMCINMethodData::relocate_nmethod_mirror(nmethod* nm) { oop nmethod_mirror = get_nmethod_mirror(nm, /* phantom_ref */ false); if (nmethod_mirror == nullptr) { diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index 620339efef81e..b31e93ad311de 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -121,6 +121,11 @@ class JVMCINMethodData : public ResourceObj { // is dead, the HotSpotNmethod.entryPoint field is also cleared. void invalidate_nmethod_mirror(nmethod* nm); + // Used during nmethod relocation to clear the mirror index of the original nmethod. + // This prevents the original, non-entrant nmethod from interacting with the + // HotSpotNmethod mirror after relocation. + void clear_nmethod_mirror_index(); + // Updates the HotSpotNmethod fields after nmethod relocation void relocate_nmethod_mirror(nmethod* nm); From c18eac976fd138761fbc47296642210724ef991f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 8 May 2025 19:09:16 +0000 Subject: [PATCH 050/103] Add nullptr check to relocate --- src/hotspot/share/code/nmethod.cpp | 4 ++++ src/hotspot/share/code/nmethod.hpp | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index d89eefd271e4f..2467b2e7f943f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1532,6 +1532,10 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { run_nmethod_entry_barrier(); nmethod* nm_copy = new (size(), code_blob_type) nmethod(this); + if (nm == nullptr) { + return nullptr; + } + // Fix relocation RelocIterator iter(nm_copy); CodeBuffer src(this); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index d9ac41cde2925..be1d0523db08d 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -496,8 +496,9 @@ class nmethod : public CodeBlob { ); // Relocate the nmethod to the code heap identified by code_blob_type. - // Returns nullptr if the code heap does not have enough space, otherwise - // the relocated nmethod. The original nmethod will be invalidated. + // Returns nullptr if the code heap does not have enough space or the + // nmethod is unrelocatable, otherwise the relocated nmethod. + // The original nmethod will be marked not entrant. nmethod* relocate(CodeBlobType code_blob_type); static nmethod* new_native_nmethod(const methodHandle& method, From 1581403db1fb61f16849f19605d63653404988cf Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 8 May 2025 19:11:39 +0000 Subject: [PATCH 051/103] Remove unnecessary include --- src/hotspot/share/runtime/vmOperations.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index de4c7738f31a7..baeea722dcef2 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_RUNTIME_VMOPERATIONS_HPP #define SHARE_RUNTIME_VMOPERATIONS_HPP -#include "code/codeBlob.hpp" #include "oops/oop.hpp" #include "runtime/javaThread.hpp" #include "runtime/vmOperation.hpp" From 9ca3563a0fe8e021a7a99107a4b675d2210a34b2 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 8 May 2025 19:14:02 +0000 Subject: [PATCH 052/103] Fix null check --- src/hotspot/share/code/nmethod.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 2467b2e7f943f..13c821a4227a7 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1532,7 +1532,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { run_nmethod_entry_barrier(); nmethod* nm_copy = new (size(), code_blob_type) nmethod(this); - if (nm == nullptr) { + if (nm_copy == nullptr) { return nullptr; } From 0813725e4bbe78809b6c81b8e17d1822b5c4295a Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 12 May 2025 21:37:38 +0000 Subject: [PATCH 053/103] Create nmethod relocation stress test --- src/hotspot/share/prims/whitebox.cpp | 21 +- .../whitebox/StressNMethodRelocation.java | 238 ++++++++++++++++++ test/lib/jdk/test/whitebox/WhiteBox.java | 1 + test/lib/jdk/test/whitebox/code/CodeBlob.java | 4 +- 4 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index f3fb0d093fccc..45dbc8d4e6695 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1557,19 +1557,21 @@ struct CodeBlobStub { name(os::strdup(blob->name())), size(blob->size()), blob_type(static_cast(WhiteBox::get_blob_type(blob))), - address((jlong) blob) { } + address((jlong) blob), + is_nmethod((jboolean) blob->is_nmethod()) { } ~CodeBlobStub() { os::free((void*) name); } const char* const name; const jint size; const jint blob_type; const jlong address; + const jboolean is_nmethod; }; static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBlobStub* cb) { ResourceMark rm; jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); CHECK_JNI_EXCEPTION_(env, nullptr); - jobjectArray result = env->NewObjectArray(4, clazz, nullptr); + jobjectArray result = env->NewObjectArray(5, clazz, nullptr); jstring name = env->NewStringUTF(cb->name); CHECK_JNI_EXCEPTION_(env, nullptr); @@ -1587,6 +1589,10 @@ static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBl CHECK_JNI_EXCEPTION_(env, nullptr); env->SetObjectArrayElement(result, 3, obj); + obj = booleanBox(thread, env, cb->is_nmethod); + CHECK_JNI_EXCEPTION_(env, nullptr); + env->SetObjectArrayElement(result, 4, obj); + return result; } @@ -1647,6 +1653,15 @@ WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint } WB_END +WB_ENTRY(void, WB_RelocateMemNMethodTo(JNIEnv* env, jobject o, jlong addr, jint blob_type)) + ResourceMark rm(THREAD); + CHECK_JNI_EXCEPTION(env); + nmethod* code = (nmethod*) addr; + if (code != nullptr) { + code->relocate(static_cast(blob_type)); + } +WB_END + CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled"); BufferBlob* blob; @@ -2894,6 +2909,8 @@ static JNINativeMethod methods[] = { (void*)&WB_GetNMethod }, {CC"relocateNMethodTo0", CC"(Ljava/lang/reflect/Executable;I)V", (void*)&WB_RelocateNMethodTo }, + {CC"relocateMemNMethodTo0", CC"(JI)V", + (void*)&WB_RelocateMemNMethodTo }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java new file mode 100644 index 0000000000000..17cb7cb897ffc --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test StressNMethodRelocation + * @summary Call and relocate methods concurrently + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache + * compiler.whitebox.StressNMethodRelocation + */ + +package compiler.whitebox; + +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.CodeBlob; +import jdk.test.whitebox.code.NMethod; + +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Random; + +public class StressNMethodRelocation { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final int C2_LEVEL = 4; + private static final int ACTIVE_METHODS = 1024; + + private static TestMethod[] methods; + private static byte[] num1; + private static byte[] num2; + + private static long DURATION = 60_000; + + public static void main(String[] args) throws Exception { + // Initialize defaults + initNums(); + + // Generate compiled code + methods = new TestMethod[ACTIVE_METHODS]; + generateCode(methods); + + // Create thread that runs compiled methods + RunMethods runMethods = new RunMethods(); + Thread runMethodsThread = new Thread(runMethods); + + // Create thread that relocates compiled methods + RelocateNMethods relocate = new RelocateNMethods(); + Thread relocateThread = new Thread(relocate); + + // Start theads + runMethodsThread.start(); + relocateThread.start(); + + // Wait for threads to finish + runMethodsThread.join(); + relocateThread.join(); + } + + private static byte[] genNum(Random random, int digitCount) { + byte[] num = new byte[digitCount]; + int d; + do { + d = random.nextInt(10); + } while (d == 0); + + num[0] = (byte)d; + for (int i = 1; i < digitCount; ++i) { + num[i] = (byte)random.nextInt(10); + } + return num; + } + + private static void initNums() { + final long seed = 8374592837465123L; + Random random = new Random(seed); + + final int digitCount = 40; + num1 = genNum(random, digitCount); + num2 = genNum(random, digitCount); + } + + private static void generateCode(TestMethod[] m) throws Exception { + byte[] result = new byte[num1.length + 1]; + + for (int i = 0; i < ACTIVE_METHODS; ++i) { + m[i] = new TestMethod(); + m[i].profile(num1, num2, result); + m[i].compileWithC2(); + } + } + + private static final class TestMethod { + private static final String CLASS_NAME = "A"; + private static final String METHOD_TO_COMPILE = "sum"; + private static final String JAVA_CODE = """ + public class A { + + public static void sum(byte[] n1, byte[] n2, byte[] out) { + final int digitCount = n1.length; + int carry = 0; + for (int i = digitCount - 1; i >= 0; --i) { + int sum = n1[i] + n2[i] + carry; + out[i] = (byte)(sum % 10); + carry = sum / 10; + } + if (carry != 0) { + for (int i = digitCount; i > 0; --i) { + out[i] = out[i - 1]; + } + out[0] = (byte)carry; + } + } + }"""; + + private static final byte[] BYTE_CODE; + + static { + BYTE_CODE = InMemoryJavaCompiler.compile(CLASS_NAME, JAVA_CODE); + } + + private final Method method; + + private static ClassLoader createClassLoaderFor() { + return new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (!name.equals(CLASS_NAME)) { + return super.loadClass(name); + } + + return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length); + } + }; + } + + public TestMethod() throws Exception { + var cl = createClassLoaderFor().loadClass(CLASS_NAME); + method = cl.getMethod(METHOD_TO_COMPILE, byte[].class, byte[].class, byte[].class); + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + public void profile(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + WHITE_BOX.markMethodProfiled(method); + } + + public void invoke(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + } + + public void compileWithC2() throws Exception { + WHITE_BOX.enqueueMethodForCompilation(method, C2_LEVEL); + while (WHITE_BOX.isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + if (WHITE_BOX.getMethodCompilationLevel(method) != C2_LEVEL) { + throw new IllegalStateException("Method " + method + " is not compiled by C2."); + } + } + } + + private static final class RelocateNMethods implements Runnable { + public RelocateNMethods() {} + + // Move nmethod back and forth between NonProfiled and Profiled code heaps + public void run() { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < DURATION) { + // Relocate NonProfiled to Profiled + CodeBlob[] nonProfiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodNonProfiled); + for (CodeBlob blob : nonProfiledBlobs) { + if (blob.isNMethod) { + WHITE_BOX.relocateMemNMethodTo0(blob.address, BlobType.MethodProfiled.id); + } + } + + // Relocate Profiled to NonProfiled + CodeBlob[] profiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodProfiled); + for (CodeBlob blob : nonProfiledBlobs) { + if (blob.isNMethod) { + WHITE_BOX.relocateMemNMethodTo0(blob.address, BlobType.MethodNonProfiled.id); + } + } + } + } + } + + private static final class RunMethods implements Runnable { + public RunMethods() {} + + public void run() { + try { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < DURATION) { + callMethods(); + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + + private void callMethods() throws Exception { + for (var m : methods) { + byte[] result = new byte[num1.length + 1]; + m.invoke(num1, num2, result); + } + } + } + +} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 892c80eb7ceab..7b0f267d78bf5 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -495,6 +495,7 @@ public void relocateNMethodTo(Executable method, int type) { Objects.requireNonNull(method); relocateNMethodTo0(method, type); } + public native void relocateMemNMethodTo0(long address, int type); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; diff --git a/test/lib/jdk/test/whitebox/code/CodeBlob.java b/test/lib/jdk/test/whitebox/code/CodeBlob.java index c6c23fdff0cb7..f4ba52ba9eb14 100644 --- a/test/lib/jdk/test/whitebox/code/CodeBlob.java +++ b/test/lib/jdk/test/whitebox/code/CodeBlob.java @@ -46,18 +46,20 @@ public static CodeBlob getCodeBlob(long addr) { return new CodeBlob(obj); } protected CodeBlob(Object[] obj) { - assert obj.length == 4; + assert obj.length == 5; name = (String) obj[0]; size = (Integer) obj[1]; int blob_type_index = (Integer) obj[2]; code_blob_type = BlobType.values()[blob_type_index]; assert code_blob_type.id == (Integer) obj[2]; address = (Long) obj[3]; + isNMethod = (Boolean) obj[4]; } public final String name; public final int size; public final BlobType code_blob_type; public final long address; + public final boolean isNMethod; @Override public String toString() { return "CodeBlob{" From e81296d4944f4c1b2367931a13557a63297889e3 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 22 May 2025 18:57:38 +0000 Subject: [PATCH 054/103] Exclude JVMCI methods --- src/hotspot/share/code/nmethod.cpp | 12 ++++-------- src/hotspot/share/jvmci/jvmciRuntime.cpp | 18 ------------------ src/hotspot/share/jvmci/jvmciRuntime.hpp | 8 -------- 3 files changed, 4 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 13c821a4227a7..4f8cf753a1370 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1576,14 +1576,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { if (nm_copy->method() != nullptr && nm_copy->method()->code() == this && nm_copy->make_in_use()) { methodHandle mh(Thread::current(), nm_copy->method()); nm_copy->method()->set_code(mh, nm_copy); - -#if INCLUDE_JVMCI - if (jvmci_nmethod_data() != nullptr) { - nm_copy->jvmci_nmethod_data()->relocate_nmethod_mirror(nm_copy); - jvmci_nmethod_data()->clear_nmethod_mirror_index(); - } -#endif - make_not_used(); } @@ -1591,6 +1583,10 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } bool nmethod::is_relocatable() { + if (is_compiled_by_jvmci()) { + return false; + } + if (is_marked_for_deoptimization()) { return false; } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c92c6e344fe99..6f1fa52576e41 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -844,24 +844,6 @@ void JVMCINMethodData::invalidate_nmethod_mirror(nmethod* nm) { } } -void JVMCINMethodData::clear_nmethod_mirror_index() { - _nmethod_mirror_index = -1; -} - -void JVMCINMethodData::relocate_nmethod_mirror(nmethod* nm) { - oop nmethod_mirror = get_nmethod_mirror(nm, /* phantom_ref */ false); - if (nmethod_mirror == nullptr) { - return; - } - - JVMCIEnv* jvmciEnv = nullptr; - HotSpotJVMCI::InstalledCode::set_address(jvmciEnv, nmethod_mirror, (jlong)(nm)); - HotSpotJVMCI::InstalledCode::set_entryPoint(jvmciEnv, nmethod_mirror, (jlong)(nm->entry_point())); - HotSpotJVMCI::HotSpotInstalledCode::set_size(jvmciEnv, nmethod_mirror, (jlong)(nm->size())); - HotSpotJVMCI::HotSpotInstalledCode::set_codeStart(jvmciEnv, nmethod_mirror, (jlong)(nm->code_begin())); - HotSpotJVMCI::HotSpotInstalledCode::set_codeSize(jvmciEnv, nmethod_mirror, (jlong)(nm->code_size())); -} - // Handles to objects in the Hotspot heap. static OopStorage* object_handles() { return Universe::vm_global(); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index b31e93ad311de..884d11f792e2a 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -121,14 +121,6 @@ class JVMCINMethodData : public ResourceObj { // is dead, the HotSpotNmethod.entryPoint field is also cleared. void invalidate_nmethod_mirror(nmethod* nm); - // Used during nmethod relocation to clear the mirror index of the original nmethod. - // This prevents the original, non-entrant nmethod from interacting with the - // HotSpotNmethod mirror after relocation. - void clear_nmethod_mirror_index(); - - // Updates the HotSpotNmethod fields after nmethod relocation - void relocate_nmethod_mirror(nmethod* nm); - // Gets the mirror from nm's oops table. oop get_nmethod_mirror(nmethod* nm, bool phantom_ref); From 398a4dc424a2f290336c48bb3b618f49c28fd46e Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 22 May 2025 19:28:50 +0000 Subject: [PATCH 055/103] Update tests --- src/hotspot/share/prims/whitebox.cpp | 11 +++++------ .../whitebox/DeoptimizeRelocatedNMethod.java | 2 +- .../jtreg/compiler/whitebox/RelocateNMethod.java | 12 ++++++------ .../whitebox/RelocateNMethodMultiplePaths.java | 2 +- .../compiler/whitebox/StressNMethodRelocation.java | 4 ++-- test/lib/jdk/test/whitebox/WhiteBox.java | 8 ++++---- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 45dbc8d4e6695..c3c94b6bbf2de 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1642,7 +1642,7 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo return result; WB_END -WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint blob_type)) +WB_ENTRY(void, WB_RelocateNMethodFromMethod(JNIEnv* env, jobject o, jobject method, jint blob_type)) ResourceMark rm(THREAD); jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION(env); @@ -1653,7 +1653,7 @@ WB_ENTRY(void, WB_RelocateNMethodTo(JNIEnv* env, jobject o, jobject method, jint } WB_END -WB_ENTRY(void, WB_RelocateMemNMethodTo(JNIEnv* env, jobject o, jlong addr, jint blob_type)) +WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, jint blob_type)) ResourceMark rm(THREAD); CHECK_JNI_EXCEPTION(env); nmethod* code = (nmethod*) addr; @@ -2907,10 +2907,9 @@ static JNINativeMethod methods[] = { {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, - {CC"relocateNMethodTo0", CC"(Ljava/lang/reflect/Executable;I)V", - (void*)&WB_RelocateNMethodTo }, - {CC"relocateMemNMethodTo0", CC"(JI)V", - (void*)&WB_RelocateMemNMethodTo }, + {CC"relocateNMethodFromMethod0", CC"(Ljava/lang/reflect/Executable;I)V", + (void*)&WB_RelocateNMethodFromMethod }, + {CC"relocateNMethodFromAddr0", CC"(JI)V", (void*)&WB_RelocateNMethodFromAddr }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java index 3bd581485867b..340685e36849e 100644 --- a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java @@ -108,7 +108,7 @@ public static void main(String [] args) throws Exception { NMethod origNmethod = NMethod.get(method, false); // Relocate nmethod and mark old for cleanup - WHITE_BOX.relocateNMethodTo(method, BlobType.MethodProfiled.id); + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodProfiled.id); // Trigger GC to clean up old nmethod WHITE_BOX.fullGC(); diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java index 258a121d5bd4f..77a4f41f4937b 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -25,7 +25,7 @@ /* * @test id=Serial * @bug 8316694 - * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @summary test that nmethod::relocate() correctly creates a new nmethod * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @@ -39,7 +39,7 @@ /* * @test id=Parallel * @bug 8316694 - * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @summary test that nmethod::relocate() correctly creates a new nmethod * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @@ -53,7 +53,7 @@ /* * @test id=G1 * @bug 8316694 - * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @summary test that nmethod::relocate() correctly creates a new nmethod * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @@ -67,7 +67,7 @@ /* * @test id=Shenandoah * @bug 8316694 - * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @summary test that nmethod::relocate() correctly creates a new nmethod * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @@ -81,7 +81,7 @@ /* * @test id=ZGC * @bug 8316694 - * @summary test that WB::relocateNMethodTo() correctly creates a new nmethod + * @summary test that nmethod::relocate() correctly creates a new nmethod * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @@ -122,7 +122,7 @@ protected void test() throws Exception { checkCompiled(); NMethod origNmethod = NMethod.get(method, false); - WHITE_BOX.relocateNMethodTo(method, BlobType.MethodProfiled.id); + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodProfiled.id); WHITE_BOX.fullGC(); diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java index 3a7971b9fbe22..499f56022135c 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java @@ -195,7 +195,7 @@ public static void main(String [] args) throws Exception { NMethod origNmethod = NMethod.get(method, false); // Relocate nmethod and mark old for cleanup - WHITE_BOX.relocateNMethodTo(method, BlobType.MethodNonProfiled.id); + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodNonProfiled.id); // Trigger GC to clean up old nmethod WHITE_BOX.fullGC(); diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java index 17cb7cb897ffc..b70e85a56ba37 100644 --- a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -198,7 +198,7 @@ public void run() { CodeBlob[] nonProfiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodNonProfiled); for (CodeBlob blob : nonProfiledBlobs) { if (blob.isNMethod) { - WHITE_BOX.relocateMemNMethodTo0(blob.address, BlobType.MethodProfiled.id); + WHITE_BOX.relocateNMethodFromAddr0(blob.address, BlobType.MethodProfiled.id); } } @@ -206,7 +206,7 @@ public void run() { CodeBlob[] profiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodProfiled); for (CodeBlob blob : nonProfiledBlobs) { if (blob.isNMethod) { - WHITE_BOX.relocateMemNMethodTo0(blob.address, BlobType.MethodNonProfiled.id); + WHITE_BOX.relocateNMethodFromAddr0(blob.address, BlobType.MethodNonProfiled.id); } } } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 7b0f267d78bf5..0a49d55c94d5a 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -490,12 +490,12 @@ public Object[] getNMethod(Executable method, boolean isOsr) { Objects.requireNonNull(method); return getNMethod0(method, isOsr); } - private native void relocateNMethodTo0(Executable method, int type); - public void relocateNMethodTo(Executable method, int type) { + private native void relocateNMethodFromMethod0(Executable method, int type); + public void relocateNMethodFromMethod(Executable method, int type) { Objects.requireNonNull(method); - relocateNMethodTo0(method, type); + relocateNMethodFromMethod0(method, type); } - public native void relocateMemNMethodTo0(long address, int type); + public native void relocateNMethodFromAddr0(long address, int type); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; From edefbf6210948374213d7898e75a66e3c3885a31 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 27 May 2025 17:05:48 +0000 Subject: [PATCH 056/103] Only exclude JVMCI methods that contain a mirror --- src/hotspot/share/code/nmethod.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 4f8cf753a1370..2175fe913b468 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1583,9 +1583,13 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } bool nmethod::is_relocatable() { - if (is_compiled_by_jvmci()) { - return false; +#if INCLUDE_JVMCI + if (jvmci_nmethod_data() != nullptr) { + if (jvmci_nmethod_data()->get_nmethod_mirror(this, false) != nullptr) { + return false; + } } +#endif if (is_marked_for_deoptimization()) { return false; From a0134a8702d31ab5e27cfa13e2b5a16627c188b6 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 27 May 2025 21:38:09 +0000 Subject: [PATCH 057/103] Add JVMCINMethodData::has_mirror() --- src/hotspot/share/code/nmethod.cpp | 4 +--- src/hotspot/share/jvmci/jvmciRuntime.hpp | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 2175fe913b468..371546093f9d9 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1584,10 +1584,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { bool nmethod::is_relocatable() { #if INCLUDE_JVMCI - if (jvmci_nmethod_data() != nullptr) { - if (jvmci_nmethod_data()->get_nmethod_mirror(this, false) != nullptr) { + if (jvmci_nmethod_data() != nullptr && jvmci_nmethod_data()->has_mirror()) { return false; - } } #endif diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index 884d11f792e2a..0efc957aa88cd 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -117,6 +117,11 @@ class JVMCINMethodData : public ResourceObj { // Gets the JVMCI name of the nmethod (which may be null). const char* name() { return _has_name ? (char*)(((address) this) + sizeof(JVMCINMethodData)) : nullptr; } + // Returns true if this nmethod has a mirror + bool has_mirror() const { + return _nmethod_mirror_index != -1; + } + // Clears the HotSpotNmethod.address field in the mirror. If nm // is dead, the HotSpotNmethod.entryPoint field is also cleared. void invalidate_nmethod_mirror(nmethod* nm); From 54aedbe46951b3741096aecd9c4caf0d70646d57 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 29 May 2025 19:34:42 +0000 Subject: [PATCH 058/103] Update assert note in nmethod::clear_inline_caches --- src/hotspot/share/code/nmethod.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 371546093f9d9..2fed1335066aa 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -767,7 +767,7 @@ Method* nmethod::attached_method_before_pc(address pc) { } void nmethod::clear_inline_caches() { - assert(SafepointSynchronize::is_at_safepoint() || is_not_installed(), "clearing of IC's only allowed at safepoint"); + assert(SafepointSynchronize::is_at_safepoint() || is_not_installed(), "clearing of IC's only allowed at safepoint or when not installed"); RelocIterator iter(this); while (iter.next()) { iter.reloc()->clear_inline_cache(); From 4e749188b17186217457852645acf37a8293f220 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 29 May 2025 19:38:57 +0000 Subject: [PATCH 059/103] Fix incorrect destination set if no trampoline available --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index e37a42f0ee847..724065557c202 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -83,9 +83,8 @@ void Relocation::pd_set_call_destination(address x) { NativeCall* call = nativeCall_at(addr()); if (!Assembler::reachable_from_branch_at(addr(), x)) { address trampoline = call->get_trampoline(); - if (trampoline != nullptr) { - x = call->get_trampoline(); - } + guarantee(trampoline != nullptr, "Must have trampoline for far call"); + x = trampoline; } call->set_destination(x); } else { From 37f2fbc6fab1b84981998d72b14a1f5aa3c30a71 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 29 May 2025 20:17:55 +0000 Subject: [PATCH 060/103] Add type for immutable_data_references --- src/hotspot/share/code/nmethod.cpp | 16 ++++++++-------- src/hotspot/share/code/nmethod.hpp | 8 +++++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 2fed1335066aa..7cc856de042c8 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1157,14 +1157,14 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, int immutable_data_size = adjust_pcs_size(debug_info->pcs_size()) - + align_up((int)dependencies->size_in_bytes(), oopSize) - + align_up(handler_table->size_in_bytes() , oopSize) - + align_up(nul_chk_table->size_in_bytes() , oopSize) + + align_up((int)dependencies->size_in_bytes() , oopSize) + + align_up(handler_table->size_in_bytes() , oopSize) + + align_up(nul_chk_table->size_in_bytes() , oopSize) #if INCLUDE_JVMCI - + align_up(speculations_len , oopSize) + + align_up(speculations_len , oopSize) #endif - + align_up(debug_info->data_size() , oopSize) - + align_up((int)sizeof(int) , oopSize); + + align_up(debug_info->data_size() , oopSize) + + align_up((int)sizeof(IMMUTABLE_DATA_REFERENCES) , oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -1755,9 +1755,9 @@ nmethod::nmethod( #if INCLUDE_JVMCI _speculations_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up((int)sizeof(int), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up((int)sizeof(IMMUTABLE_DATA_REFERENCES), oopSize); ) #else - DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up((int)sizeof(int), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up((int)sizeof(IMMUTABLE_DATA_REFERENCES), oopSize); ) #endif assert(immutable_data_end_offset <= immutable_data_size, "wrong read-only data size: %d > %d", immutable_data_end_offset, immutable_data_size); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index be1d0523db08d..33753c2da9d9e 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -25,6 +25,8 @@ #ifndef SHARE_CODE_NMETHOD_HPP #define SHARE_CODE_NMETHOD_HPP +#define IMMUTABLE_DATA_REFERENCES int + #include "code/codeBlob.hpp" #include "code/pcDesc.hpp" #include "oops/metadata.hpp" @@ -572,12 +574,12 @@ class nmethod : public CodeBlob { #if INCLUDE_JVMCI address scopes_data_end () const { return _immutable_data + _speculations_offset ; } address speculations_begin () const { return _immutable_data + _speculations_offset ; } - address speculations_end () const { return immutable_data_end() - sizeof(int) ; } + address speculations_end () const { return immutable_data_end() - sizeof(IMMUTABLE_DATA_REFERENCES) ; } #else - address scopes_data_end () const { return immutable_data_end() - sizeof(int) ; } + address scopes_data_end () const { return immutable_data_end() - sizeof(IMMUTABLE_DATA_REFERENCES) ; } #endif - address immutable_data_references_begin () const { return immutable_data_end() - sizeof(int) ; } + address immutable_data_references_begin () const { return immutable_data_end() - sizeof(IMMUTABLE_DATA_REFERENCES) ; } // Sizes int immutable_data_size() const { return _immutable_data_size; } From c5ff58f4e22cbbcdbe06997efe482f73fcee73f5 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 29 May 2025 22:43:19 +0000 Subject: [PATCH 061/103] Add requires GC to tests --- .../compiler/whitebox/DeoptimizeRelocatedNMethod.java | 5 +++++ .../jtreg/compiler/whitebox/RelocateNMethod.java | 5 +++++ .../whitebox/RelocateNMethodMultiplePaths.java | 10 ++++++++++ 3 files changed, 20 insertions(+) diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java index 340685e36849e..172df14449777 100644 --- a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java @@ -28,6 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Serial * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.DeoptimizeRelocatedNMethod @@ -39,6 +40,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Parallel * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.DeoptimizeRelocatedNMethod @@ -50,6 +52,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.G1 * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.DeoptimizeRelocatedNMethod @@ -61,6 +64,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Shenandoah * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.DeoptimizeRelocatedNMethod @@ -72,6 +76,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc java.management * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Z * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.DeoptimizeRelocatedNMethod diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java index 77a4f41f4937b..dca076e2245ac 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -30,6 +30,7 @@ * @modules java.base/jdk.internal.misc java.management * * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Serial * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox @@ -44,6 +45,7 @@ * @modules java.base/jdk.internal.misc java.management * * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Parallel * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox @@ -58,6 +60,7 @@ * @modules java.base/jdk.internal.misc java.management * * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.G1 * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox @@ -72,6 +75,7 @@ * @modules java.base/jdk.internal.misc java.management * * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Shenandoah * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox @@ -86,6 +90,7 @@ * @modules java.base/jdk.internal.misc java.management * * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Z * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java index 499f56022135c..85eb7d46f3302 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java @@ -26,6 +26,7 @@ * @test id=SerialC1 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.Serial * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -40,6 +41,7 @@ * @test id=SerialC2 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.Serial * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -54,6 +56,7 @@ * @test id=ParallelC1 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.Parallel * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -68,6 +71,7 @@ * @test id=ParallelC2 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.Parallel * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -82,6 +86,7 @@ * @test id=G1C1 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.G1 * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -96,6 +101,7 @@ * @test id=G1C2 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.G1 * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -110,6 +116,7 @@ * @test id=ShenandoahC1 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.Shenandoah * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -124,6 +131,7 @@ * @test id=ShenandoahC2 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.Shenandoah * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -138,6 +146,7 @@ * @test id=ZGCC1 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.Z * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management @@ -152,6 +161,7 @@ * @test id=ZGCC2 * @bug 8316694 * @requires vm.debug == true + * @requires vm.gc.Z * @summary test that relocated nmethod is correctly deoptimized * @library /test/lib / * @modules java.base/jdk.internal.misc java.management From ec06bb5ed919bc8a95d29992a65317b7b0852451 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 30 May 2025 18:28:02 +0000 Subject: [PATCH 062/103] Remove gc on allocation --- src/hotspot/share/code/nmethod.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 7cc856de042c8..c169f2efb8468 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1523,9 +1523,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { return nullptr; } - // Check if memory should be freed before allocation - CodeCache::gc_on_allocation(); - MutexLocker ml_Compile_lock(Compile_lock); MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); @@ -1569,17 +1566,23 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } } - ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); - - // Update corresponding Java method to point to this nmethod MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); - if (nm_copy->method() != nullptr && nm_copy->method()->code() == this && nm_copy->make_in_use()) { - methodHandle mh(Thread::current(), nm_copy->method()); - nm_copy->method()->set_code(mh, nm_copy); - make_not_used(); + + // Verify the nm we copied from is still valid + if (method() != nullptr && method()->code() == this && !is_marked_for_deoptimization() && is_in_use()) { + + // Attempt to start using the copy + if (nm_copy->make_in_use()) { + methodHandle mh(Thread::current(), nm_copy->method()); + nm_copy->method()->set_code(mh, nm_copy); + + make_not_used(); + + return nm_copy; + } } - return nm_copy; + return nullptr; } bool nmethod::is_relocatable() { From d3bdb1f8f1dcfa26dd807318381b95b32c97b4bc Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 30 May 2025 20:54:00 +0000 Subject: [PATCH 063/103] Small fix --- src/hotspot/share/code/nmethod.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c169f2efb8468..01ab0af7cf32f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1566,6 +1566,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } } + ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); + MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); // Verify the nm we copied from is still valid @@ -1582,6 +1584,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } } + nm_copy->make_not_used(); + return nullptr; } From ec6821fc89cf56f97b51015fc3e6826e4f7c9451 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 30 May 2025 22:16:16 +0000 Subject: [PATCH 064/103] Fix comment --- src/hotspot/share/code/nmethod.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 33753c2da9d9e..2936b13ccee3e 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -498,9 +498,9 @@ class nmethod : public CodeBlob { ); // Relocate the nmethod to the code heap identified by code_blob_type. - // Returns nullptr if the code heap does not have enough space or the - // nmethod is unrelocatable, otherwise the relocated nmethod. - // The original nmethod will be marked not entrant. + // Returns nullptr if the code heap does not have enough space, the + // nmethod is unrelocatable, or the nmethod is invalidated during relocation, + // otherwise the relocated nmethod. The original nmethod will be marked not entrant. nmethod* relocate(CodeBlobType code_blob_type); static nmethod* new_native_nmethod(const methodHandle& method, From 6d053dc004d0b0e7998aa3f5c11759bf1fbcd41d Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 30 May 2025 22:16:37 +0000 Subject: [PATCH 065/103] Move ICache::invalidate_range --- src/hotspot/share/code/nmethod.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 01ab0af7cf32f..a8f09c7797902 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1566,8 +1566,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } } - ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); - MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); // Verify the nm we copied from is still valid @@ -1575,6 +1573,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { // Attempt to start using the copy if (nm_copy->make_in_use()) { + ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); + methodHandle mh(Thread::current(), nm_copy->method()); nm_copy->method()->set_code(mh, nm_copy); From 9f753071dfbac839324b9d485a3350e19db0d628 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 30 May 2025 22:46:20 +0000 Subject: [PATCH 066/103] Change to ImmutableDataReferences --- src/hotspot/share/code/nmethod.cpp | 6 +++--- src/hotspot/share/code/nmethod.hpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index a8f09c7797902..5bc6248ad5736 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1164,7 +1164,7 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, + align_up(speculations_len , oopSize) #endif + align_up(debug_info->data_size() , oopSize) - + align_up((int)sizeof(IMMUTABLE_DATA_REFERENCES) , oopSize); + + align_up((int)sizeof(ImmutableDataReferences) , oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -1762,9 +1762,9 @@ nmethod::nmethod( #if INCLUDE_JVMCI _speculations_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up((int)sizeof(IMMUTABLE_DATA_REFERENCES), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up((int)sizeof(ImmutableDataReferences), oopSize); ) #else - DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up((int)sizeof(IMMUTABLE_DATA_REFERENCES), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up((int)sizeof(ImmutableDataReferences), oopSize); ) #endif assert(immutable_data_end_offset <= immutable_data_size, "wrong read-only data size: %d > %d", immutable_data_end_offset, immutable_data_size); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 2936b13ccee3e..cbcb29420fbe1 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -25,8 +25,6 @@ #ifndef SHARE_CODE_NMETHOD_HPP #define SHARE_CODE_NMETHOD_HPP -#define IMMUTABLE_DATA_REFERENCES int - #include "code/codeBlob.hpp" #include "code/pcDesc.hpp" #include "oops/metadata.hpp" @@ -171,6 +169,8 @@ class nmethod : public CodeBlob { friend class JVMCINMethodData; friend class DeoptimizationScope; + using ImmutableDataReferences = int; + private: // Used to track in which deoptimize handshake this method will be deoptimized. @@ -574,12 +574,12 @@ class nmethod : public CodeBlob { #if INCLUDE_JVMCI address scopes_data_end () const { return _immutable_data + _speculations_offset ; } address speculations_begin () const { return _immutable_data + _speculations_offset ; } - address speculations_end () const { return immutable_data_end() - sizeof(IMMUTABLE_DATA_REFERENCES) ; } + address speculations_end () const { return immutable_data_end() - sizeof(ImmutableDataReferences) ; } #else - address scopes_data_end () const { return immutable_data_end() - sizeof(IMMUTABLE_DATA_REFERENCES) ; } + address scopes_data_end () const { return immutable_data_end() - sizeof(ImmutableDataReferences) ; } #endif - address immutable_data_references_begin () const { return immutable_data_end() - sizeof(IMMUTABLE_DATA_REFERENCES) ; } + address immutable_data_references_begin () const { return immutable_data_end() - sizeof(ImmutableDataReferences) ; } // Sizes int immutable_data_size() const { return _immutable_data_size; } From 14bcbbfd9b892d484549bfc11e972196595145d5 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 2 Jun 2025 17:42:46 +0000 Subject: [PATCH 067/103] Use ptrdiff_t instead of int --- src/hotspot/share/code/relocInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 0014f164ab1c8..cd4cd80a59496 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -380,7 +380,7 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer if (src->contains(callee)) { // If the original call is to an address in the src CodeBuffer (such as a stub call) // the updated call should be to the corresponding address in dest CodeBuffer - int offset = callee - orig_addr; + ptrdiff_t offset = callee - orig_addr; callee = addr() + offset; } From 37fb2fac1f7ad177b5a7947abd4b63329817703c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 2 Jun 2025 19:58:12 +0000 Subject: [PATCH 068/103] Fix is_safe --- src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp | 2 +- src/hotspot/share/gc/z/zUnload.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 83151313f7565..aaa6d0b67eff7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -103,7 +103,7 @@ class ShenandoahCompiledICProtectionBehaviour : public CompiledICProtectionBehav } virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || nm->is_not_installed()) { return true; } diff --git a/src/hotspot/share/gc/z/zUnload.cpp b/src/hotspot/share/gc/z/zUnload.cpp index 3dc7ecd3edc41..03dbf88ad89a3 100644 --- a/src/hotspot/share/gc/z/zUnload.cpp +++ b/src/hotspot/share/gc/z/zUnload.cpp @@ -100,7 +100,7 @@ class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { } virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || nm->is_not_installed()) { return true; } From 8ac5c241b00bc66890be67f443000a5bf9dedc28 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 2 Jun 2025 19:58:56 +0000 Subject: [PATCH 069/103] Update DeoptimizeRelocatedNMethod to call relocated function --- .../jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java index 172df14449777..51aab8d703730 100644 --- a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java @@ -127,6 +127,9 @@ public static void main(String [] args) throws Exception { throw new RuntimeException("Did not create new nmethod"); } + // Call to verify everything still works + function(); + // Deoptimized method WHITE_BOX.deoptimizeMethod(method); From 7f558f629e8588a3598fc90942ea5d90346dfe13 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 2 Jun 2025 20:00:19 +0000 Subject: [PATCH 070/103] Remove 0 from relocateNMethodFromAddr0 --- src/hotspot/share/prims/whitebox.cpp | 2 +- .../jtreg/compiler/whitebox/StressNMethodRelocation.java | 4 ++-- test/lib/jdk/test/whitebox/WhiteBox.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index c3c94b6bbf2de..a92814b381c5a 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2909,7 +2909,7 @@ static JNINativeMethod methods[] = { (void*)&WB_GetNMethod }, {CC"relocateNMethodFromMethod0", CC"(Ljava/lang/reflect/Executable;I)V", (void*)&WB_RelocateNMethodFromMethod }, - {CC"relocateNMethodFromAddr0", CC"(JI)V", (void*)&WB_RelocateNMethodFromAddr }, + {CC"relocateNMethodFromAddr", CC"(JI)V", (void*)&WB_RelocateNMethodFromAddr }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java index b70e85a56ba37..b3e148b1dad00 100644 --- a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -198,7 +198,7 @@ public void run() { CodeBlob[] nonProfiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodNonProfiled); for (CodeBlob blob : nonProfiledBlobs) { if (blob.isNMethod) { - WHITE_BOX.relocateNMethodFromAddr0(blob.address, BlobType.MethodProfiled.id); + WHITE_BOX.relocateNMethodFromAddr(blob.address, BlobType.MethodProfiled.id); } } @@ -206,7 +206,7 @@ public void run() { CodeBlob[] profiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodProfiled); for (CodeBlob blob : nonProfiledBlobs) { if (blob.isNMethod) { - WHITE_BOX.relocateNMethodFromAddr0(blob.address, BlobType.MethodNonProfiled.id); + WHITE_BOX.relocateNMethodFromAddr(blob.address, BlobType.MethodNonProfiled.id); } } } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 0a49d55c94d5a..8ad5015101b7d 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -495,7 +495,7 @@ public void relocateNMethodFromMethod(Executable method, int type) { Objects.requireNonNull(method); relocateNMethodFromMethod0(method, type); } - public native void relocateNMethodFromAddr0(long address, int type); + public native void relocateNMethodFromAddr(long address, int type); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; From 39a476d09707f838bf6409595410433c24365f1e Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 2 Jun 2025 20:27:07 +0000 Subject: [PATCH 071/103] Update nm valid check --- src/hotspot/share/code/nmethod.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5bc6248ad5736..730fc78c7e13d 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1569,7 +1569,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); // Verify the nm we copied from is still valid - if (method() != nullptr && method()->code() == this && !is_marked_for_deoptimization() && is_in_use()) { + if (!is_marked_for_deoptimization() && is_in_use()) { + assert(method() != nullptr && method()->code() == this, "should be if is in use"); // Attempt to start using the copy if (nm_copy->make_in_use()) { From eed3d434b91144b386c33795e343a5cf09b5502b Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 2 Jun 2025 20:51:29 +0000 Subject: [PATCH 072/103] Update ImmutableDataReferences --- src/hotspot/share/code/nmethod.cpp | 6 +++--- src/hotspot/share/code/nmethod.hpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 730fc78c7e13d..675cb4b371352 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1164,7 +1164,7 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, + align_up(speculations_len , oopSize) #endif + align_up(debug_info->data_size() , oopSize) - + align_up((int)sizeof(ImmutableDataReferences) , oopSize); + + align_up(ImmutableDataReferencesCounterSize , oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -1763,9 +1763,9 @@ nmethod::nmethod( #if INCLUDE_JVMCI _speculations_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up((int)sizeof(ImmutableDataReferences), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up(ImmutableDataReferencesCounterSize, oopSize); ) #else - DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up((int)sizeof(ImmutableDataReferences), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up(ImmutableDataReferencesCounterSize, oopSize); ) #endif assert(immutable_data_end_offset <= immutable_data_size, "wrong read-only data size: %d > %d", immutable_data_end_offset, immutable_data_size); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index cbcb29420fbe1..caa9971f772e2 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -169,7 +169,7 @@ class nmethod : public CodeBlob { friend class JVMCINMethodData; friend class DeoptimizationScope; - using ImmutableDataReferences = int; + #define ImmutableDataReferencesCounterSize (int)sizeof(int) private: @@ -574,12 +574,12 @@ class nmethod : public CodeBlob { #if INCLUDE_JVMCI address scopes_data_end () const { return _immutable_data + _speculations_offset ; } address speculations_begin () const { return _immutable_data + _speculations_offset ; } - address speculations_end () const { return immutable_data_end() - sizeof(ImmutableDataReferences) ; } + address speculations_end () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } #else - address scopes_data_end () const { return immutable_data_end() - sizeof(ImmutableDataReferences) ; } + address scopes_data_end () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } #endif - address immutable_data_references_begin () const { return immutable_data_end() - sizeof(ImmutableDataReferences) ; } + address immutable_data_references_begin () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } // Sizes int immutable_data_size() const { return _immutable_data_size; } From b0dad6659047553ebee1387939e54ea817b31cb1 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 2 Jun 2025 21:43:56 +0000 Subject: [PATCH 073/103] Update immutable_data_references naming --- src/hotspot/share/code/nmethod.cpp | 8 ++++---- src/hotspot/share/code/nmethod.hpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 675cb4b371352..07e1517ca38c2 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1442,7 +1442,7 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h _immutable_data_size = nm->_immutable_data_size; if (_immutable_data_size > 0) { _immutable_data = nm->_immutable_data; - set_immutable_data_references(get_immutable_data_references() + 1); + set_immutable_data_references_counter(get_immutable_data_references_counter() + 1); } else { _immutable_data = blob_end(); } @@ -1798,7 +1798,7 @@ nmethod::nmethod( memcpy(speculations_begin(), speculations, speculations_len); } #endif - set_immutable_data_references(1); + set_immutable_data_references_counter(1); post_init(); @@ -2387,10 +2387,10 @@ void nmethod::purge(bool unregister_nmethod) { if (_immutable_data != blob_end()) { // Free memory if this is the last nmethod referencing immutable data - if (get_immutable_data_references() == 1) { + if (get_immutable_data_references_counter() == 1) { os::free(_immutable_data); } else { - set_immutable_data_references(get_immutable_data_references() - 1); + set_immutable_data_references_counter(get_immutable_data_references_counter() - 1); } _immutable_data = blob_end(); // Valid not null address diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index caa9971f772e2..b33bc73103c26 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -579,7 +579,7 @@ class nmethod : public CodeBlob { address scopes_data_end () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } #endif - address immutable_data_references_begin () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } + address immutable_data_references_counter_begin () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } // Sizes int immutable_data_size() const { return _immutable_data_size; } @@ -893,8 +893,8 @@ class nmethod : public CodeBlob { bool load_reported() const { return _load_reported; } void set_load_reported() { _load_reported = true; } - inline int get_immutable_data_references() { return *((int*)immutable_data_references_begin()); } - inline void set_immutable_data_references(int count) { *((int*)immutable_data_references_begin()) = count; } + inline int get_immutable_data_references_counter() { return *((int*)immutable_data_references_counter_begin()); } + inline void set_immutable_data_references_counter(int count) { *((int*)immutable_data_references_counter_begin()) = count; } public: // ScopeDesc retrieval operation From 4e80e35959829ecf1579efc65b9525b2aff2be1f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 2 Jun 2025 22:39:43 +0000 Subject: [PATCH 074/103] Fix test copywrite --- .../jtreg/compiler/whitebox/StressNMethodRelocation.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java index b3e148b1dad00..26b7a7e85bca0 100644 --- a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,6 +19,7 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. + * */ /* From 3c3211db5553fb16f3ea4d7641676f63d3010ca6 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 11 Jun 2025 18:11:05 +0000 Subject: [PATCH 075/103] Publish JVMTI events --- src/hotspot/share/code/nmethod.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 07e1517ca38c2..4352ccec3251f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1581,6 +1581,9 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { make_not_used(); + post_compiled_method_unload(); + nm_copy->post_compiled_method_load_event(); + return nm_copy; } } From a21b6acccd157926d19cda01bf6746851732f4ea Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 11 Jun 2025 21:32:53 +0000 Subject: [PATCH 076/103] Log relocated nmethod --- src/hotspot/share/code/codeCache.hpp | 2 +- src/hotspot/share/code/nmethod.cpp | 36 ++++++++++++++++++++++++++++ src/hotspot/share/code/nmethod.hpp | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 3e446ab8430fe..dc9e5d7dc2030 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -259,7 +259,7 @@ class CodeCache : AllStatic { static bool heap_available(CodeBlobType code_blob_type); // Returns the CodeBlobType for the given nmethod - static CodeBlobType get_code_blob_type(nmethod* nm) { + static CodeBlobType get_code_blob_type(const nmethod* nm) { return get_code_heap(nm)->code_blob_type(); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 4352ccec3251f..64c4a4d7021b4 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1584,6 +1584,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { post_compiled_method_unload(); nm_copy->post_compiled_method_load_event(); + nm_copy->log_relocated_nmethod(this); + return nm_copy; } } @@ -1868,6 +1870,40 @@ void nmethod::log_new_nmethod() const { } } + +void nmethod::log_relocated_nmethod(nmethod* original) const { + if (LogCompilation && xtty != nullptr) { + ttyLocker ttyl; + xtty->begin_elem("relocated nmethod"); + log_identity(xtty); + xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", p2i(code_begin()), size()); + + const char* original_code_heap_name = CodeCache::get_code_heap_name(CodeCache::get_code_blob_type(original)); + xtty->print(" original_address='" INTPTR_FORMAT "'", p2i(original)); + xtty->print(" original_code_heap='%s'", original_code_heap_name); + + const char* new_code_heap_name = CodeCache::get_code_heap_name(CodeCache::get_code_blob_type(this)); + xtty->print(" new_address='" INTPTR_FORMAT "'", p2i(this)); + xtty->print(" new_code_heap='%s'", new_code_heap_name); + + LOG_OFFSET(xtty, relocation); + LOG_OFFSET(xtty, consts); + LOG_OFFSET(xtty, insts); + LOG_OFFSET(xtty, stub); + LOG_OFFSET(xtty, scopes_data); + LOG_OFFSET(xtty, scopes_pcs); + LOG_OFFSET(xtty, dependencies); + LOG_OFFSET(xtty, handler_table); + LOG_OFFSET(xtty, nul_chk_table); + LOG_OFFSET(xtty, oops); + LOG_OFFSET(xtty, metadata); + + xtty->method(method()); + xtty->stamp(); + xtty->end_elem(); + } +} + #undef LOG_OFFSET diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index b33bc73103c26..372696bd99612 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -964,6 +964,7 @@ class nmethod : public CodeBlob { // Logging void log_identity(xmlStream* log) const; void log_new_nmethod() const; + void log_relocated_nmethod(nmethod* original) const; void log_state_change(const char* reason) const; // Prints block-level comments, including nmethod specific block labels: From b3358bda645c68f1ffccdfdcb98c44ee0ec69ce0 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 17 Jun 2025 00:07:40 +0000 Subject: [PATCH 077/103] Add test to verify JVMTI events during nmethod relocation --- src/hotspot/share/code/nmethod.cpp | 1 - src/hotspot/share/prims/whitebox.cpp | 10 +- .../NMethodRelocation/nmethodrelocation.java | 127 ++++++++++++++ .../nmethodrelocation/TestDriver.java | 82 +++++++++ .../agentnmethodrelocation001.cpp | 159 ++++++++++++++++++ .../libagentnmethodrelocation001.cpp | 33 ++++ test/lib/jdk/test/whitebox/code/CodeBlob.java | 7 +- 7 files changed, 414 insertions(+), 5 deletions(-) create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/libagentnmethodrelocation001.cpp diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 64c4a4d7021b4..9b3091cf0131a 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1581,7 +1581,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { make_not_used(); - post_compiled_method_unload(); nm_copy->post_compiled_method_load_event(); nm_copy->log_relocated_nmethod(this); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index a92814b381c5a..5211599c63dbd 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1558,12 +1558,14 @@ struct CodeBlobStub { size(blob->size()), blob_type(static_cast(WhiteBox::get_blob_type(blob))), address((jlong) blob), + code_begin((jlong) blob->code_begin()), is_nmethod((jboolean) blob->is_nmethod()) { } ~CodeBlobStub() { os::free((void*) name); } const char* const name; const jint size; const jint blob_type; const jlong address; + const jlong code_begin; const jboolean is_nmethod; }; @@ -1571,7 +1573,7 @@ static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBl ResourceMark rm; jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); CHECK_JNI_EXCEPTION_(env, nullptr); - jobjectArray result = env->NewObjectArray(5, clazz, nullptr); + jobjectArray result = env->NewObjectArray(6, clazz, nullptr); jstring name = env->NewStringUTF(cb->name); CHECK_JNI_EXCEPTION_(env, nullptr); @@ -1589,10 +1591,14 @@ static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBl CHECK_JNI_EXCEPTION_(env, nullptr); env->SetObjectArrayElement(result, 3, obj); - obj = booleanBox(thread, env, cb->is_nmethod); + obj = longBox(thread, env, cb->code_begin); CHECK_JNI_EXCEPTION_(env, nullptr); env->SetObjectArrayElement(result, 4, obj); + obj = booleanBox(thread, env, cb->is_nmethod); + CHECK_JNI_EXCEPTION_(env, nullptr); + env->SetObjectArrayElement(result, 5, obj); + return result; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java new file mode 100644 index 0000000000000..3aa39d2b837ae --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java @@ -0,0 +1,127 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.jvmti.NMethodRelocation; + +import java.io.PrintStream; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.Objects; + +import nsk.share.*; +import nsk.share.jvmti.*; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.NMethod; +import jdk.test.whitebox.code.BlobType; + +public class nmethodrelocation extends DebugeeClass { + + protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + /** Value of {@code -XX:CompileThreshold} */ + protected static final int COMPILE_THRESHOLD + = Integer.parseInt(getVMOption("CompileThreshold", "10000")); + + /** Load native library if required. */ + static { + loadLibrary("agentnmethodrelocation001"); + } + + /** + * Returns value of VM option. + * + * @param name option's name + * @return value of option or {@code null}, if option doesn't exist + * @throws NullPointerException if name is null + */ + protected static String getVMOption(String name) { + Objects.requireNonNull(name); + return Objects.toString(WHITE_BOX.getVMFlag(name), null); + } + + /** + * Returns value of VM option or default value. + * + * @param name option's name + * @param defaultValue default value + * @return value of option or {@code defaultValue}, if option doesn't exist + * @throws NullPointerException if name is null + * @see #getVMOption(String) + */ + protected static String getVMOption(String name, String defaultValue) { + String result = getVMOption(name); + return result == null ? defaultValue : result; + } + public static void main(String argv[]) throws Exception { + argv = nsk.share.jvmti.JVMTITest.commonInit(argv); + + run(); + } + + static int status = Consts.TEST_PASSED; + + public static int run() throws Exception { + Executable method = nmethodrelocation.class.getDeclaredMethod("compiledMethod"); + WHITE_BOX.testSetDontInlineMethod(method, true); + + compile(); + + NMethod originalNMethod = NMethod.get(method, false); + if (originalNMethod == null) { + throw new AssertionError("Could not find original nmethod"); + } + + WHITE_BOX.relocateNMethodFromAddr(originalNMethod.address, BlobType.MethodNonProfiled.id); + + NMethod relocatedNMethod = NMethod.get(method, false); + if (relocatedNMethod == null) { + throw new AssertionError("Could not find relocated nmethod"); + } + + if (originalNMethod.address == relocatedNMethod.address) { + throw new AssertionError("Relocated nmethod same as original"); + } + + WHITE_BOX.deoptimizeAll(); + + WHITE_BOX.fullGC(); + WHITE_BOX.fullGC(); + + status = checkStatus(status); + + System.out.printf("Relocated nmethod from %d to %d%n", originalNMethod.code_begin, relocatedNMethod.code_begin); + System.out.flush(); + + return status; + } + + private static void compile() { + for (int i = 0; i < COMPILE_THRESHOLD; i++) { + compiledMethod(); + } + } + + public static long compiledMethod() { + return 0; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java new file mode 100644 index 0000000000000..2ba6a9f6d979d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java @@ -0,0 +1,82 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + + +/* + * @test + * + * @summary + * + * @library /vmTestbase /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm/native TestDriver + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Asserts; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +public class TestDriver { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-agentlib:agentnmethodrelocation001=-waittime=5", + "--enable-native-access=ALL-UNNAMED", + "-Xbootclasspath/a:.", + "-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:+SegmentedCodeCache", + "-XX:-TieredCompilation", + "-Xbatch", + nsk.jvmti.NMethodRelocation.nmethodrelocation.class.getName()); + + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + String output = oa.getOutput(); + if (oa.getExitValue() != 0) { + System.err.println(oa.getOutput()); + throw new RuntimeException("Non-zero exit code returned from the test"); + } + Asserts.assertTrue(oa.getExitValue() == 0); + + Pattern pattern = Pattern.compile("(?m)^Relocated nmethod from (\\d+) to (\\d+)$"); + Matcher matcher = pattern.matcher(output); + + if (matcher.find()) { + String fromAddr = matcher.group(1); + String toAddr = matcher.group(2); + + // Confirm events sent for both original and relocated nmethod + oa.shouldContain(": name: compiledMethod, code: " + fromAddr); + oa.shouldContain(": name: compiledMethod, code: " + toAddr); + oa.shouldContain(": name: compiledMethod, code: " + fromAddr); + oa.shouldContain(": name: compiledMethod, code: " + toAddr); + } else { + throw new RuntimeException("Unable to find relocation information"); + } + } +} + diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp new file mode 100644 index 0000000000000..305f4f7ad093f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp @@ -0,0 +1,159 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmti.h" +#include "agent_common.hpp" +#include "jvmti_tools.hpp" + +extern "C" { + +/* scaffold objects */ +static jlong timeout = 0; + +#define EVENTS_COUNT 2 + +/* tested events */ +static jvmtiEvent eventsList[EVENTS_COUNT] = { + JVMTI_EVENT_COMPILED_METHOD_LOAD, + JVMTI_EVENT_COMPILED_METHOD_UNLOAD +}; + +/** Agent library initialization. */ +#ifdef STATIC_BUILD +JNIEXPORT jint JNICALL Agent_OnLoad_setevntcallb001(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} +JNIEXPORT jint JNICALL Agent_OnAttach_setevntcallb001(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} +JNIEXPORT jint JNI_OnLoad_setevntcallb001(JavaVM *jvm, char *options, void *reserved) { + return JNI_VERSION_1_8; +} +#endif + +/* ============================================================================= */ + +/** Agent algorithm. */ +static void JNICALL +agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { + NSK_DISPLAY0("Wait for tested method forced to compile\n"); + if (!nsk_jvmti_waitForSync(timeout)) + return; + + if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, nullptr)) { + nsk_jvmti_setFailStatus(); + } + + if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, nullptr)) { + nsk_jvmti_setFailStatus(); + } + + NSK_DISPLAY0("Let debugee to finish\n"); + if (!nsk_jvmti_resumeSync()) + return; +} + +/* ============================================================================= */ + +JNIEXPORT void JNICALL +callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, + jint code_size, const void* code_addr, + jint map_length, const jvmtiAddrLocationMap* map, + const void* compile_info) { + char* name = nullptr; + char* sig = nullptr; + + if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { + printf(" [Could not retrieve method name]\n"); + fflush(stdout); + return; + } + + printf(": name: %s, code: %lu\n", + name, code_addr); + fflush(stdout); +} + +/** + * Callback for COMPILED_METHOD_UNLOAD event. + */ +JNIEXPORT void JNICALL +callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, + const void* code_addr) { + char* name = nullptr; + char* sig = nullptr; + + if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { + printf(" [Could not retrieve method name]\n"); + fflush(stdout); + return; + } + printf(": name: %s, code: %lu\n", + name, (void*)code_addr); + fflush(stdout); +} + +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jvmtiEnv* jvmti = nullptr; + + if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) + return JNI_ERR; + + timeout = nsk_jvmti_getWaitTime() * 60 * 1000; + + if (!NSK_VERIFY((jvmti = + nsk_jvmti_createJVMTIEnv(jvm, reserved)) != nullptr)) + return JNI_ERR; + + if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, nullptr))) + return JNI_ERR; + + /* add required capabilities */ + { + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_generate_compiled_method_load_events = 1; + if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) + return JNI_ERR; + } + + /* set event callbacks */ + { + jvmtiEventCallbacks eventCallbacks; + memset(&eventCallbacks, 0, sizeof(eventCallbacks)); + eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad; + eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload; + if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)))) + return JNI_ERR; + + if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, nullptr))) + return JNI_ERR; + if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, nullptr))) + return JNI_ERR; + } + + return JNI_OK; +} + +/* ============================================================================= */ +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/libagentnmethodrelocation001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/libagentnmethodrelocation001.cpp new file mode 100644 index 0000000000000..98c338486118f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/libagentnmethodrelocation001.cpp @@ -0,0 +1,33 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "native_thread.cpp" +#include "nsk_tools.cpp" +#include "jni_tools.cpp" +#include "jvmti_tools.cpp" +#include "agent_tools.cpp" +#include "jvmti_FollowRefObjects.cpp" +#include "Injector.cpp" +#include "JVMTITools.cpp" +#include "agent_common.cpp" +#include "agentnmethodrelocation001.cpp" diff --git a/test/lib/jdk/test/whitebox/code/CodeBlob.java b/test/lib/jdk/test/whitebox/code/CodeBlob.java index f4ba52ba9eb14..fd95b5a7e7d3d 100644 --- a/test/lib/jdk/test/whitebox/code/CodeBlob.java +++ b/test/lib/jdk/test/whitebox/code/CodeBlob.java @@ -46,19 +46,21 @@ public static CodeBlob getCodeBlob(long addr) { return new CodeBlob(obj); } protected CodeBlob(Object[] obj) { - assert obj.length == 5; + assert obj.length == 6; name = (String) obj[0]; size = (Integer) obj[1]; int blob_type_index = (Integer) obj[2]; code_blob_type = BlobType.values()[blob_type_index]; assert code_blob_type.id == (Integer) obj[2]; address = (Long) obj[3]; - isNMethod = (Boolean) obj[4]; + code_begin = (Long) obj[4]; + isNMethod = (Boolean) obj[5]; } public final String name; public final int size; public final BlobType code_blob_type; public final long address; + public final long code_begin; public final boolean isNMethod; @Override public String toString() { @@ -67,6 +69,7 @@ public String toString() { + ", size=" + size + ", code_blob_type=" + code_blob_type + ", address=" + address + + ", code_begin=" + code_begin + '}'; } } From 4091740402f66cb7f354925340edcaa5deda5e6b Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 17 Jun 2025 00:42:08 +0000 Subject: [PATCH 078/103] Move far branch fix to fix_relocation_after_move --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 5 ----- src/hotspot/share/code/relocInfo.cpp | 9 +++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 724065557c202..94694b58d2fae 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -81,11 +81,6 @@ void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { NativeCall* call = nativeCall_at(addr()); - if (!Assembler::reachable_from_branch_at(addr(), x)) { - address trampoline = call->get_trampoline(); - guarantee(trampoline != nullptr, "Must have trampoline for far call"); - x = trampoline; - } call->set_destination(x); } else { MacroAssembler::pd_patch_instruction(addr(), x); diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index cd4cd80a59496..e138393095313 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -384,6 +384,15 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer callee = addr() + offset; } + if (!Assembler::reachable_from_branch_at(addr(), callee)) { + if (NativeCall::is_call_at(addr())) { + NativeCall* call = nativeCall_at(addr()); + address trampoline = call->get_trampoline(); + guarantee(trampoline != nullptr, "Must have trampoline for far call"); + callee = trampoline; + } + } + // Reassert the callee address, this time in the new copy of the code. pd_set_call_destination(callee); } From 60005e51fefd2d7daf397f06e2d58a68f93e856c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 17 Jun 2025 00:42:08 +0000 Subject: [PATCH 079/103] Move far branch fix to fix_relocation_after_move --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 5 ----- src/hotspot/share/code/relocInfo.cpp | 13 +++++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 724065557c202..94694b58d2fae 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -81,11 +81,6 @@ void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { NativeCall* call = nativeCall_at(addr()); - if (!Assembler::reachable_from_branch_at(addr(), x)) { - address trampoline = call->get_trampoline(); - guarantee(trampoline != nullptr, "Must have trampoline for far call"); - x = trampoline; - } call->set_destination(x); } else { MacroAssembler::pd_patch_instruction(addr(), x); diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index cd4cd80a59496..afa8e2cab3cfb 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -384,6 +384,19 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer callee = addr() + offset; } +// We must check that the new offset can still fit in the instruction +// for architectures that have small branch ranges +#if defined(AARCH64) || defined(RISV) + if (!Assembler::reachable_from_branch_at(addr(), callee)) { + if (NativeCall::is_call_at(addr())) { + NativeCall* call = nativeCall_at(addr()); + address trampoline = call->get_trampoline(); + guarantee(trampoline != nullptr, "Must have trampoline for far call"); + callee = trampoline; + } + } +#endif + // Reassert the callee address, this time in the new copy of the code. pd_set_call_destination(callee); } From d5e566c1f4249b465af88b5700bcb7220e0b431f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 17 Jun 2025 21:11:29 +0000 Subject: [PATCH 080/103] Use new _metadata_size instead of _jvmci_data_size --- src/hotspot/share/code/nmethod.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index e04b4da60a86c..bc94e573ee214 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1478,7 +1478,7 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h _num_stack_arg_slots = nm->_num_stack_arg_slots; _oops_size = nm->_oops_size; #if INCLUDE_JVMCI - _jvmci_data_size = nm->_jvmci_data_size; + _metadata_size = nm->_metadata_size; #endif _nul_chk_table_offset = nm->_nul_chk_table_offset; _handler_table_offset = nm->_handler_table_offset; From 50f0edb38eff12284fee67f224c5e2aaf6412287 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 18 Jun 2025 01:09:03 +0000 Subject: [PATCH 081/103] Print address as pointer --- .../nsk/jvmti/NMethodRelocation/nmethodrelocation.java | 2 +- .../NMethodRelocation/nmethodrelocation/TestDriver.java | 3 ++- .../nmethodrelocation/agentnmethodrelocation001.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java index 3aa39d2b837ae..2db18c9ee0a73 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java @@ -109,7 +109,7 @@ public static int run() throws Exception { status = checkStatus(status); - System.out.printf("Relocated nmethod from %d to %d%n", originalNMethod.code_begin, relocatedNMethod.code_begin); + System.out.printf("Relocated nmethod from 0x%016x to 0x%016x%n", originalNMethod.code_begin, relocatedNMethod.code_begin); System.out.flush(); return status; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java index 2ba6a9f6d979d..a5918d2b03e26 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java @@ -62,7 +62,7 @@ public static void main(String[] args) throws Exception { } Asserts.assertTrue(oa.getExitValue() == 0); - Pattern pattern = Pattern.compile("(?m)^Relocated nmethod from (\\d+) to (\\d+)$"); + Pattern pattern = Pattern.compile("(?m)^Relocated nmethod from (0x[0-9a-f]{16}) to (0x[0-9a-f]{16})$"); Matcher matcher = pattern.matcher(output); if (matcher.find()) { @@ -75,6 +75,7 @@ public static void main(String[] args) throws Exception { oa.shouldContain(": name: compiledMethod, code: " + fromAddr); oa.shouldContain(": name: compiledMethod, code: " + toAddr); } else { + System.err.println(oa.getOutput()); throw new RuntimeException("Unable to find relocation information"); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp index 305f4f7ad093f..315fe07ae4476 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp @@ -89,8 +89,8 @@ callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, return; } - printf(": name: %s, code: %lu\n", - name, code_addr); + printf(": name: %s, code: 0x%016lx\n", + name, (unsigned long)code_addr); fflush(stdout); } @@ -108,8 +108,8 @@ callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, fflush(stdout); return; } - printf(": name: %s, code: %lu\n", - name, (void*)code_addr); + printf(": name: %s, code: 0x%016lx\n", + name, (unsigned long)code_addr); fflush(stdout); } From b02e8bdb63db8042418b92ade4a26647e4e2dd8b Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 18 Jun 2025 21:52:24 +0000 Subject: [PATCH 082/103] Use set_destination_mt_safe --- src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp | 4 ++-- src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp | 2 +- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 12 ++++++++++-- src/hotspot/share/code/relocInfo.cpp | 13 ------------- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 33158d6b97a91..18a96b48fe2f4 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -76,7 +76,7 @@ address NativeCall::destination() const { // call instruction at all times. // // Used in the runtime linkage of calls; see class CompiledIC. -void NativeCall::set_destination_mt_safe(address dest) { +void NativeCall::set_destination_mt_safe(address dest, bool update_trampoline) { assert((CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); @@ -87,7 +87,7 @@ void NativeCall::set_destination_mt_safe(address dest) { // Patch the constant in the call's trampoline stub. address trampoline_stub_addr = get_trampoline(); - if (trampoline_stub_addr != nullptr) { + if (trampoline_stub_addr != nullptr && update_trampoline) { assert (! is_NativeCallTrampolineStub_at(dest), "chained trampolines"); nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest); } diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 0eb5ff815be1d..576de7f73faf1 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -214,7 +214,7 @@ class NativeCall: public NativeInstruction { // // Used in the runtime linkage of calls; see class CompiledIC. // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) - void set_destination_mt_safe(address dest); + void set_destination_mt_safe(address dest, bool update_trampoline=true); address get_trampoline(); #if INCLUDE_JVMCI diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 94694b58d2fae..c9f98eef2bbb9 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -81,11 +81,19 @@ void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { NativeCall* call = nativeCall_at(addr()); - call->set_destination(x); + CodeBlob* cb = CodeCache::find_blob(addr()); + if (cb->is_nmethod()) { + // Relocation for trampoline stub will fix its own destination + call->set_destination_mt_safe(x, false); + assert(pd_call_destination(addr()) == x || pd_call_destination(addr()) == call->get_trampoline(), "fail in reloc"); + } else { + call->set_destination(x); + assert(pd_call_destination(addr()) == x, "fail in reloc"); + } } else { MacroAssembler::pd_patch_instruction(addr(), x); + assert(pd_call_destination(addr()) == x, "fail in reloc"); } - assert(pd_call_destination(addr()) == x, "fail in reloc"); } void trampoline_stub_Relocation::pd_fix_owner_after_move() { diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index d0a9021220a2b..9c62bb82e2e33 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -410,19 +410,6 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer callee = addr() + offset; } -// We must check that the new offset can still fit in the instruction -// for architectures that have small branch ranges -#if defined(AARCH64) || defined(RISV) - if (!Assembler::reachable_from_branch_at(addr(), callee)) { - if (NativeCall::is_call_at(addr())) { - NativeCall* call = nativeCall_at(addr()); - address trampoline = call->get_trampoline(); - guarantee(trampoline != nullptr, "Must have trampoline for far call"); - callee = trampoline; - } - } -#endif - // Reassert the callee address, this time in the new copy of the code. pd_set_call_destination(callee); } From 292ab74f8dfd21b2e17f95e39520688d65c72ec5 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 18 Jun 2025 22:01:30 +0000 Subject: [PATCH 083/103] Fix pointer printing --- .../NMethodRelocation/nmethodrelocation/TestDriver.java | 5 ++--- .../nmethodrelocation/agentnmethodrelocation001.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java index a5918d2b03e26..97c86cd509f8b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java @@ -21,12 +21,11 @@ * questions. */ - - /* * @test * - * @summary + * @bug 8316694 + * @summary Verify that nmethod relocation posts the correct JVMTI events * * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp index 315fe07ae4476..f132849c3cf92 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp @@ -89,8 +89,8 @@ callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, return; } - printf(": name: %s, code: 0x%016lx\n", - name, (unsigned long)code_addr); + printf(": name: %s, code: 0x%016" PRIxPTR "\n", + name, (uintptr_t)code_addr); fflush(stdout); } @@ -108,8 +108,8 @@ callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, fflush(stdout); return; } - printf(": name: %s, code: 0x%016lx\n", - name, (unsigned long)code_addr); + printf(": name: %s, code: 0x%016" PRIxPTR "\n", + name, (uintptr_t)code_addr); fflush(stdout); } From ff5c6d9602ee97b376133ff3f5d31dc3b6ce049c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 25 Jun 2025 18:39:54 +0000 Subject: [PATCH 084/103] Update how call sites are fixed --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 2 +- .../cpu/aarch64/macroAssembler_aarch64.hpp | 3 +++ .../cpu/aarch64/nativeInst_aarch64.cpp | 4 ++-- .../cpu/aarch64/nativeInst_aarch64.hpp | 2 +- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 10 ++++---- src/hotspot/cpu/arm/relocInfo_arm.cpp | 4 ++-- src/hotspot/cpu/ppc/relocInfo_ppc.cpp | 4 ++-- src/hotspot/cpu/riscv/relocInfo_riscv.cpp | 4 ++-- src/hotspot/cpu/s390/relocInfo_s390.cpp | 4 ++-- src/hotspot/cpu/x86/relocInfo_x86.cpp | 4 ++-- src/hotspot/cpu/zero/relocInfo_zero.cpp | 5 ++-- src/hotspot/share/asm/codeBuffer.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 23 ++++++++++++++++-- src/hotspot/share/code/relocInfo.cpp | 24 ++++++++++--------- src/hotspot/share/code/relocInfo.hpp | 14 +++++------ 15 files changed, 66 insertions(+), 43 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index cbd941397f305..ec494d8d56205 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -856,7 +856,7 @@ void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, in } // Check the entry target is always reachable from any branch. -static bool is_always_within_branch_range(Address entry) { +bool MacroAssembler::is_always_within_branch_range(Address entry) { if (AOTCodeCache::is_on_for_dump()) { return false; } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index fe2440fd3fd00..e75f9baffd861 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -105,6 +105,9 @@ class MacroAssembler: public Assembler { static KlassDecodeMode klass_decode_mode(); public: + // Check the entry target is always reachable from any branch. + static bool is_always_within_branch_range(Address entry); + // Checks the decode mode and returns false if not compatible with preferred decoding mode. static bool check_klass_decode_mode(address base, int shift, const size_t range); diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 73e83c50a074b..84275a88e9a9b 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -76,7 +76,7 @@ address NativeCall::destination() const { // call instruction at all times. // // Used in the runtime linkage of calls; see class CompiledIC. -void NativeCall::set_destination_mt_safe(address dest, bool update_trampoline) { +void NativeCall::set_destination_mt_safe(address dest) { assert((CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); @@ -87,7 +87,7 @@ void NativeCall::set_destination_mt_safe(address dest, bool update_trampoline) { // Patch the constant in the call's trampoline stub. address trampoline_stub_addr = get_trampoline(); - if (trampoline_stub_addr != nullptr && update_trampoline) { + if (trampoline_stub_addr != nullptr && dest != trampoline_stub_addr) { assert (! is_NativeCallTrampolineStub_at(dest), "chained trampolines"); nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest); } diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 398d0473fc80c..9b9b83e38b8a2 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -214,7 +214,7 @@ class NativeCall: public NativeInstruction { // // Used in the runtime linkage of calls; see class CompiledIC. // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) - void set_destination_mt_safe(address dest, bool update_trampoline=true); + void set_destination_mt_safe(address dest); address get_trampoline(); #if INCLUDE_JVMCI diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index c9f98eef2bbb9..545d1f8494628 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -77,14 +77,12 @@ address Relocation::pd_call_destination(address orig_addr) { } -void Relocation::pd_set_call_destination(address x) { +void Relocation::pd_set_call_destination(address x, bool be_safe) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { NativeCall* call = nativeCall_at(addr()); - CodeBlob* cb = CodeCache::find_blob(addr()); - if (cb->is_nmethod()) { - // Relocation for trampoline stub will fix its own destination - call->set_destination_mt_safe(x, false); + if (be_safe) { + call->set_destination_mt_safe(x); assert(pd_call_destination(addr()) == x || pd_call_destination(addr()) == call->get_trampoline(), "fail in reloc"); } else { call->set_destination(x); @@ -116,7 +114,7 @@ address Relocation::pd_get_address_from_code() { return MacroAssembler::pd_call_destination(addr()); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { if (NativeInstruction::maybe_cpool_ref(addr())) { address old_addr = old_addr_for(addr(), src, dest); MacroAssembler::pd_patch_instruction(addr(), MacroAssembler::target_addr_for_insn(old_addr)); diff --git a/src/hotspot/cpu/arm/relocInfo_arm.cpp b/src/hotspot/cpu/arm/relocInfo_arm.cpp index 2006be978bcdf..04890d58bd65a 100644 --- a/src/hotspot/cpu/arm/relocInfo_arm.cpp +++ b/src/hotspot/cpu/arm/relocInfo_arm.cpp @@ -71,7 +71,7 @@ address Relocation::pd_call_destination(address orig_addr) { return nullptr; } -void Relocation::pd_set_call_destination(address x) { +void Relocation::pd_set_call_destination(address x, bool be_safe) { address pc = addr(); NativeInstruction* ni = nativeInstruction_at(pc); @@ -105,7 +105,7 @@ address Relocation::pd_get_address_from_code() { return *pd_address_in_code(); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { } void metadata_Relocation::pd_fix_value(address x) { diff --git a/src/hotspot/cpu/ppc/relocInfo_ppc.cpp b/src/hotspot/cpu/ppc/relocInfo_ppc.cpp index 559d30a8f23f7..5c8d89ce634b0 100644 --- a/src/hotspot/cpu/ppc/relocInfo_ppc.cpp +++ b/src/hotspot/cpu/ppc/relocInfo_ppc.cpp @@ -73,7 +73,7 @@ address Relocation::pd_call_destination(address orig_addr) { } } -void Relocation::pd_set_call_destination(address x) { +void Relocation::pd_set_call_destination(address x, bool be_safe) { address inst_loc = addr(); if (NativeFarCall::is_far_call_at(inst_loc)) { @@ -99,7 +99,7 @@ address Relocation::pd_get_address_from_code() { return (address)(nativeMovConstReg_at(addr())->data()); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { } void metadata_Relocation::pd_fix_value(address x) { diff --git a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp index 7bee372b0ef80..b1bc9ecb82cfd 100644 --- a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp +++ b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp @@ -90,7 +90,7 @@ address Relocation::pd_call_destination(address orig_addr) { return MacroAssembler::pd_call_destination(addr()); } -void Relocation::pd_set_call_destination(address x) { +void Relocation::pd_set_call_destination(address x, bool be_safe) { assert(is_call(), "should be an address instruction here"); if (NativeCall::is_at(addr())) { NativeCall* nc = nativeCall_at(addr()); @@ -112,7 +112,7 @@ address Relocation::pd_get_address_from_code() { return MacroAssembler::pd_call_destination(addr()); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { if (NativeInstruction::maybe_cpool_ref(addr())) { address old_addr = old_addr_for(addr(), src, dest); MacroAssembler::pd_patch_instruction_size(addr(), MacroAssembler::target_addr_for_insn(old_addr)); diff --git a/src/hotspot/cpu/s390/relocInfo_s390.cpp b/src/hotspot/cpu/s390/relocInfo_s390.cpp index fdaf00e2bc34a..ad9a412d34aca 100644 --- a/src/hotspot/cpu/s390/relocInfo_s390.cpp +++ b/src/hotspot/cpu/s390/relocInfo_s390.cpp @@ -116,7 +116,7 @@ address Relocation::pd_call_destination(address orig_addr) { return (address) nativeMovConstReg_at(inst_addr)->data(); } -void Relocation::pd_set_call_destination(address x) { +void Relocation::pd_set_call_destination(address x, bool be_safe) { address inst_addr = addr(); if (NativeFarCall::is_far_call_at(inst_addr)) { @@ -169,7 +169,7 @@ address Relocation::pd_get_address_from_code() { return (address) (nativeMovConstReg_at(addr())->data()); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { } void metadata_Relocation::pd_fix_value(address x) { diff --git a/src/hotspot/cpu/x86/relocInfo_x86.cpp b/src/hotspot/cpu/x86/relocInfo_x86.cpp index a447c5aca9d92..f9109982477d5 100644 --- a/src/hotspot/cpu/x86/relocInfo_x86.cpp +++ b/src/hotspot/cpu/x86/relocInfo_x86.cpp @@ -113,7 +113,7 @@ address Relocation::pd_call_destination(address orig_addr) { } -void Relocation::pd_set_call_destination(address x) { +void Relocation::pd_set_call_destination(address x, bool be_safe) { NativeInstruction* ni = nativeInstruction_at(addr()); if (ni->is_call()) { nativeCall_at(addr())->set_destination(x); @@ -186,7 +186,7 @@ address Relocation::pd_get_address_from_code() { return *pd_address_in_code(); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { } void metadata_Relocation::pd_fix_value(address x) { diff --git a/src/hotspot/cpu/zero/relocInfo_zero.cpp b/src/hotspot/cpu/zero/relocInfo_zero.cpp index 647d5be31314c..12fc2a3f55287 100644 --- a/src/hotspot/cpu/zero/relocInfo_zero.cpp +++ b/src/hotspot/cpu/zero/relocInfo_zero.cpp @@ -38,7 +38,7 @@ address Relocation::pd_call_destination(address orig_addr) { return nullptr; } -void Relocation::pd_set_call_destination(address x) { +void Relocation::pd_set_call_destination(address x, bool be_safe) { ShouldNotCallThis(); } @@ -53,7 +53,8 @@ address* Relocation::pd_address_in_code() { } void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, - CodeBuffer* dst) { + CodeBuffer* dst, + bool is_nmethod_relocation) { ShouldNotCallThis(); } diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 81bfc932147a3..f22066707ad0f 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -804,7 +804,7 @@ void CodeBuffer::relocate_code_to(CodeBuffer* dest) const { { // Repair the pc relative information in the code after the move RelocIterator iter(dest_cs); while (iter.next()) { - iter.reloc()->fix_relocation_after_move(this, dest); + iter.reloc()->fix_relocation_after_move(this, dest, false); } } } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 108be59bf9274..3d160c039ba1f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1544,7 +1544,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { CodeBuffer src(this); CodeBuffer dst(nm_copy); while (iter.next()) { - iter.reloc()->fix_relocation_after_move(&src, &dst); + iter.reloc()->fix_relocation_after_move(&src, &dst, true); } nm_copy->clear_inline_caches(); @@ -1603,7 +1603,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { bool nmethod::is_relocatable() { #if INCLUDE_JVMCI if (jvmci_nmethod_data() != nullptr && jvmci_nmethod_data()->has_mirror()) { - return false; + return false; } #endif @@ -1634,6 +1634,25 @@ bool nmethod::is_relocatable() { } } +#ifdef AARCH64 + // Ensure all call instructions that might require trampolines include them. + // In debug builds, HotSpot intentionally reduces the maximum branch range + // to stress-test trampoline generation. This constraint may not be honored + // by JVMCI, so we explicitly verify compliance here before relocation. + RelocIterator iter(this); + while (iter.next()) { + if (iter.reloc()->is_call()) { + CallRelocation* call_reloc = (CallRelocation*) iter.reloc(); + if (NativeCall::is_call_at(call_reloc->addr())) { + NativeCall* call = nativeCall_at(call_reloc->addr()); + if (!MacroAssembler::is_always_within_branch_range(Address(call->destination())) && call->get_trampoline() == nullptr) { + return false; + } + } + } + } +#endif + return true; } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 9c62bb82e2e33..71a3e09554ae3 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -393,30 +393,32 @@ void Relocation::normalize_address(address& addr, const CodeSection* dest, bool void CallRelocation::set_destination(address x) { - pd_set_call_destination(x); + pd_set_call_destination(x, false); } -void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { // Usually a self-relative reference to an external routine. // On some platforms, the reference is absolute (not self-relative). // The enhanced use of pd_call_destination sorts this all out. address orig_addr = old_addr_for(addr(), src, dest); address callee = pd_call_destination(orig_addr); - if (src->contains(callee)) { - // If the original call is to an address in the src CodeBuffer (such as a stub call) - // the updated call should be to the corresponding address in dest CodeBuffer - ptrdiff_t offset = callee - orig_addr; - callee = addr() + offset; + if (is_nmethod_relocation) { + if (src->contains(callee)) { + // If the original call is to an address in the src CodeBuffer (such as a stub call) + // the updated call should be to the corresponding address in dest CodeBuffer + ptrdiff_t offset = callee - orig_addr; + callee = addr() + offset; + } } // Reassert the callee address, this time in the new copy of the code. - pd_set_call_destination(callee); + pd_set_call_destination(callee, is_nmethod_relocation); } #ifdef USE_TRAMPOLINE_STUB_FIX_OWNER -void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { // Finalize owner destination only for nmethods if (dest->blob() != nullptr) return; // We either relocate a nmethod residing in CodeCache or just generated code from CodeBuffer @@ -773,7 +775,7 @@ void static_stub_Relocation::clear_inline_cache() { } -void external_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void external_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { if (_target != nullptr) { // Probably this reference is absolute, not relative, so the following is // probably a no-op. @@ -796,7 +798,7 @@ address external_word_Relocation::target() { } -void internal_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { +void internal_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { address target = _target; if (target == nullptr) { target = new_addr_for(this->target(), src, dest); diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 714a964b28d28..12e2827d024d4 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -785,7 +785,7 @@ class Relocation { void pd_set_data_value (address x, bool verify_only = false); // a set or mem-ref void pd_verify_data_value (address x) { pd_set_data_value(x, true); } address pd_call_destination (address orig_addr = nullptr); - void pd_set_call_destination (address x); + void pd_set_call_destination (address x, bool be_safe); // this extracts the address of an address in the code stream instead of the reloc data address* pd_address_in_code (); @@ -860,7 +860,7 @@ class Relocation { // This method assumes that all virtual/static (inline) caches are cleared (since for static_call_type and // ic_call_type is not always position dependent (depending on the state of the cache)). However, this is // probably a reasonable assumption, since empty caches simplifies code reloacation. - virtual void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } + virtual void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { } }; @@ -950,7 +950,7 @@ class CallRelocation : public Relocation { address destination() { return pd_call_destination(); } void set_destination(address x); // pd_set_call_destination - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; address value() override { return destination(); } void set_value(address x) override { set_destination(x); } }; @@ -1262,7 +1262,7 @@ class runtime_call_w_cp_Relocation : public CallRelocation { class trampoline_stub_Relocation : public Relocation { #ifdef USE_TRAMPOLINE_STUB_FIX_OWNER void pd_fix_owner_after_move(); - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; #endif public: @@ -1334,7 +1334,7 @@ class external_word_Relocation : public DataRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; address target(); // if _target==nullptr, fetch addr from code stream address value() override { return target(); } }; @@ -1378,7 +1378,7 @@ class internal_word_Relocation : public DataRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; void fix_relocation_after_aot_load(address orig_base_addr, address current_base_addr); address target(); // if _target==nullptr, fetch addr from code stream @@ -1411,7 +1411,7 @@ class section_word_Relocation : public internal_word_Relocation { class poll_Relocation : public Relocation { bool is_data() override { return true; } - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; public: poll_Relocation(relocInfo::relocType type = relocInfo::poll_type) : Relocation(type) { } From a6302fdf5754b382702577e8e421c85a5fb9063c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 2 Jul 2025 21:01:23 +0000 Subject: [PATCH 085/103] Let trampolines fix their owners --- .../cpu/aarch64/nativeInst_aarch64.cpp | 2 +- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 14 ++++------- src/hotspot/cpu/arm/relocInfo_arm.cpp | 4 ++-- src/hotspot/cpu/ppc/relocInfo_ppc.cpp | 4 ++-- src/hotspot/cpu/riscv/relocInfo_riscv.cpp | 4 ++-- src/hotspot/cpu/s390/relocInfo_s390.cpp | 4 ++-- src/hotspot/cpu/x86/relocInfo_x86.cpp | 4 ++-- src/hotspot/cpu/zero/relocInfo_zero.cpp | 5 ++-- src/hotspot/share/asm/codeBuffer.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 12 +++++++++- src/hotspot/share/code/relocInfo.cpp | 23 +++++-------------- src/hotspot/share/code/relocInfo.hpp | 14 +++++------ 12 files changed, 42 insertions(+), 50 deletions(-) diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 84275a88e9a9b..0b05b4ac3e508 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -87,7 +87,7 @@ void NativeCall::set_destination_mt_safe(address dest) { // Patch the constant in the call's trampoline stub. address trampoline_stub_addr = get_trampoline(); - if (trampoline_stub_addr != nullptr && dest != trampoline_stub_addr) { + if (trampoline_stub_addr != nullptr) { assert (! is_NativeCallTrampolineStub_at(dest), "chained trampolines"); nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest); } diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 545d1f8494628..94694b58d2fae 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -77,21 +77,15 @@ address Relocation::pd_call_destination(address orig_addr) { } -void Relocation::pd_set_call_destination(address x, bool be_safe) { +void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { NativeCall* call = nativeCall_at(addr()); - if (be_safe) { - call->set_destination_mt_safe(x); - assert(pd_call_destination(addr()) == x || pd_call_destination(addr()) == call->get_trampoline(), "fail in reloc"); - } else { - call->set_destination(x); - assert(pd_call_destination(addr()) == x, "fail in reloc"); - } + call->set_destination(x); } else { MacroAssembler::pd_patch_instruction(addr(), x); - assert(pd_call_destination(addr()) == x, "fail in reloc"); } + assert(pd_call_destination(addr()) == x, "fail in reloc"); } void trampoline_stub_Relocation::pd_fix_owner_after_move() { @@ -114,7 +108,7 @@ address Relocation::pd_get_address_from_code() { return MacroAssembler::pd_call_destination(addr()); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { if (NativeInstruction::maybe_cpool_ref(addr())) { address old_addr = old_addr_for(addr(), src, dest); MacroAssembler::pd_patch_instruction(addr(), MacroAssembler::target_addr_for_insn(old_addr)); diff --git a/src/hotspot/cpu/arm/relocInfo_arm.cpp b/src/hotspot/cpu/arm/relocInfo_arm.cpp index 04890d58bd65a..2006be978bcdf 100644 --- a/src/hotspot/cpu/arm/relocInfo_arm.cpp +++ b/src/hotspot/cpu/arm/relocInfo_arm.cpp @@ -71,7 +71,7 @@ address Relocation::pd_call_destination(address orig_addr) { return nullptr; } -void Relocation::pd_set_call_destination(address x, bool be_safe) { +void Relocation::pd_set_call_destination(address x) { address pc = addr(); NativeInstruction* ni = nativeInstruction_at(pc); @@ -105,7 +105,7 @@ address Relocation::pd_get_address_from_code() { return *pd_address_in_code(); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } void metadata_Relocation::pd_fix_value(address x) { diff --git a/src/hotspot/cpu/ppc/relocInfo_ppc.cpp b/src/hotspot/cpu/ppc/relocInfo_ppc.cpp index 5c8d89ce634b0..559d30a8f23f7 100644 --- a/src/hotspot/cpu/ppc/relocInfo_ppc.cpp +++ b/src/hotspot/cpu/ppc/relocInfo_ppc.cpp @@ -73,7 +73,7 @@ address Relocation::pd_call_destination(address orig_addr) { } } -void Relocation::pd_set_call_destination(address x, bool be_safe) { +void Relocation::pd_set_call_destination(address x) { address inst_loc = addr(); if (NativeFarCall::is_far_call_at(inst_loc)) { @@ -99,7 +99,7 @@ address Relocation::pd_get_address_from_code() { return (address)(nativeMovConstReg_at(addr())->data()); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } void metadata_Relocation::pd_fix_value(address x) { diff --git a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp index b1bc9ecb82cfd..7bee372b0ef80 100644 --- a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp +++ b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp @@ -90,7 +90,7 @@ address Relocation::pd_call_destination(address orig_addr) { return MacroAssembler::pd_call_destination(addr()); } -void Relocation::pd_set_call_destination(address x, bool be_safe) { +void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be an address instruction here"); if (NativeCall::is_at(addr())) { NativeCall* nc = nativeCall_at(addr()); @@ -112,7 +112,7 @@ address Relocation::pd_get_address_from_code() { return MacroAssembler::pd_call_destination(addr()); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { if (NativeInstruction::maybe_cpool_ref(addr())) { address old_addr = old_addr_for(addr(), src, dest); MacroAssembler::pd_patch_instruction_size(addr(), MacroAssembler::target_addr_for_insn(old_addr)); diff --git a/src/hotspot/cpu/s390/relocInfo_s390.cpp b/src/hotspot/cpu/s390/relocInfo_s390.cpp index ad9a412d34aca..fdaf00e2bc34a 100644 --- a/src/hotspot/cpu/s390/relocInfo_s390.cpp +++ b/src/hotspot/cpu/s390/relocInfo_s390.cpp @@ -116,7 +116,7 @@ address Relocation::pd_call_destination(address orig_addr) { return (address) nativeMovConstReg_at(inst_addr)->data(); } -void Relocation::pd_set_call_destination(address x, bool be_safe) { +void Relocation::pd_set_call_destination(address x) { address inst_addr = addr(); if (NativeFarCall::is_far_call_at(inst_addr)) { @@ -169,7 +169,7 @@ address Relocation::pd_get_address_from_code() { return (address) (nativeMovConstReg_at(addr())->data()); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } void metadata_Relocation::pd_fix_value(address x) { diff --git a/src/hotspot/cpu/x86/relocInfo_x86.cpp b/src/hotspot/cpu/x86/relocInfo_x86.cpp index f9109982477d5..a447c5aca9d92 100644 --- a/src/hotspot/cpu/x86/relocInfo_x86.cpp +++ b/src/hotspot/cpu/x86/relocInfo_x86.cpp @@ -113,7 +113,7 @@ address Relocation::pd_call_destination(address orig_addr) { } -void Relocation::pd_set_call_destination(address x, bool be_safe) { +void Relocation::pd_set_call_destination(address x) { NativeInstruction* ni = nativeInstruction_at(addr()); if (ni->is_call()) { nativeCall_at(addr())->set_destination(x); @@ -186,7 +186,7 @@ address Relocation::pd_get_address_from_code() { return *pd_address_in_code(); } -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } void metadata_Relocation::pd_fix_value(address x) { diff --git a/src/hotspot/cpu/zero/relocInfo_zero.cpp b/src/hotspot/cpu/zero/relocInfo_zero.cpp index 12fc2a3f55287..647d5be31314c 100644 --- a/src/hotspot/cpu/zero/relocInfo_zero.cpp +++ b/src/hotspot/cpu/zero/relocInfo_zero.cpp @@ -38,7 +38,7 @@ address Relocation::pd_call_destination(address orig_addr) { return nullptr; } -void Relocation::pd_set_call_destination(address x, bool be_safe) { +void Relocation::pd_set_call_destination(address x) { ShouldNotCallThis(); } @@ -53,8 +53,7 @@ address* Relocation::pd_address_in_code() { } void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, - CodeBuffer* dst, - bool is_nmethod_relocation) { + CodeBuffer* dst) { ShouldNotCallThis(); } diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index f22066707ad0f..81bfc932147a3 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -804,7 +804,7 @@ void CodeBuffer::relocate_code_to(CodeBuffer* dest) const { { // Repair the pc relative information in the code after the move RelocIterator iter(dest_cs); while (iter.next()) { - iter.reloc()->fix_relocation_after_move(this, dest, false); + iter.reloc()->fix_relocation_after_move(this, dest); } } } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 3d160c039ba1f..d8418e81fc2a2 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1544,7 +1544,17 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { CodeBuffer src(this); CodeBuffer dst(nm_copy); while (iter.next()) { - iter.reloc()->fix_relocation_after_move(&src, &dst, true); +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER + // Let the trampoline stub relocation fix the owner if it exists + if (iter.reloc()->is_call()) { + address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), nm_copy); + if (trampoline != nullptr) { + continue; + } + } +#endif + + iter.reloc()->fix_relocation_after_move(&src, &dst); } nm_copy->clear_inline_caches(); diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 71a3e09554ae3..02a1e5faf16a3 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -393,32 +393,21 @@ void Relocation::normalize_address(address& addr, const CodeSection* dest, bool void CallRelocation::set_destination(address x) { - pd_set_call_destination(x, false); + pd_set_call_destination(x); } -void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { // Usually a self-relative reference to an external routine. // On some platforms, the reference is absolute (not self-relative). // The enhanced use of pd_call_destination sorts this all out. address orig_addr = old_addr_for(addr(), src, dest); address callee = pd_call_destination(orig_addr); - - if (is_nmethod_relocation) { - if (src->contains(callee)) { - // If the original call is to an address in the src CodeBuffer (such as a stub call) - // the updated call should be to the corresponding address in dest CodeBuffer - ptrdiff_t offset = callee - orig_addr; - callee = addr() + offset; - } - } - // Reassert the callee address, this time in the new copy of the code. - pd_set_call_destination(callee, is_nmethod_relocation); + pd_set_call_destination(callee); } - #ifdef USE_TRAMPOLINE_STUB_FIX_OWNER -void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { // Finalize owner destination only for nmethods if (dest->blob() != nullptr) return; // We either relocate a nmethod residing in CodeCache or just generated code from CodeBuffer @@ -775,7 +764,7 @@ void static_stub_Relocation::clear_inline_cache() { } -void external_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void external_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { if (_target != nullptr) { // Probably this reference is absolute, not relative, so the following is // probably a no-op. @@ -798,7 +787,7 @@ address external_word_Relocation::target() { } -void internal_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { +void internal_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { address target = _target; if (target == nullptr) { target = new_addr_for(this->target(), src, dest); diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 12e2827d024d4..714a964b28d28 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -785,7 +785,7 @@ class Relocation { void pd_set_data_value (address x, bool verify_only = false); // a set or mem-ref void pd_verify_data_value (address x) { pd_set_data_value(x, true); } address pd_call_destination (address orig_addr = nullptr); - void pd_set_call_destination (address x, bool be_safe); + void pd_set_call_destination (address x); // this extracts the address of an address in the code stream instead of the reloc data address* pd_address_in_code (); @@ -860,7 +860,7 @@ class Relocation { // This method assumes that all virtual/static (inline) caches are cleared (since for static_call_type and // ic_call_type is not always position dependent (depending on the state of the cache)). However, this is // probably a reasonable assumption, since empty caches simplifies code reloacation. - virtual void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) { } + virtual void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } }; @@ -950,7 +950,7 @@ class CallRelocation : public Relocation { address destination() { return pd_call_destination(); } void set_destination(address x); // pd_set_call_destination - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; address value() override { return destination(); } void set_value(address x) override { set_destination(x); } }; @@ -1262,7 +1262,7 @@ class runtime_call_w_cp_Relocation : public CallRelocation { class trampoline_stub_Relocation : public Relocation { #ifdef USE_TRAMPOLINE_STUB_FIX_OWNER void pd_fix_owner_after_move(); - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; #endif public: @@ -1334,7 +1334,7 @@ class external_word_Relocation : public DataRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; address target(); // if _target==nullptr, fetch addr from code stream address value() override { return target(); } }; @@ -1378,7 +1378,7 @@ class internal_word_Relocation : public DataRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; void fix_relocation_after_aot_load(address orig_base_addr, address current_base_addr); address target(); // if _target==nullptr, fetch addr from code stream @@ -1411,7 +1411,7 @@ class section_word_Relocation : public internal_word_Relocation { class poll_Relocation : public Relocation { bool is_data() override { return true; } - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest, bool is_nmethod_relocation) override; + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; public: poll_Relocation(relocInfo::relocType type = relocInfo::poll_type) : Relocation(type) { } From c3245fb7eab068f63e80642593c72e1a348f8c62 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 2 Jul 2025 21:10:35 +0000 Subject: [PATCH 086/103] Enclose ImmutableDataReferencesCounterSize in parentheses --- src/hotspot/share/code/nmethod.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 861157d061dbe..422cb987b0ef3 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -169,7 +169,7 @@ class nmethod : public CodeBlob { friend class JVMCINMethodData; friend class DeoptimizationScope; - #define ImmutableDataReferencesCounterSize (int)sizeof(int) + #define ImmutableDataReferencesCounterSize ((int)sizeof(int)) private: From 0f4ff9646d1f7f43214c5ccd4bbe572fffd08d16 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 2 Jul 2025 22:20:00 +0000 Subject: [PATCH 087/103] Update justification for skipping CallRelocation --- src/hotspot/share/code/nmethod.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index d8418e81fc2a2..60a1354b9b19e 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1545,7 +1545,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { CodeBuffer dst(nm_copy); while (iter.next()) { #ifdef USE_TRAMPOLINE_STUB_FIX_OWNER - // Let the trampoline stub relocation fix the owner if it exists + // Direct calls may no longer be in range and the use of a trampoline may now be required. + // Instead allow the trapoline relocations to update their owner and perform the necessary checks. if (iter.reloc()->is_call()) { address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), nm_copy); if (trampoline != nullptr) { From 66d73c167270b54a155b293f1fbeb8b08ea796e5 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 8 Jul 2025 20:00:16 +0000 Subject: [PATCH 088/103] Typo --- src/hotspot/share/code/nmethod.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index b316a7e405ad3..5ba6c39f62c28 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1538,7 +1538,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { while (iter.next()) { #ifdef USE_TRAMPOLINE_STUB_FIX_OWNER // Direct calls may no longer be in range and the use of a trampoline may now be required. - // Instead allow the trapoline relocations to update their owner and perform the necessary checks. + // Instead, allow trampoline relocations to update their owners and perform the necessary checks. if (iter.reloc()->is_call()) { address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), nm_copy); if (trampoline != nullptr) { From 68a987669768dfda39d54998775c1efcea90d9c3 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 14 Jul 2025 19:33:37 +0000 Subject: [PATCH 089/103] Remove aarch64 trampoline check --- src/hotspot/share/code/nmethod.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5ba6c39f62c28..3b812a5c53121 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1637,25 +1637,6 @@ bool nmethod::is_relocatable() { } } -#ifdef AARCH64 - // Ensure all call instructions that might require trampolines include them. - // In debug builds, HotSpot intentionally reduces the maximum branch range - // to stress-test trampoline generation. This constraint may not be honored - // by JVMCI, so we explicitly verify compliance here before relocation. - RelocIterator iter(this); - while (iter.next()) { - if (iter.reloc()->is_call()) { - CallRelocation* call_reloc = (CallRelocation*) iter.reloc(); - if (NativeCall::is_call_at(call_reloc->addr())) { - NativeCall* call = nativeCall_at(call_reloc->addr()); - if (!MacroAssembler::is_always_within_branch_range(Address(call->destination())) && call->get_trampoline() == nullptr) { - return false; - } - } - } - } -#endif - return true; } From 371e13037954b99e73bb31f543c558285f5225d1 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 14 Jul 2025 20:01:20 +0000 Subject: [PATCH 090/103] Add nmethod copy constructor --- src/hotspot/share/code/nmethod.cpp | 114 ++++++++++++++--------------- src/hotspot/share/code/nmethod.hpp | 2 +- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 3b812a5c53121..e05052f9abbe6 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1389,57 +1389,57 @@ nmethod::nmethod( } -nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_header_size) +nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm._header_size) { - if (nm->_oop_maps != nullptr) { - _oop_maps = nm->_oop_maps->clone(); + if (nm._oop_maps != nullptr) { + _oop_maps = nm._oop_maps->clone(); } else { _oop_maps = nullptr; } - _size = nm->_size; - _relocation_size = nm->_relocation_size; - _content_offset = nm->_content_offset; - _code_offset = nm->_code_offset; - _data_offset = nm->_data_offset; - _frame_size = nm->_frame_size; + _size = nm._size; + _relocation_size = nm._relocation_size; + _content_offset = nm._content_offset; + _code_offset = nm._code_offset; + _data_offset = nm._data_offset; + _frame_size = nm._frame_size; - S390_ONLY( _ctable_offset = nm->_ctable_offset; ) + S390_ONLY( _ctable_offset = nm._ctable_offset; ) - _header_size = nm->_header_size; - _frame_complete_offset = nm->_frame_complete_offset; + _header_size = nm._header_size; + _frame_complete_offset = nm._frame_complete_offset; - _kind = nm->_kind; + _kind = nm._kind; - _caller_must_gc_arguments = nm->_caller_must_gc_arguments; + _caller_must_gc_arguments = nm._caller_must_gc_arguments; #ifndef PRODUCT - _asm_remarks.share(nm->_asm_remarks); - _dbg_strings.share(nm->_dbg_strings); + _asm_remarks.share(nm._asm_remarks); + _dbg_strings.share(nm._dbg_strings); #endif // Allocate memory and copy mutable data to C heap - _mutable_data_size = nm->_mutable_data_size; + _mutable_data_size = nm._mutable_data_size; if (_mutable_data_size > 0) { _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); if (_mutable_data == nullptr) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "nmethod: no space for mutable data"); } - memcpy(mutable_data_begin(), nm->mutable_data_begin(), nm->mutable_data_size()); + memcpy(mutable_data_begin(), nm.mutable_data_begin(), nm.mutable_data_size()); } else { _mutable_data = nullptr; } _deoptimization_generation = 0; _gc_epoch = CodeCache::gc_epoch(); - _method = nm->_method; + _method = nm._method; _osr_link = nullptr; // Increment number of references to immutable data to share it between nmethods - _immutable_data_size = nm->_immutable_data_size; + _immutable_data_size = nm._immutable_data_size; if (_immutable_data_size > 0) { - _immutable_data = nm->_immutable_data; + _immutable_data = nm._immutable_data; set_immutable_data_references_counter(get_immutable_data_references_counter() + 1); } else { _immutable_data = blob_end(); @@ -1451,54 +1451,54 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h _oops_do_mark_link = nullptr; _compiled_ic_data = nullptr; - if (nm->_osr_entry_point != nullptr) { - _osr_entry_point = (nm->_osr_entry_point - (address) nm) + (address) this; + if (nm._osr_entry_point != nullptr) { + _osr_entry_point = (nm._osr_entry_point - (address) &nm) + (address) this; } else { _osr_entry_point = nullptr; } - _entry_offset = nm->_entry_offset; - _verified_entry_offset = nm->_verified_entry_offset; - _entry_bci = nm->_entry_bci; + _entry_offset = nm._entry_offset; + _verified_entry_offset = nm._verified_entry_offset; + _entry_bci = nm._entry_bci; - _skipped_instructions_size = nm->_skipped_instructions_size; - _stub_offset = nm->_stub_offset; - _exception_offset = nm->_exception_offset; - _deopt_handler_offset = nm->_deopt_handler_offset; - _deopt_mh_handler_offset = nm->_deopt_mh_handler_offset; - _unwind_handler_offset = nm->_unwind_handler_offset; - _num_stack_arg_slots = nm->_num_stack_arg_slots; - _oops_size = nm->_oops_size; + _skipped_instructions_size = nm._skipped_instructions_size; + _stub_offset = nm._stub_offset; + _exception_offset = nm._exception_offset; + _deopt_handler_offset = nm._deopt_handler_offset; + _deopt_mh_handler_offset = nm._deopt_mh_handler_offset; + _unwind_handler_offset = nm._unwind_handler_offset; + _num_stack_arg_slots = nm._num_stack_arg_slots; + _oops_size = nm._oops_size; #if INCLUDE_JVMCI - _metadata_size = nm->_metadata_size; + _metadata_size = nm._metadata_size; #endif - _nul_chk_table_offset = nm->_nul_chk_table_offset; - _handler_table_offset = nm->_handler_table_offset; - _scopes_pcs_offset = nm->_scopes_pcs_offset; - _scopes_data_offset = nm->_scopes_data_offset; + _nul_chk_table_offset = nm._nul_chk_table_offset; + _handler_table_offset = nm._handler_table_offset; + _scopes_pcs_offset = nm._scopes_pcs_offset; + _scopes_data_offset = nm._scopes_data_offset; #if INCLUDE_JVMCI - _speculations_offset = nm->_speculations_offset; + _speculations_offset = nm._speculations_offset; #endif - _orig_pc_offset = nm->_orig_pc_offset; - _compile_id = nm->_compile_id; - _comp_level = nm->_comp_level; - _compiler_type = nm->_compiler_type; - _is_unloading_state = nm->_is_unloading_state; + _orig_pc_offset = nm._orig_pc_offset; + _compile_id = nm._compile_id; + _comp_level = nm._comp_level; + _compiler_type = nm._compiler_type; + _is_unloading_state = nm._is_unloading_state; _state = not_installed; - _has_unsafe_access = nm->_has_unsafe_access; - _has_method_handle_invokes = nm->_has_method_handle_invokes; - _has_wide_vectors = nm->_has_wide_vectors; - _has_monitors = nm->_has_monitors; - _has_scoped_access = nm->_has_scoped_access; - _has_flushed_dependencies = nm->_has_flushed_dependencies; - _is_unlinked = nm->_is_unlinked; - _load_reported = nm->_load_reported; + _has_unsafe_access = nm._has_unsafe_access; + _has_method_handle_invokes = nm._has_method_handle_invokes; + _has_wide_vectors = nm._has_wide_vectors; + _has_monitors = nm._has_monitors; + _has_scoped_access = nm._has_scoped_access; + _has_flushed_dependencies = nm._has_flushed_dependencies; + _is_unlinked = nm._is_unlinked; + _load_reported = nm._load_reported; - _deoptimization_status = nm->_deoptimization_status; + _deoptimization_status = nm._deoptimization_status; - if (nm->_pc_desc_container != nullptr) { + if (nm._pc_desc_container != nullptr) { _pc_desc_container = new PcDescContainer(scopes_pcs_begin()); } else { _pc_desc_container = nullptr; @@ -1511,7 +1511,7 @@ nmethod::nmethod(nmethod* nm) : CodeBlob(nm->_name, nm->_kind, nm->_size, nm->_h // - Exception handler // - Stub code // - OOP table - memcpy(consts_begin(), nm->consts_begin(), nm->data_end() - nm->consts_begin()); + memcpy(consts_begin(), nm.consts_begin(), nm.data_end() - nm.consts_begin()); post_init(); } @@ -1525,7 +1525,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); run_nmethod_entry_barrier(); - nmethod* nm_copy = new (size(), code_blob_type) nmethod(this); + nmethod* nm_copy = new (size(), code_blob_type) nmethod(*this); if (nm_copy == nullptr) { return nullptr; diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 146bf2166e33a..93c416f8832ec 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -338,7 +338,7 @@ class nmethod : public CodeBlob { #endif ); - nmethod(nmethod* nm); + nmethod(const nmethod &nm); // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); From 36834705de3b18f6f1a0a410254d5d9ac29dc4c4 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 14 Jul 2025 20:31:11 +0000 Subject: [PATCH 091/103] Revert is_always_within_branch_range changes --- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 2 +- src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 8a0d92806ad85..44dbf3692f604 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -856,7 +856,7 @@ void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, in } // Check the entry target is always reachable from any branch. -bool MacroAssembler::is_always_within_branch_range(Address entry) { +static bool is_always_within_branch_range(Address entry) { if (AOTCodeCache::is_on_for_dump()) { return false; } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index e75f9baffd861..fe2440fd3fd00 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -105,9 +105,6 @@ class MacroAssembler: public Assembler { static KlassDecodeMode klass_decode_mode(); public: - // Check the entry target is always reachable from any branch. - static bool is_always_within_branch_range(Address entry); - // Checks the decode mode and returns false if not compatible with preferred decoding mode. static bool check_klass_decode_mode(address base, int shift, const size_t range); From 1dcf47e4e2a6223abfc8a6b6fc0de6fab1b884f6 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 17 Jul 2025 16:15:55 +0000 Subject: [PATCH 092/103] Require caller to hold locks --- src/hotspot/share/code/nmethod.cpp | 16 ++++++++-------- src/hotspot/share/prims/whitebox.cpp | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index e05052f9abbe6..22e83876f810e 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1517,13 +1517,16 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm. } nmethod* nmethod::relocate(CodeBlobType code_blob_type) { + // Locks required to be held by caller to ensure the nmethod + // is not modified or purged from code cache during relocation + assert_lock_strong(CompiledIC_lock); + assert_lock_strong(Compile_lock); + assert_lock_strong(CodeCache_lock); + if (!is_relocatable()) { return nullptr; } - MutexLocker ml_Compile_lock(Compile_lock); - MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); - run_nmethod_entry_barrier(); nmethod* nm_copy = new (size(), code_blob_type) nmethod(*this); @@ -1630,11 +1633,8 @@ bool nmethod::is_relocatable() { return false; } - { - CompiledICLocker ic_locker(this); - if (has_evol_metadata()) { - return false; - } + if (has_evol_metadata()) { + return false; } return true; diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 394edbe574894..1e5384b6e77f6 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1647,6 +1647,9 @@ WB_ENTRY(void, WB_RelocateNMethodFromMethod(JNIEnv* env, jobject o, jobject meth ResourceMark rm(THREAD); jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION(env); + MutexLocker ml_Compile_lock(Compile_lock); + MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); nmethod* code = mh->code(); if (code != nullptr) { @@ -1657,6 +1660,9 @@ WB_END WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, jint blob_type)) ResourceMark rm(THREAD); CHECK_JNI_EXCEPTION(env); + MutexLocker ml_Compile_lock(Compile_lock); + MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); nmethod* code = (nmethod*) addr; if (code != nullptr) { code->relocate(static_cast(blob_type)); From 4d782afd04dc263abddadd2a46d3157a6a8683ab Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 21 Jul 2025 23:32:50 +0000 Subject: [PATCH 093/103] Reorder is_relocatable checks --- src/hotspot/share/code/nmethod.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 22e83876f810e..3906d31d1b413 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1607,29 +1607,29 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { } bool nmethod::is_relocatable() { -#if INCLUDE_JVMCI - if (jvmci_nmethod_data() != nullptr && jvmci_nmethod_data()->has_mirror()) { + if (!is_java_method()) { return false; } -#endif - if (is_marked_for_deoptimization()) { + if (!is_in_use()) { return false; } - if (is_unloading()) { + if (is_osr_method()) { return false; } - if (is_osr_method()) { + if (is_marked_for_deoptimization()) { return false; } - if (!is_java_method()) { +#if INCLUDE_JVMCI + if (jvmci_nmethod_data() != nullptr && jvmci_nmethod_data()->has_mirror()) { return false; } +#endif - if (!is_in_use()) { + if (is_unloading()) { return false; } From fbfa27b447e60b6f65cdc4b8730d389a25697261 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 22 Jul 2025 00:07:31 +0000 Subject: [PATCH 094/103] Add assert before freeing immutable data --- src/hotspot/share/code/nmethod.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 3906d31d1b413..daa01b59a96ac 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1154,14 +1154,14 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, int immutable_data_size = adjust_pcs_size(debug_info->pcs_size()) - + align_up((int)dependencies->size_in_bytes() , oopSize) - + align_up(handler_table->size_in_bytes() , oopSize) - + align_up(nul_chk_table->size_in_bytes() , oopSize) + + align_up((int)dependencies->size_in_bytes(), oopSize) + + align_up(handler_table->size_in_bytes() , oopSize) + + align_up(nul_chk_table->size_in_bytes() , oopSize) #if INCLUDE_JVMCI - + align_up(speculations_len , oopSize) + + align_up(speculations_len , oopSize) #endif - + align_up(debug_info->data_size() , oopSize) - + align_up(ImmutableDataReferencesCounterSize , oopSize); + + align_up(debug_info->data_size() , oopSize) + + align_up(ImmutableDataReferencesCounterSize, oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -2448,11 +2448,14 @@ void nmethod::purge(bool unregister_nmethod) { delete[] _compiled_ic_data; if (_immutable_data != blob_end()) { + int reference_count = get_immutable_data_references_counter(); + assert(reference_count > 0, "immutable data has no references"); + + set_immutable_data_references_counter(reference_count - 1); + // Free memory if this is the last nmethod referencing immutable data - if (get_immutable_data_references_counter() == 1) { + if (reference_count == 0) { os::free(_immutable_data); - } else { - set_immutable_data_references_counter(get_immutable_data_references_counter() - 1); } _immutable_data = blob_end(); // Valid not null address From 27991b2029ad0d0b417ef14175b2d0cbdb7c5224 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 22 Jul 2025 00:08:01 +0000 Subject: [PATCH 095/103] Rename method to nm --- src/hotspot/share/code/codeBehaviours.cpp | 10 +++++----- src/hotspot/share/code/codeBehaviours.hpp | 12 ++++++------ src/hotspot/share/code/compiledIC.cpp | 4 ++-- src/hotspot/share/code/compiledIC.hpp | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/code/codeBehaviours.cpp b/src/hotspot/share/code/codeBehaviours.cpp index 99e7f19ff9ba7..e077f5c8ae461 100644 --- a/src/hotspot/share/code/codeBehaviours.cpp +++ b/src/hotspot/share/code/codeBehaviours.cpp @@ -29,18 +29,18 @@ CompiledICProtectionBehaviour* CompiledICProtectionBehaviour::_current = nullptr; -bool DefaultICProtectionBehaviour::lock(nmethod* method) { - if (is_safe(method)) { +bool DefaultICProtectionBehaviour::lock(nmethod* nm) { + if (is_safe(nm)) { return false; } CompiledIC_lock->lock_without_safepoint_check(); return true; } -void DefaultICProtectionBehaviour::unlock(nmethod* method) { +void DefaultICProtectionBehaviour::unlock(nmethod* nm) { CompiledIC_lock->unlock(); } -bool DefaultICProtectionBehaviour::is_safe(nmethod* method) { - return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self() || method->is_not_installed(); +bool DefaultICProtectionBehaviour::is_safe(nmethod* nm) { + return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self() || nm->is_not_installed(); } diff --git a/src/hotspot/share/code/codeBehaviours.hpp b/src/hotspot/share/code/codeBehaviours.hpp index 0350f5752f696..96a38fffc30e0 100644 --- a/src/hotspot/share/code/codeBehaviours.hpp +++ b/src/hotspot/share/code/codeBehaviours.hpp @@ -33,18 +33,18 @@ class CompiledICProtectionBehaviour { static CompiledICProtectionBehaviour* _current; public: - virtual bool lock(nmethod* method) = 0; - virtual void unlock(nmethod* method) = 0; - virtual bool is_safe(nmethod* method) = 0; + virtual bool lock(nmethod* nm) = 0; + virtual void unlock(nmethod* nm) = 0; + virtual bool is_safe(nmethod* nm) = 0; static CompiledICProtectionBehaviour* current() { return _current; } static void set_current(CompiledICProtectionBehaviour* current) { _current = current; } }; class DefaultICProtectionBehaviour: public CompiledICProtectionBehaviour, public CHeapObj { - virtual bool lock(nmethod* method); - virtual void unlock(nmethod* method); - virtual bool is_safe(nmethod* method); + virtual bool lock(nmethod* nm); + virtual void unlock(nmethod* nm); + virtual bool is_safe(nmethod* nm); }; #endif // SHARE_CODE_CODEBEHAVIOURS_HPP diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 2547b8711db16..7490d68af02b1 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -55,8 +55,8 @@ CompiledICLocker::~CompiledICLocker() { } } -bool CompiledICLocker::is_safe(nmethod* method) { - return CompiledICProtectionBehaviour::current()->is_safe(method); +bool CompiledICLocker::is_safe(nmethod* nm) { + return CompiledICProtectionBehaviour::current()->is_safe(nm); } bool CompiledICLocker::is_safe(address code) { diff --git a/src/hotspot/share/code/compiledIC.hpp b/src/hotspot/share/code/compiledIC.hpp index 624c1b428de79..db8a0860b39d7 100644 --- a/src/hotspot/share/code/compiledIC.hpp +++ b/src/hotspot/share/code/compiledIC.hpp @@ -50,7 +50,7 @@ class CompiledICLocker: public StackObj { public: CompiledICLocker(nmethod* method); ~CompiledICLocker(); - static bool is_safe(nmethod* method); + static bool is_safe(nmethod* nm); static bool is_safe(address code); }; From b257ea5d508c7710226cfc04177d72407f53ebc8 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 22 Jul 2025 00:51:55 +0000 Subject: [PATCH 096/103] Update NMethod.java with immutable data changes --- .../classes/sun/jvm/hotspot/code/NMethod.java | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index a3228765e910d..f4b52434944cc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -37,6 +37,7 @@ public class NMethod extends CodeBlob { private static long pcDescSize; + private static long immutableDataReferencesCounterSize; private static AddressField methodField; /** != InvocationEntryBci if this nmethod is an on-stack replacement method */ private static CIntegerField entryBCIField; @@ -79,25 +80,26 @@ public void update(Observable o, Object data) { private static void initialize(TypeDataBase db) { Type type = db.lookupType("nmethod"); - methodField = type.getAddressField("_method"); - entryBCIField = type.getCIntegerField("_entry_bci"); - osrLinkField = type.getAddressField("_osr_link"); - immutableDataField = type.getAddressField("_immutable_data"); - immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); - exceptionOffsetField = type.getCIntegerField("_exception_offset"); - deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); - deoptMhHandlerOffsetField = type.getCIntegerField("_deopt_mh_handler_offset"); - origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); - stubOffsetField = type.getCIntegerField("_stub_offset"); - scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); - scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); - handlerTableOffsetField = new CIntField(type.getCIntegerField("_handler_table_offset"), 0); - nulChkTableOffsetField = new CIntField(type.getCIntegerField("_nul_chk_table_offset"), 0); - entryOffsetField = new CIntField(type.getCIntegerField("_entry_offset"), 0); - verifiedEntryOffsetField = new CIntField(type.getCIntegerField("_verified_entry_offset"), 0); - osrEntryPointField = type.getAddressField("_osr_entry_point"); - compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); - pcDescSize = db.lookupType("PcDesc").getSize(); + methodField = type.getAddressField("_method"); + entryBCIField = type.getCIntegerField("_entry_bci"); + osrLinkField = type.getAddressField("_osr_link"); + immutableDataField = type.getAddressField("_immutable_data"); + immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); + exceptionOffsetField = type.getCIntegerField("_exception_offset"); + deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); + deoptMhHandlerOffsetField = type.getCIntegerField("_deopt_mh_handler_offset"); + origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); + stubOffsetField = type.getCIntegerField("_stub_offset"); + scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); + scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); + handlerTableOffsetField = new CIntField(type.getCIntegerField("_handler_table_offset"), 0); + nulChkTableOffsetField = new CIntField(type.getCIntegerField("_nul_chk_table_offset"), 0); + entryOffsetField = new CIntField(type.getCIntegerField("_entry_offset"), 0); + verifiedEntryOffsetField = new CIntField(type.getCIntegerField("_verified_entry_offset"), 0); + osrEntryPointField = type.getAddressField("_osr_entry_point"); + compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); + pcDescSize = db.lookupType("PcDesc").getSize(); + immutableDataReferencesCounterSize = VM.getVM().getIntSize(); } public NMethod(Address addr) { @@ -142,7 +144,7 @@ public Method getMethod() { public Address scopesDataBegin() { return immutableDataBegin().addOffsetTo(getScopesDataOffset()); } public Address scopesDataEnd() { return immutableDataBegin().addOffsetTo(getScopesPCsOffset()); } public Address scopesPCsBegin() { return immutableDataBegin().addOffsetTo(getScopesPCsOffset()); } - public Address scopesPCsEnd() { return immutableDataEnd(); } + public Address scopesPCsEnd() { return immutableDataEnd().addOffsetTo(-immutableDataReferencesCounterSize); } public Address metadataBegin() { return mutableDataBegin().addOffsetTo(getRelocationSize()); } public Address metadataEnd() { return mutableDataEnd(); } @@ -172,7 +174,8 @@ public int immutableDataSize() { scopesPCsSize() + dependenciesSize() + handlerTableSize() + - nulChkTableSize(); + nulChkTableSize() + + (int) immutableDataReferencesCounterSize; } public boolean constantsContains (Address addr) { return constantsBegin() .lessThanOrEqual(addr) && constantsEnd() .greaterThan(addr); } From 1b001df870e4c342c5d68810911e6aefb597a744 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 22 Jul 2025 01:01:58 +0000 Subject: [PATCH 097/103] Fix spacing --- .../classes/sun/jvm/hotspot/code/NMethod.java | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index f4b52434944cc..cead36ef8ba10 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -80,26 +80,26 @@ public void update(Observable o, Object data) { private static void initialize(TypeDataBase db) { Type type = db.lookupType("nmethod"); - methodField = type.getAddressField("_method"); - entryBCIField = type.getCIntegerField("_entry_bci"); - osrLinkField = type.getAddressField("_osr_link"); - immutableDataField = type.getAddressField("_immutable_data"); - immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); - exceptionOffsetField = type.getCIntegerField("_exception_offset"); - deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); - deoptMhHandlerOffsetField = type.getCIntegerField("_deopt_mh_handler_offset"); - origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); - stubOffsetField = type.getCIntegerField("_stub_offset"); - scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); - scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); - handlerTableOffsetField = new CIntField(type.getCIntegerField("_handler_table_offset"), 0); - nulChkTableOffsetField = new CIntField(type.getCIntegerField("_nul_chk_table_offset"), 0); - entryOffsetField = new CIntField(type.getCIntegerField("_entry_offset"), 0); - verifiedEntryOffsetField = new CIntField(type.getCIntegerField("_verified_entry_offset"), 0); - osrEntryPointField = type.getAddressField("_osr_entry_point"); - compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); - pcDescSize = db.lookupType("PcDesc").getSize(); - immutableDataReferencesCounterSize = VM.getVM().getIntSize(); + methodField = type.getAddressField("_method"); + entryBCIField = type.getCIntegerField("_entry_bci"); + osrLinkField = type.getAddressField("_osr_link"); + immutableDataField = type.getAddressField("_immutable_data"); + immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); + exceptionOffsetField = type.getCIntegerField("_exception_offset"); + deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); + deoptMhHandlerOffsetField = type.getCIntegerField("_deopt_mh_handler_offset"); + origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); + stubOffsetField = type.getCIntegerField("_stub_offset"); + scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); + scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); + handlerTableOffsetField = new CIntField(type.getCIntegerField("_handler_table_offset"), 0); + nulChkTableOffsetField = new CIntField(type.getCIntegerField("_nul_chk_table_offset"), 0); + entryOffsetField = new CIntField(type.getCIntegerField("_entry_offset"), 0); + verifiedEntryOffsetField = new CIntField(type.getCIntegerField("_verified_entry_offset"), 0); + osrEntryPointField = type.getAddressField("_osr_entry_point"); + compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); + pcDescSize = db.lookupType("PcDesc").getSize(); + immutableDataReferencesCounterSize = VM.getVM().getIntSize(); } public NMethod(Address addr) { From d4e3dd31864f9d7cf4dcaae21c1318f80bd37d2e Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 24 Jul 2025 01:03:48 +0000 Subject: [PATCH 098/103] Use CompiledICLocker instead of CompiledIC_lock --- src/hotspot/share/code/nmethod.cpp | 4 ++-- src/hotspot/share/prims/whitebox.cpp | 13 +++++++------ .../compiler/whitebox/StressNMethodRelocation.java | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index daa01b59a96ac..231e142c284c2 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1519,9 +1519,9 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm. nmethod* nmethod::relocate(CodeBlobType code_blob_type) { // Locks required to be held by caller to ensure the nmethod // is not modified or purged from code cache during relocation - assert_lock_strong(CompiledIC_lock); - assert_lock_strong(Compile_lock); assert_lock_strong(CodeCache_lock); + assert_lock_strong(Compile_lock); + assert(CompiledICLocker::is_safe(this), "mt unsafe call"); if (!is_relocatable()) { return nullptr; diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 1e5384b6e77f6..d6cf9aa905936 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -39,6 +39,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" +#include "code/compiledIC.hpp" #include "compiler/compilationPolicy.hpp" #include "compiler/compilerOracle.hpp" #include "compiler/directivesParser.hpp" @@ -1647,12 +1648,12 @@ WB_ENTRY(void, WB_RelocateNMethodFromMethod(JNIEnv* env, jobject o, jobject meth ResourceMark rm(THREAD); jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION(env); - MutexLocker ml_Compile_lock(Compile_lock); - MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); - MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); nmethod* code = mh->code(); if (code != nullptr) { + MutexLocker ml_Compile_lock(Compile_lock); + CompiledICLocker ic_locker(code); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); code->relocate(static_cast(blob_type)); } WB_END @@ -1660,11 +1661,11 @@ WB_END WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, jint blob_type)) ResourceMark rm(THREAD); CHECK_JNI_EXCEPTION(env); - MutexLocker ml_Compile_lock(Compile_lock); - MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); - MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); nmethod* code = (nmethod*) addr; if (code != nullptr) { + MutexLocker ml_Compile_lock(Compile_lock); + CompiledICLocker ic_locker(code); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); code->relocate(static_cast(blob_type)); } WB_END diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java index 26b7a7e85bca0..2bc815ea35946 100644 --- a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -30,8 +30,8 @@ * java.management * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+SegmentedCodeCache -XX:-UseCodeCacheFlushing -XX:-MethodFlushing * compiler.whitebox.StressNMethodRelocation */ From cc8d2862a9c794cf148fff62e3ab1997269ef39a Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Mon, 11 Aug 2025 21:04:29 +0000 Subject: [PATCH 099/103] Lock nmethod::relocate behind experimental flag --- src/hotspot/share/code/nmethod.cpp | 2 ++ src/hotspot/share/runtime/globals.hpp | 3 ++ .../whitebox/DeoptimizeRelocatedNMethod.java | 15 ++++++---- .../compiler/whitebox/RelocateNMethod.java | 15 ++++++---- .../RelocateNMethodMultiplePaths.java | 30 ++++++++++++------- .../whitebox/StressNMethodRelocation.java | 2 +- .../nmethodrelocation/TestDriver.java | 2 ++ 7 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 231e142c284c2..b3cee3ae6f932 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1517,6 +1517,8 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm. } nmethod* nmethod::relocate(CodeBlobType code_blob_type) { + assert(NMethodRelocation, "must enable use of function"); + // Locks required to be held by caller to ensure the nmethod // is not modified or purged from code cache during relocation assert_lock_strong(CodeCache_lock); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 41520442cd407..aa9c879649ae3 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1569,6 +1569,9 @@ const int ObjectAlignmentInBytes = 8; "Start aggressive sweeping if less than X[%] of the total code cache is free.")\ range(0, 100) \ \ + product(bool, NMethodRelocation, false, EXPERIMENTAL, \ + "Enables use of experimental function nmethod::relocate()") \ + \ /* interpreter debugging */ \ develop(intx, BinarySwitchThreshold, 5, \ "Minimal number of lookupswitch entries for rewriting to binary " \ diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java index 51aab8d703730..25314051fdd46 100644 --- a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java @@ -31,7 +31,8 @@ * @requires vm.gc.Serial * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.DeoptimizeRelocatedNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseSerialGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod */ /* @@ -43,7 +44,8 @@ * @requires vm.gc.Parallel * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.DeoptimizeRelocatedNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseParallelGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod */ /* @@ -55,7 +57,8 @@ * @requires vm.gc.G1 * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.DeoptimizeRelocatedNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseG1GC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod */ /* @@ -67,7 +70,8 @@ * @requires vm.gc.Shenandoah * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.DeoptimizeRelocatedNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseShenandoahGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod */ /* @@ -79,7 +83,8 @@ * @requires vm.gc.Z * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.DeoptimizeRelocatedNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseZGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod */ package compiler.whitebox; diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java index dca076e2245ac..c18a8afa40036 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -34,7 +34,8 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseSerialGC compiler.whitebox.RelocateNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod */ /* @@ -49,7 +50,8 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseParallelGC compiler.whitebox.RelocateNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod */ /* @@ -64,7 +66,8 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseG1GC compiler.whitebox.RelocateNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod */ /* @@ -79,7 +82,8 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseShenandoahGC compiler.whitebox.RelocateNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod */ /* @@ -94,7 +98,8 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache -XX:+UseZGC compiler.whitebox.RelocateNMethod + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod */ package compiler.whitebox; diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java index 85eb7d46f3302..49be3eff8c247 100644 --- a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java @@ -34,7 +34,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -49,7 +50,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -64,7 +66,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -79,7 +82,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -94,7 +98,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -109,7 +114,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -124,7 +130,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -139,7 +146,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -154,7 +162,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ /* @@ -169,7 +178,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+TieredCompilation - * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC compiler.whitebox.RelocateNMethodMultiplePaths + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths */ package compiler.whitebox; diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java index 2bc815ea35946..c084a800e58f4 100644 --- a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -32,7 +32,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+SegmentedCodeCache -XX:-UseCodeCacheFlushing -XX:-MethodFlushing - * compiler.whitebox.StressNMethodRelocation + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.StressNMethodRelocation */ package compiler.whitebox; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java index 97c86cd509f8b..333dc1d51b5e6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java @@ -51,6 +51,8 @@ public static void main(String[] args) throws Exception { "-XX:+SegmentedCodeCache", "-XX:-TieredCompilation", "-Xbatch", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+NMethodRelocation", nsk.jvmti.NMethodRelocation.nmethodrelocation.class.getName()); OutputAnalyzer oa = new OutputAnalyzer(pb.start()); From 3344a72ab00134b796805ec217f155e26a7c843a Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 22 Aug 2025 23:24:30 +0000 Subject: [PATCH 100/103] Fix WB_RelocateNMethodFromAddr to not use stale nmethod pointer --- src/hotspot/share/prims/whitebox.cpp | 24 ++++++++++++++----- .../whitebox/StressNMethodRelocation.java | 4 ++-- .../NMethodRelocation/nmethodrelocation.java | 2 +- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 8ef950a059d33..55cb5554b1fa6 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1656,12 +1656,24 @@ WB_END WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, jint blob_type)) ResourceMark rm(THREAD); CHECK_JNI_EXCEPTION(env); - nmethod* code = (nmethod*) addr; - if (code != nullptr) { - MutexLocker ml_Compile_lock(Compile_lock); - CompiledICLocker ic_locker(code); - MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); - code->relocate(static_cast(blob_type)); + void* address = (void*) addr; + + if (address == nullptr) { + return; + } + + MutexLocker ml_Compile_lock(Compile_lock); + MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + // Verify that nmethod address is still valid + CodeBlob* blob = CodeCache::find_blob(address); + if (blob != nullptr && blob->is_nmethod()) { + nmethod* code = blob->as_nmethod(); + if (code->is_in_use()) { + CompiledICLocker ic_locker(code); + code->relocate(static_cast(blob_type)); + } } WB_END diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java index c084a800e58f4..3b397f4830602 100644 --- a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -31,8 +31,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+SegmentedCodeCache -XX:-UseCodeCacheFlushing -XX:-MethodFlushing - * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.StressNMethodRelocation + * -XX:+SegmentedCodeCache -XX:+UnlockExperimentalVMOptions + * -XX:+NMethodRelocation compiler.whitebox.StressNMethodRelocation */ package compiler.whitebox; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java index 2db18c9ee0a73..9177d3b9f65b8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java @@ -91,7 +91,7 @@ public static int run() throws Exception { throw new AssertionError("Could not find original nmethod"); } - WHITE_BOX.relocateNMethodFromAddr(originalNMethod.address, BlobType.MethodNonProfiled.id); + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodNonProfiled.id); NMethod relocatedNMethod = NMethod.get(method, false); if (relocatedNMethod == null) { From 023472c41c00bdbd2c4c742a8212c99dc262ca9d Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 28 Aug 2025 20:04:53 +0000 Subject: [PATCH 101/103] Refactor JVMTI test --- .../NMethodRelocationTest.java} | 91 ++++++++-- .../libNMethodRelocationTest.cpp | 114 +++++++++++++ .../nmethodrelocation/TestDriver.java | 84 --------- .../agentnmethodrelocation001.cpp | 159 ------------------ .../libagentnmethodrelocation001.cpp | 33 ---- 5 files changed, 187 insertions(+), 294 deletions(-) rename test/hotspot/jtreg/{vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java => serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java} (55%) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/libagentnmethodrelocation001.cpp diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java similarity index 55% rename from test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java rename to test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java index 9177d3b9f65b8..76863667b146d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation.java +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java @@ -21,20 +21,75 @@ * questions. */ -package nsk.jvmti.NMethodRelocation; +/* + * @test + * + * @bug 8316694 + * @summary Verify that nmethod relocation posts the correct JVMTI events + * @requires vm.jvmti + * @library /test/lib /test/hotspot/jtreg + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm/native NMethodRelocationTest + */ -import java.io.PrintStream; import java.lang.reflect.Executable; -import java.lang.reflect.Method; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -import nsk.share.*; -import nsk.share.jvmti.*; +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; import jdk.test.whitebox.WhiteBox; -import jdk.test.whitebox.code.NMethod; import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; -public class nmethodrelocation extends DebugeeClass { + +public class NMethodRelocationTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-agentlib:NMethodRelocationTest", + "--enable-native-access=ALL-UNNAMED", + "-Xbootclasspath/a:.", + "-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:+SegmentedCodeCache", + "-XX:-TieredCompilation", + "-Xbatch", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+NMethodRelocation", + "DoWork"); + + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + String output = oa.getOutput(); + if (oa.getExitValue() != 0) { + System.err.println(oa.getOutput()); + throw new RuntimeException("Non-zero exit code returned from the test"); + } + Asserts.assertTrue(oa.getExitValue() == 0); + + Pattern pattern = Pattern.compile("(?m)^Relocated nmethod from (0x[0-9a-f]{16}) to (0x[0-9a-f]{16})$"); + Matcher matcher = pattern.matcher(output); + + if (matcher.find()) { + String fromAddr = matcher.group(1); + String toAddr = matcher.group(2); + + // Confirm events sent for both original and relocated nmethod + oa.shouldContain(": name: compiledMethod, code: " + fromAddr); + oa.shouldContain(": name: compiledMethod, code: " + toAddr); + oa.shouldContain(": name: compiledMethod, code: " + fromAddr); + oa.shouldContain(": name: compiledMethod, code: " + toAddr); + } else { + System.err.println(oa.getOutput()); + throw new RuntimeException("Unable to find relocation information"); + } + } +} + +class DoWork { protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); @@ -44,7 +99,14 @@ public class nmethodrelocation extends DebugeeClass { /** Load native library if required. */ static { - loadLibrary("agentnmethodrelocation001"); + try { + System.loadLibrary("NMethodRelocationTest"); + } catch (UnsatisfiedLinkError ule) { + System.err.println("Could not load NMethodRelocationTest library"); + System.err.println("java.library.path: " + + System.getProperty("java.library.path")); + throw ule; + } } /** @@ -72,16 +134,13 @@ protected static String getVMOption(String name, String defaultValue) { String result = getVMOption(name); return result == null ? defaultValue : result; } - public static void main(String argv[]) throws Exception { - argv = nsk.share.jvmti.JVMTITest.commonInit(argv); + public static void main(String argv[]) throws Exception { run(); } - static int status = Consts.TEST_PASSED; - - public static int run() throws Exception { - Executable method = nmethodrelocation.class.getDeclaredMethod("compiledMethod"); + public static void run() throws Exception { + Executable method = DoWork.class.getDeclaredMethod("compiledMethod"); WHITE_BOX.testSetDontInlineMethod(method, true); compile(); @@ -107,12 +166,8 @@ public static int run() throws Exception { WHITE_BOX.fullGC(); WHITE_BOX.fullGC(); - status = checkStatus(status); - System.out.printf("Relocated nmethod from 0x%016x to 0x%016x%n", originalNMethod.code_begin, relocatedNMethod.code_begin); System.out.flush(); - - return status; } private static void compile() { diff --git a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp new file mode 100644 index 0000000000000..41ba6b1060859 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp @@ -0,0 +1,114 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include + +/** + * Callback for COMPILED_METHOD_LOAD event. + */ +JNIEXPORT void JNICALL +callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, + jint code_size, const void* code_addr, + jint map_length, const jvmtiAddrLocationMap* map, + const void* compile_info) { + char* name = nullptr; + char* sig = nullptr; + + if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { + printf(" [Could not retrieve method name]\n"); + fflush(stdout); + return; + } + + printf(": name: %s, code: 0x%016" PRIxPTR "\n", + name, (uintptr_t)code_addr); + fflush(stdout); +} + +/** + * Callback for COMPILED_METHOD_UNLOAD event. + */ +JNIEXPORT void JNICALL +callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, + const void* code_addr) { + char* name = nullptr; + char* sig = nullptr; + + if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { + printf(" [Could not retrieve method name]\n"); + fflush(stdout); + return; + } + printf(": name: %s, code: 0x%016" PRIxPTR "\n", + name, (uintptr_t)code_addr); + fflush(stdout); +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jvmtiEnv* jvmti = nullptr; + jvmtiError error; + + if (jvm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_0) != JNI_OK) { + printf("Unable to access JVMTI!\n"); + return JNI_ERR; + } + + // Add required capabilities + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_generate_compiled_method_load_events = 1; + error = jvmti->AddCapabilities(&caps); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to add capabilities, error=%d\n", error); + return JNI_ERR; + } + + // Set event callbacks + jvmtiEventCallbacks eventCallbacks; + memset(&eventCallbacks, 0, sizeof(eventCallbacks)); + eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad; + eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload; + error = jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to set event callbacks, error=%d\n", error); + return JNI_ERR; + } + + // Enable events + error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, nullptr); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to enable COMPILED_METHOD_LOAD event, error=%d\n", error); + return JNI_ERR; + } + + error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, nullptr); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to enable COMPILED_METHOD_UNLOAD event, error=%d\n", error); + return JNI_ERR; + } + + return JNI_OK; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java deleted file mode 100644 index 333dc1d51b5e6..0000000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/TestDriver.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * - * @bug 8316694 - * @summary Verify that nmethod relocation posts the correct JVMTI events - * - * @library /vmTestbase /test/lib - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/native TestDriver - */ - -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Asserts; -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -public class TestDriver { - public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-agentlib:agentnmethodrelocation001=-waittime=5", - "--enable-native-access=ALL-UNNAMED", - "-Xbootclasspath/a:.", - "-XX:+UseG1GC", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - "-XX:+SegmentedCodeCache", - "-XX:-TieredCompilation", - "-Xbatch", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+NMethodRelocation", - nsk.jvmti.NMethodRelocation.nmethodrelocation.class.getName()); - - OutputAnalyzer oa = new OutputAnalyzer(pb.start()); - String output = oa.getOutput(); - if (oa.getExitValue() != 0) { - System.err.println(oa.getOutput()); - throw new RuntimeException("Non-zero exit code returned from the test"); - } - Asserts.assertTrue(oa.getExitValue() == 0); - - Pattern pattern = Pattern.compile("(?m)^Relocated nmethod from (0x[0-9a-f]{16}) to (0x[0-9a-f]{16})$"); - Matcher matcher = pattern.matcher(output); - - if (matcher.find()) { - String fromAddr = matcher.group(1); - String toAddr = matcher.group(2); - - // Confirm events sent for both original and relocated nmethod - oa.shouldContain(": name: compiledMethod, code: " + fromAddr); - oa.shouldContain(": name: compiledMethod, code: " + toAddr); - oa.shouldContain(": name: compiledMethod, code: " + fromAddr); - oa.shouldContain(": name: compiledMethod, code: " + toAddr); - } else { - System.err.println(oa.getOutput()); - throw new RuntimeException("Unable to find relocation information"); - } - } -} - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp deleted file mode 100644 index f132849c3cf92..0000000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/agentnmethodrelocation001.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "jvmti.h" -#include "agent_common.hpp" -#include "jvmti_tools.hpp" - -extern "C" { - -/* scaffold objects */ -static jlong timeout = 0; - -#define EVENTS_COUNT 2 - -/* tested events */ -static jvmtiEvent eventsList[EVENTS_COUNT] = { - JVMTI_EVENT_COMPILED_METHOD_LOAD, - JVMTI_EVENT_COMPILED_METHOD_UNLOAD -}; - -/** Agent library initialization. */ -#ifdef STATIC_BUILD -JNIEXPORT jint JNICALL Agent_OnLoad_setevntcallb001(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} -JNIEXPORT jint JNICALL Agent_OnAttach_setevntcallb001(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} -JNIEXPORT jint JNI_OnLoad_setevntcallb001(JavaVM *jvm, char *options, void *reserved) { - return JNI_VERSION_1_8; -} -#endif - -/* ============================================================================= */ - -/** Agent algorithm. */ -static void JNICALL -agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { - NSK_DISPLAY0("Wait for tested method forced to compile\n"); - if (!nsk_jvmti_waitForSync(timeout)) - return; - - if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, nullptr)) { - nsk_jvmti_setFailStatus(); - } - - if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, nullptr)) { - nsk_jvmti_setFailStatus(); - } - - NSK_DISPLAY0("Let debugee to finish\n"); - if (!nsk_jvmti_resumeSync()) - return; -} - -/* ============================================================================= */ - -JNIEXPORT void JNICALL -callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, - jint code_size, const void* code_addr, - jint map_length, const jvmtiAddrLocationMap* map, - const void* compile_info) { - char* name = nullptr; - char* sig = nullptr; - - if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { - printf(" [Could not retrieve method name]\n"); - fflush(stdout); - return; - } - - printf(": name: %s, code: 0x%016" PRIxPTR "\n", - name, (uintptr_t)code_addr); - fflush(stdout); -} - -/** - * Callback for COMPILED_METHOD_UNLOAD event. - */ -JNIEXPORT void JNICALL -callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, - const void* code_addr) { - char* name = nullptr; - char* sig = nullptr; - - if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { - printf(" [Could not retrieve method name]\n"); - fflush(stdout); - return; - } - printf(": name: %s, code: 0x%016" PRIxPTR "\n", - name, (uintptr_t)code_addr); - fflush(stdout); -} - -jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { - jvmtiEnv* jvmti = nullptr; - - if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) - return JNI_ERR; - - timeout = nsk_jvmti_getWaitTime() * 60 * 1000; - - if (!NSK_VERIFY((jvmti = - nsk_jvmti_createJVMTIEnv(jvm, reserved)) != nullptr)) - return JNI_ERR; - - if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, nullptr))) - return JNI_ERR; - - /* add required capabilities */ - { - jvmtiCapabilities caps; - memset(&caps, 0, sizeof(caps)); - caps.can_generate_compiled_method_load_events = 1; - if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) - return JNI_ERR; - } - - /* set event callbacks */ - { - jvmtiEventCallbacks eventCallbacks; - memset(&eventCallbacks, 0, sizeof(eventCallbacks)); - eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad; - eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload; - if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)))) - return JNI_ERR; - - if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, nullptr))) - return JNI_ERR; - if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, nullptr))) - return JNI_ERR; - } - - return JNI_OK; -} - -/* ============================================================================= */ -} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/libagentnmethodrelocation001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/libagentnmethodrelocation001.cpp deleted file mode 100644 index 98c338486118f..0000000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/NMethodRelocation/nmethodrelocation/libagentnmethodrelocation001.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "native_thread.cpp" -#include "nsk_tools.cpp" -#include "jni_tools.cpp" -#include "jvmti_tools.cpp" -#include "agent_tools.cpp" -#include "jvmti_FollowRefObjects.cpp" -#include "Injector.cpp" -#include "JVMTITools.cpp" -#include "agent_common.cpp" -#include "agentnmethodrelocation001.cpp" From a20516379c3270223144250e710cda189c23ad23 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 29 Aug 2025 01:01:48 +0000 Subject: [PATCH 102/103] Fix NMethodRelocationTest.java logging race --- .../NMethodRelocationTest.java | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java index 76863667b146d..b12e2c3455c4e 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java @@ -33,6 +33,8 @@ * @run main/othervm/native NMethodRelocationTest */ +import static compiler.whitebox.CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION; + import java.lang.reflect.Executable; import java.util.Objects; import java.util.regex.Matcher; @@ -52,12 +54,11 @@ public static void main(String[] args) throws Exception { "-agentlib:NMethodRelocationTest", "--enable-native-access=ALL-UNNAMED", "-Xbootclasspath/a:.", - "-XX:+UseG1GC", + "-XX:+UseSerialGC", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:+SegmentedCodeCache", "-XX:-TieredCompilation", - "-Xbatch", "-XX:+UnlockExperimentalVMOptions", "-XX:+NMethodRelocation", "DoWork"); @@ -93,10 +94,6 @@ class DoWork { protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - /** Value of {@code -XX:CompileThreshold} */ - protected static final int COMPILE_THRESHOLD - = Integer.parseInt(getVMOption("CompileThreshold", "10000")); - /** Load native library if required. */ static { try { @@ -143,7 +140,10 @@ public static void run() throws Exception { Executable method = DoWork.class.getDeclaredMethod("compiledMethod"); WHITE_BOX.testSetDontInlineMethod(method, true); - compile(); + WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_FULL_OPTIMIZATION); + while (WHITE_BOX.isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } NMethod originalNMethod = NMethod.get(method, false); if (originalNMethod == null) { @@ -166,16 +166,12 @@ public static void run() throws Exception { WHITE_BOX.fullGC(); WHITE_BOX.fullGC(); + WHITE_BOX.lockCompilation(); + System.out.printf("Relocated nmethod from 0x%016x to 0x%016x%n", originalNMethod.code_begin, relocatedNMethod.code_begin); System.out.flush(); } - private static void compile() { - for (int i = 0; i < COMPILE_THRESHOLD; i++) { - compiledMethod(); - } - } - public static long compiledMethod() { return 0; } From bf18a4c8ba3e8567f550edd2ab5c00b5317d2cf7 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Tue, 9 Sep 2025 22:28:22 +0000 Subject: [PATCH 103/103] Fix race when not installed nmethod is deoptimized --- src/hotspot/share/code/codeBehaviours.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 6 +++--- src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp | 2 +- src/hotspot/share/gc/z/zUnload.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/code/codeBehaviours.cpp b/src/hotspot/share/code/codeBehaviours.cpp index e077f5c8ae461..bc5a81c95b3ca 100644 --- a/src/hotspot/share/code/codeBehaviours.cpp +++ b/src/hotspot/share/code/codeBehaviours.cpp @@ -42,5 +42,5 @@ void DefaultICProtectionBehaviour::unlock(nmethod* nm) { } bool DefaultICProtectionBehaviour::is_safe(nmethod* nm) { - return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self() || nm->is_not_installed(); + return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self() || (NMethodState_lock->owned_by_self() && nm->is_not_installed()); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index b9673efaaada8..c2dbd27d5210d 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -762,7 +762,7 @@ Method* nmethod::attached_method_before_pc(address pc) { } void nmethod::clear_inline_caches() { - assert(SafepointSynchronize::is_at_safepoint() || is_not_installed(), "clearing of IC's only allowed at safepoint or when not installed"); + assert(SafepointSynchronize::is_at_safepoint() || (NMethodState_lock->owned_by_self() && is_not_installed()), "clearing of IC's only allowed at safepoint or when not installed"); RelocIterator iter(this); while (iter.next()) { iter.reloc()->clear_inline_cache(); @@ -1555,8 +1555,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { iter.reloc()->fix_relocation_after_move(&src, &dst); } - nm_copy->clear_inline_caches(); - // To make dependency checking during class loading fast, record // the nmethod dependencies in the classes it is dependent on. // This allows the dependency checking code to simply walk the @@ -1586,6 +1584,8 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { if (!is_marked_for_deoptimization() && is_in_use()) { assert(method() != nullptr && method()->code() == this, "should be if is in use"); + nm_copy->clear_inline_caches(); + // Attempt to start using the copy if (nm_copy->make_in_use()) { ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index aaa6d0b67eff7..b248fab7958ac 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -103,7 +103,7 @@ class ShenandoahCompiledICProtectionBehaviour : public CompiledICProtectionBehav } virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || nm->is_not_installed()) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || (NMethodState_lock->owned_by_self() && nm->is_not_installed())) { return true; } diff --git a/src/hotspot/share/gc/z/zUnload.cpp b/src/hotspot/share/gc/z/zUnload.cpp index 03dbf88ad89a3..5e7bae3f656a3 100644 --- a/src/hotspot/share/gc/z/zUnload.cpp +++ b/src/hotspot/share/gc/z/zUnload.cpp @@ -100,7 +100,7 @@ class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { } virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || nm->is_not_installed()) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || (NMethodState_lock->owned_by_self() && nm->is_not_installed())) { return true; }