diff --git a/8014628-Support-AES-Encryption-with-HMAC-SHA2-for-Ke.patch b/8014628-Support-AES-Encryption-with-HMAC-SHA2-for-Ke.patch index 148c5aec8f9a0b602caa90520c14c5242e55cd65..08411fd6f00c8cf19db13e61916c1528e037fbc9 100644 --- a/8014628-Support-AES-Encryption-with-HMAC-SHA2-for-Ke.patch +++ b/8014628-Support-AES-Encryption-with-HMAC-SHA2-for-Ke.patch @@ -1954,13 +1954,13 @@ index 6413e155b..b59832f73 100644 /* * @test -- * @bug 7152176 -+ * @bug 7152176 8014628 +- * @bug 7152176 8168518 ++ * @bug 7152176 8168518 8014628 * @summary More krb5 tests * @library ../../../../java/security/testlibrary/ * @compile -XDignore.symbol.file ReplayCacheTestProc.java -@@ -95,8 +95,13 @@ public class ReplayCacheTestProc { - kdc.addPrincipalRandKey(peer(i)); +@@ -126,8 +126,13 @@ public class ReplayCacheTestProc { + kdc.addPrincipalRandKey(service(i)); } + // Native lib might not support aes-sha2 @@ -1972,8 +1972,8 @@ index 6413e155b..b59832f73 100644 kdc.writeKtab(OneKDC.KTAB); - KDC.saveConfig(OneKDC.KRB5_CONF, kdc); - if (mode != -1) { - // A special native server to check basic sanity + // User-provided libs + String userLibs = System.getProperty("test.libs"); diff --git a/jdk/test/sun/security/krb5/etype/ETypeOrder.java b/jdk/test/sun/security/krb5/etype/ETypeOrder.java index 9437b16ed..be36d6372 100644 --- a/jdk/test/sun/security/krb5/etype/ETypeOrder.java diff --git a/8057743-process-Synchronize-exiting-of-threads-and-p.patch b/8057743-process-Synchronize-exiting-of-threads-and-p.patch index 25c783e438eaeeb562ae3d7c591cde28fee7c8ff..2dbe3502a81cda95f2a1467308821264d0e70c3c 100644 --- a/8057743-process-Synchronize-exiting-of-threads-and-p.patch +++ b/8057743-process-Synchronize-exiting-of-threads-and-p.patch @@ -259,7 +259,7 @@ diff --git a/hotspot/src/os/windows/vm/os_windows.inline.hpp b/hotspot/src/os/wi index 5dac11c90..83c51935d 100644 --- a/hotspot/src/os/windows/vm/os_windows.inline.hpp +++ b/hotspot/src/os/windows/vm/os_windows.inline.hpp -@@ -96,6 +96,10 @@ inline int os::close(int fd) { +@@ -96,4 +96,8 @@ inline int os::close(int fd) { return ::close(fd); } @@ -267,9 +267,7 @@ index 5dac11c90..83c51935d 100644 + win32::exit_process_or_thread(win32::EPT_PROCESS, num); +} + - #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \ - os::win32::call_test_func_with_wrapper(f) - + #endif // OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 5b82a7a36..c72a5a766 100644 --- a/hotspot/src/share/vm/runtime/java.cpp diff --git a/8139595-MethodHandles-remove_dependent_nmethod-is-no.patch b/8139595-MethodHandles-remove_dependent_nmethod-is-no.patch new file mode 100644 index 0000000000000000000000000000000000000000..94a3dc9845afd90e7fd4e71faccd047377cb9e1d --- /dev/null +++ b/8139595-MethodHandles-remove_dependent_nmethod-is-no.patch @@ -0,0 +1,1220 @@ +Date: Sat, 30 Mar 2024 07:12:45 +0000 +Subject: 8139595: MethodHandles::remove_dependent_nmethod is not + MT safe + +--- + .../src/share/vm/classfile/javaClasses.cpp | 17 +- + .../src/share/vm/classfile/javaClasses.hpp | 5 +- + .../src/share/vm/code/dependencyContext.cpp | 347 ++++++++++++++++++ + .../src/share/vm/code/dependencyContext.hpp | 152 ++++++++ + .../src/share/vm/compiler/compileBroker.cpp | 2 +- + hotspot/src/share/vm/oops/instanceKlass.cpp | 207 +---------- + hotspot/src/share/vm/oops/instanceKlass.hpp | 62 +--- + hotspot/src/share/vm/prims/jni.cpp | 2 + + hotspot/src/share/vm/prims/methodHandles.cpp | 64 ++-- + hotspot/src/share/vm/runtime/init.cpp | 2 + + hotspot/src/share/vm/runtime/perfData.hpp | 1 + + hotspot/src/share/vm/runtime/vmStructs.cpp | 5 - + 12 files changed, 573 insertions(+), 293 deletions(-) + create mode 100644 hotspot/src/share/vm/code/dependencyContext.cpp + create mode 100644 hotspot/src/share/vm/code/dependencyContext.hpp + +diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp +index 267bbacd..ece8ef03 100644 +--- a/hotspot/src/share/vm/classfile/javaClasses.cpp ++++ b/hotspot/src/share/vm/classfile/javaClasses.cpp +@@ -28,6 +28,7 @@ + #include "classfile/symbolTable.hpp" + #include "classfile/vmSymbols.hpp" + #include "code/debugInfo.hpp" ++#include "code/dependencyContext.hpp" + #include "code/pcDesc.hpp" + #include "compiler/compilerOracle.hpp" + #include "interpreter/interpreter.hpp" +@@ -3033,14 +3034,16 @@ void java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets() { + } + } + +-nmethodBucket* java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) { ++DependencyContext java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) { + assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); +- return (nmethodBucket*) (address) call_site->long_field(_vmdependencies_offset); +-} +- +-void java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(oop call_site, nmethodBucket* context) { +- assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); +- call_site->long_field_put(_vmdependencies_offset, (jlong) (address) context); ++ intptr_t* vmdeps_addr = (intptr_t*)call_site->address_field_addr(_vmdependencies_offset); ++#ifndef ASSERT ++ DependencyContext dep_ctx(vmdeps_addr); ++#else ++ // Verify that call_site isn't moved during DependencyContext lifetime. ++ DependencyContext dep_ctx(vmdeps_addr, Handle(call_site)); ++#endif // ASSERT ++ return dep_ctx; + } + + // Support for java_security_AccessControlContext +diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp +index 1eb04b96..ccd0cf27 100644 +--- a/hotspot/src/share/vm/classfile/javaClasses.hpp ++++ b/hotspot/src/share/vm/classfile/javaClasses.hpp +@@ -1243,6 +1243,8 @@ public: + #define CALLSITECONTEXT_INJECTED_FIELDS(macro) \ + macro(java_lang_invoke_MethodHandleNatives_CallSiteContext, vmdependencies, intptr_signature, false) + ++class DependencyContext; ++ + class java_lang_invoke_MethodHandleNatives_CallSiteContext : AllStatic { + friend class JavaClasses; + +@@ -1253,8 +1255,7 @@ private: + + public: + // Accessors +- static nmethodBucket* vmdependencies(oop context); +- static void set_vmdependencies(oop context, nmethodBucket* bucket); ++ static DependencyContext vmdependencies(oop context); + + // Testers + static bool is_subclass(Klass* klass) { +diff --git a/hotspot/src/share/vm/code/dependencyContext.cpp b/hotspot/src/share/vm/code/dependencyContext.cpp +new file mode 100644 +index 00000000..5c0af1e3 +--- /dev/null ++++ b/hotspot/src/share/vm/code/dependencyContext.cpp +@@ -0,0 +1,347 @@ ++/* ++ * Copyright (c) 2015, 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. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "code/nmethod.hpp" ++#include "code/dependencies.hpp" ++#include "code/dependencyContext.hpp" ++#include "memory/resourceArea.hpp" ++#include "runtime/atomic.hpp" ++#include "runtime/perfData.hpp" ++#include "utilities/exceptions.hpp" ++ ++PerfCounter* DependencyContext::_perf_total_buckets_allocated_count = NULL; ++PerfCounter* DependencyContext::_perf_total_buckets_deallocated_count = NULL; ++PerfCounter* DependencyContext::_perf_total_buckets_stale_count = NULL; ++PerfCounter* DependencyContext::_perf_total_buckets_stale_acc_count = NULL; ++ ++void dependencyContext_init() { ++ DependencyContext::init(); ++} ++ ++void DependencyContext::init() { ++ if (UsePerfData) { ++ EXCEPTION_MARK; ++ _perf_total_buckets_allocated_count = ++ PerfDataManager::create_counter(SUN_CI, "nmethodBucketsAllocated", PerfData::U_Events, CHECK); ++ _perf_total_buckets_deallocated_count = ++ PerfDataManager::create_counter(SUN_CI, "nmethodBucketsDeallocated", PerfData::U_Events, CHECK); ++ _perf_total_buckets_stale_count = ++ PerfDataManager::create_counter(SUN_CI, "nmethodBucketsStale", PerfData::U_Events, CHECK); ++ _perf_total_buckets_stale_acc_count = ++ PerfDataManager::create_counter(SUN_CI, "nmethodBucketsStaleAccumulated", PerfData::U_Events, CHECK); ++ } ++} ++ ++// ++// Walk the list of dependent nmethods searching for nmethods which ++// are dependent on the changes that were passed in and mark them for ++// deoptimization. Returns the number of nmethods found. ++// ++int DependencyContext::mark_dependent_nmethods(DepChange& changes) { ++ int found = 0; ++ for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { ++ nmethod* nm = b->get_nmethod(); ++ // since dependencies aren't removed until an nmethod becomes a zombie, ++ // the dependency list may contain nmethods which aren't alive. ++ if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) { ++ if (TraceDependencies) { ++ ResourceMark rm; ++ tty->print_cr("Marked for deoptimization"); ++ changes.print(); ++ nm->print(); ++ nm->print_dependencies(); ++ } ++ nm->mark_for_deoptimization(); ++ found++; ++ } ++ } ++ return found; ++} ++ ++// ++// Add an nmethod to the dependency context. ++// It's possible that an nmethod has multiple dependencies on a klass ++// so a count is kept for each bucket to guarantee that creation and ++// deletion of dependencies is consistent. ++// ++void DependencyContext::add_dependent_nmethod(nmethod* nm, bool expunge) { ++ assert_lock_strong(CodeCache_lock); ++ for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { ++ if (nm == b->get_nmethod()) { ++ b->increment(); ++ return; ++ } ++ } ++ set_dependencies(new nmethodBucket(nm, dependencies())); ++ if (UsePerfData) { ++ _perf_total_buckets_allocated_count->inc(); ++ } ++ if (expunge) { ++ // Remove stale entries from the list. ++ expunge_stale_entries(); ++ } ++} ++ ++// ++// Remove an nmethod dependency from the context. ++// Decrement count of the nmethod in the dependency list and, optionally, remove ++// the bucket completely when the count goes to 0. This method must find ++// a corresponding bucket otherwise there's a bug in the recording of dependencies. ++// Can be called concurrently by parallel GC threads. ++// ++void DependencyContext::remove_dependent_nmethod(nmethod* nm, bool expunge) { ++ assert_locked_or_safepoint(CodeCache_lock); ++ nmethodBucket* first = dependencies(); ++ nmethodBucket* last = NULL; ++ for (nmethodBucket* b = first; b != NULL; b = b->next()) { ++ if (nm == b->get_nmethod()) { ++ int val = b->decrement(); ++ guarantee(val >= 0, err_msg("Underflow: %d", val)); ++ if (val == 0) { ++ if (expunge) { ++ if (last == NULL) { ++ set_dependencies(b->next()); ++ } else { ++ last->set_next(b->next()); ++ } ++ delete b; ++ if (UsePerfData) { ++ _perf_total_buckets_deallocated_count->inc(); ++ } ++ } else { ++ // Mark the context as having stale entries, since it is not safe to ++ // expunge the list right now. ++ set_has_stale_entries(true); ++ if (UsePerfData) { ++ _perf_total_buckets_stale_count->inc(); ++ _perf_total_buckets_stale_acc_count->inc(); ++ } ++ } ++ } ++ if (expunge) { ++ // Remove stale entries from the list. ++ expunge_stale_entries(); ++ } ++ return; ++ } ++ last = b; ++ } ++#ifdef ASSERT ++ tty->print_raw_cr("### can't find dependent nmethod"); ++ nm->print(); ++#endif // ASSERT ++ ShouldNotReachHere(); ++} ++ ++// ++// Reclaim all unused buckets. ++// ++void DependencyContext::expunge_stale_entries() { ++ assert_locked_or_safepoint(CodeCache_lock); ++ if (!has_stale_entries()) { ++ assert(!find_stale_entries(), "inconsistent info"); ++ return; ++ } ++ nmethodBucket* first = dependencies(); ++ nmethodBucket* last = NULL; ++ int removed = 0; ++ for (nmethodBucket* b = first; b != NULL;) { ++ assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); ++ nmethodBucket* next = b->next(); ++ if (b->count() == 0) { ++ if (last == NULL) { ++ first = next; ++ } else { ++ last->set_next(next); ++ } ++ removed++; ++ delete b; ++ // last stays the same. ++ } else { ++ last = b; ++ } ++ b = next; ++ } ++ set_dependencies(first); ++ set_has_stale_entries(false); ++ if (UsePerfData && removed > 0) { ++ _perf_total_buckets_deallocated_count->inc(removed); ++ _perf_total_buckets_stale_count->dec(removed); ++ } ++} ++ ++// ++// Invalidate all dependencies in the context ++int DependencyContext::remove_all_dependents() { ++ assert_locked_or_safepoint(CodeCache_lock); ++ nmethodBucket* b = dependencies(); ++ set_dependencies(NULL); ++ int marked = 0; ++ int removed = 0; ++ while (b != NULL) { ++ nmethod* nm = b->get_nmethod(); ++ if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) { ++ nm->mark_for_deoptimization(); ++ marked++; ++ } ++ nmethodBucket* next = b->next(); ++ removed++; ++ delete b; ++ b = next; ++ } ++ set_has_stale_entries(false); ++ if (UsePerfData && removed > 0) { ++ _perf_total_buckets_deallocated_count->inc(removed); ++ } ++ return marked; ++} ++ ++#ifndef PRODUCT ++void DependencyContext::print_dependent_nmethods(bool verbose) { ++ int idx = 0; ++ for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { ++ nmethod* nm = b->get_nmethod(); ++ tty->print("[%d] count=%d { ", idx++, b->count()); ++ if (!verbose) { ++ nm->print_on(tty, "nmethod"); ++ tty->print_cr(" } "); ++ } else { ++ nm->print(); ++ nm->print_dependencies(); ++ tty->print_cr("--- } "); ++ } ++ } ++} ++ ++bool DependencyContext::is_dependent_nmethod(nmethod* nm) { ++ for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { ++ if (nm == b->get_nmethod()) { ++#ifdef ASSERT ++ int count = b->count(); ++ assert(count >= 0, "count shouldn't be negative"); ++#endif ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool DependencyContext::find_stale_entries() { ++ for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { ++ if (b->count() == 0) return true; ++ } ++ return false; ++} ++ ++#endif //PRODUCT ++ ++int nmethodBucket::decrement() { ++ return Atomic::add(-1, (volatile int *)&_count); ++} ++ ++/////////////// Unit tests /////////////// ++ ++#ifndef PRODUCT ++ ++class TestDependencyContext { ++ public: ++ nmethod* _nmethods[3]; ++ ++ intptr_t _dependency_context; ++ ++ TestDependencyContext() : _dependency_context(DependencyContext::EMPTY) { ++ CodeCache_lock->lock_without_safepoint_check(); ++ ++ DependencyContext depContext(&_dependency_context); ++ ++ _nmethods[0] = reinterpret_cast(0x8 * 0); ++ _nmethods[1] = reinterpret_cast(0x8 * 1); ++ _nmethods[2] = reinterpret_cast(0x8 * 2); ++ ++ depContext.add_dependent_nmethod(_nmethods[2]); ++ depContext.add_dependent_nmethod(_nmethods[1]); ++ depContext.add_dependent_nmethod(_nmethods[0]); ++ } ++ ++ ~TestDependencyContext() { ++ wipe(); ++ CodeCache_lock->unlock(); ++ } ++ ++ static void testRemoveDependentNmethod(int id, bool delete_immediately) { ++ TestDependencyContext c; ++ DependencyContext depContext(&c._dependency_context); ++ assert(!has_stale_entries(depContext), "check"); ++ ++ nmethod* nm = c._nmethods[id]; ++ depContext.remove_dependent_nmethod(nm, delete_immediately); ++ ++ if (!delete_immediately) { ++ assert(has_stale_entries(depContext), "check"); ++ assert(depContext.is_dependent_nmethod(nm), "check"); ++ depContext.expunge_stale_entries(); ++ } ++ ++ assert(!has_stale_entries(depContext), "check"); ++ assert(!depContext.is_dependent_nmethod(nm), "check"); ++ } ++ ++ static void testRemoveDependentNmethod() { ++ testRemoveDependentNmethod(0, false); ++ testRemoveDependentNmethod(1, false); ++ testRemoveDependentNmethod(2, false); ++ ++ testRemoveDependentNmethod(0, true); ++ testRemoveDependentNmethod(1, true); ++ testRemoveDependentNmethod(2, true); ++ } ++ ++ static void test() { ++ testRemoveDependentNmethod(); ++ } ++ ++ static bool has_stale_entries(DependencyContext ctx) { ++ assert(ctx.has_stale_entries() == ctx.find_stale_entries(), "check"); ++ return ctx.has_stale_entries(); ++ } ++ ++ void wipe() { ++ DependencyContext ctx(&_dependency_context); ++ nmethodBucket* b = ctx.dependencies(); ++ ctx.set_dependencies(NULL); ++ ctx.set_has_stale_entries(false); ++ while (b != NULL) { ++ nmethodBucket* next = b->next(); ++ delete b; ++ b = next; ++ } ++ } ++}; ++ ++void TestDependencyContext_test() { ++ TestDependencyContext::test(); ++} ++ ++#endif // PRODUCT +\ No newline at end of file +diff --git a/hotspot/src/share/vm/code/dependencyContext.hpp b/hotspot/src/share/vm/code/dependencyContext.hpp +new file mode 100644 +index 00000000..533112b8 +--- /dev/null ++++ b/hotspot/src/share/vm/code/dependencyContext.hpp +@@ -0,0 +1,152 @@ ++/* ++ * Copyright (c) 2015, 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. ++ * ++ */ ++ ++#ifndef SHARE_VM_CODE_DEPENDENCYCONTEXT_HPP ++#define SHARE_VM_CODE_DEPENDENCYCONTEXT_HPP ++ ++#include "memory/allocation.hpp" ++#include "oops/oop.hpp" ++#include "runtime/handles.hpp" ++#include "runtime/perfData.hpp" ++ ++class nmethod; ++class DepChange; ++ ++// ++// nmethodBucket is used to record dependent nmethods for ++// deoptimization. nmethod dependencies are actually ++// pairs but we really only care about the klass part for purposes of ++// finding nmethods which might need to be deoptimized. Instead of ++// recording the method, a count of how many times a particular nmethod ++// was recorded is kept. This ensures that any recording errors are ++// noticed since an nmethod should be removed as many times are it's ++// added. ++// ++class nmethodBucket: public CHeapObj { ++ friend class VMStructs; ++ private: ++ nmethod* _nmethod; ++ int _count; ++ nmethodBucket* _next; ++ ++ public: ++ nmethodBucket(nmethod* nmethod, nmethodBucket* next) : ++ _nmethod(nmethod), _next(next), _count(1) {} ++ ++ int count() { return _count; } ++ int increment() { _count += 1; return _count; } ++ int decrement(); ++ nmethodBucket* next() { return _next; } ++ void set_next(nmethodBucket* b) { _next = b; } ++ nmethod* get_nmethod() { return _nmethod; } ++}; ++ ++// ++// Utility class to manipulate nmethod dependency context. ++// The context consists of nmethodBucket* (a head of a linked list) ++// and a boolean flag (does the list contains stale entries). The structure is ++// encoded as an intptr_t: lower bit is used for the flag. It is possible since ++// nmethodBucket* is aligned - the structure is malloc'ed in C heap. ++// Dependency context can be attached either to an InstanceKlass (_dep_context field) ++// or CallSiteContext oop for call_site_target dependencies (see javaClasses.hpp). ++// DependencyContext class operates on some location which holds a intptr_t value. ++// ++class DependencyContext : public StackObj { ++ friend class VMStructs; ++ friend class TestDependencyContext; ++ private: ++ enum TagBits { _has_stale_entries_bit = 1, _has_stale_entries_mask = 1 }; ++ ++ intptr_t* _dependency_context_addr; ++ ++ void set_dependencies(nmethodBucket* b) { ++ assert((intptr_t(b) & _has_stale_entries_mask) == 0, "should be aligned"); ++ if (has_stale_entries()) { ++ *_dependency_context_addr = intptr_t(b) | _has_stale_entries_mask; ++ } else { ++ *_dependency_context_addr = intptr_t(b); ++ } ++ } ++ ++ void set_has_stale_entries(bool x) { ++ if (x) { ++ *_dependency_context_addr |= _has_stale_entries_mask; ++ } else { ++ *_dependency_context_addr &= ~_has_stale_entries_mask; ++ } ++ } ++ ++ nmethodBucket* dependencies() { ++ intptr_t value = *_dependency_context_addr; ++ return (nmethodBucket*) (value & ~_has_stale_entries_mask); ++ } ++ ++ bool has_stale_entries() const { ++ intptr_t value = *_dependency_context_addr; ++ return (value & _has_stale_entries_mask) != 0; ++ } ++ ++ static PerfCounter* _perf_total_buckets_allocated_count; ++ static PerfCounter* _perf_total_buckets_deallocated_count; ++ static PerfCounter* _perf_total_buckets_stale_count; ++ static PerfCounter* _perf_total_buckets_stale_acc_count; ++ ++ public: ++#ifdef ASSERT ++ // Verification for dependency contexts rooted at Java objects. ++ Handle _base; // non-NULL if dependency context resides in an oop (e.g. CallSite). ++ oop _base_oop; ++ ++ DependencyContext(intptr_t* addr, Handle base = Handle()) ++ : _dependency_context_addr(addr), _base(base) ++ { ++ _base_oop = _base(); ++ } ++ ++ ~DependencyContext() { ++ // Base oop relocation invalidates _dependency_context_addr. ++ assert(_base_oop == _base(), "base oop relocation is forbidden"); ++ } ++#else ++ DependencyContext(intptr_t* addr) : _dependency_context_addr(addr) {} ++#endif // ASSERT ++ ++ static const intptr_t EMPTY = 0; // dependencies = NULL, has_stale_entries = false ++ ++ static void init(); ++ ++ int mark_dependent_nmethods(DepChange& changes); ++ void add_dependent_nmethod(nmethod* nm, bool expunge_stale_entries = false); ++ void remove_dependent_nmethod(nmethod* nm, bool expunge_stale_entries = false); ++ int remove_all_dependents(); ++ ++ void expunge_stale_entries(); ++ ++#ifndef PRODUCT ++ void print_dependent_nmethods(bool verbose); ++ bool is_dependent_nmethod(nmethod* nm); ++ bool find_stale_entries(); ++#endif //PRODUCT ++}; ++#endif // SHARE_VM_CODE_DEPENDENCYCONTEXT_HPP +\ No newline at end of file +diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp +index e8f97074..22372d07 100644 +--- a/hotspot/src/share/vm/compiler/compileBroker.cpp ++++ b/hotspot/src/share/vm/compiler/compileBroker.cpp +@@ -26,6 +26,7 @@ + #include "classfile/systemDictionary.hpp" + #include "classfile/vmSymbols.hpp" + #include "code/codeCache.hpp" ++#include "code/dependencyContext.hpp" + #include "compiler/compileBroker.hpp" + #include "compiler/compileLog.hpp" + #include "compiler/compilerOracle.hpp" +@@ -919,7 +920,6 @@ void CompileBroker::compilation_init() { + PerfData::U_Ticks, CHECK); + } + +- + if (UsePerfData) { + + EXCEPTION_MARK; +diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp +index ce297b68..1bff1309 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.cpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.cpp +@@ -28,6 +28,7 @@ + #include "classfile/systemDictionaryShared.hpp" + #include "classfile/verifier.hpp" + #include "classfile/vmSymbols.hpp" ++#include "code/dependencyContext.hpp" + #include "compiler/compileBroker.hpp" + #include "gc_implementation/shared/markSweep.inline.hpp" + #include "gc_interface/collectedHeap.inline.hpp" +@@ -194,7 +195,6 @@ InstanceKlass* InstanceKlass::allocate_instance_klass( + + int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, + access_flags.is_interface(), is_anonymous); +- + // Allocation + InstanceKlass* ik; + if (rt == REF_NONE) { +@@ -296,7 +296,7 @@ InstanceKlass::InstanceKlass(int vtable_len, + set_static_oop_field_count(0); + set_nonstatic_field_size(0); + set_is_marked_dependent(false); +- set_has_unloaded_dependent(false); ++ _dep_context = DependencyContext::EMPTY; + set_init_state(InstanceKlass::allocated); + set_init_thread(NULL); + set_init_state(allocated); +@@ -311,7 +311,6 @@ InstanceKlass::InstanceKlass(int vtable_len, + set_annotations(NULL); + set_jvmti_cached_class_field_map(NULL); + set_initial_method_idnum(0); +- _dependencies = NULL; + set_jvmti_cached_class_field_map(NULL); + set_cached_class_file(NULL); + set_initial_method_idnum(0); +@@ -2093,200 +2092,31 @@ jmethodID InstanceKlass::jmethod_id_or_null(Method* method) { + return id; + } + +-int nmethodBucket::decrement() { +- return Atomic::add(-1, (volatile int *)&_count); +-} +- +-// +-// Walk the list of dependent nmethods searching for nmethods which +-// are dependent on the changes that were passed in and mark them for +-// deoptimization. Returns the number of nmethods found. +-// +-int nmethodBucket::mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes) { +- assert_locked_or_safepoint(CodeCache_lock); +- int found = 0; +- for (nmethodBucket* b = deps; b != NULL; b = b->next()) { +- nmethod* nm = b->get_nmethod(); +- // since dependencies aren't removed until an nmethod becomes a zombie, +- // the dependency list may contain nmethods which aren't alive. +- if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) { +- if (TraceDependencies) { +- ResourceMark rm; +- tty->print_cr("Marked for deoptimization"); +- changes.print(); +- nm->print(); +- nm->print_dependencies(); +- } +- nm->mark_for_deoptimization(); +- found++; +- } +- } +- return found; +-} +- +-// +-// Add an nmethodBucket to the list of dependencies for this nmethod. +-// It's possible that an nmethod has multiple dependencies on this klass +-// so a count is kept for each bucket to guarantee that creation and +-// deletion of dependencies is consistent. Returns new head of the list. +-// +-nmethodBucket* nmethodBucket::add_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { +- assert_locked_or_safepoint(CodeCache_lock); +- for (nmethodBucket* b = deps; b != NULL; b = b->next()) { +- if (nm == b->get_nmethod()) { +- b->increment(); +- return deps; +- } +- } +- return new nmethodBucket(nm, deps); +-} +- +-// +-// Decrement count of the nmethod in the dependency list and remove +-// the bucket completely when the count goes to 0. This method must +-// find a corresponding bucket otherwise there's a bug in the +-// recording of dependencies. Returns true if the bucket was deleted, +-// or marked ready for reclaimation. +-bool nmethodBucket::remove_dependent_nmethod(nmethodBucket** deps, nmethod* nm, bool delete_immediately) { +- assert_locked_or_safepoint(CodeCache_lock); +- +- nmethodBucket* first = *deps; +- nmethodBucket* last = NULL; +- for (nmethodBucket* b = first; b != NULL; b = b->next()) { +- if (nm == b->get_nmethod()) { +- int val = b->decrement(); +- guarantee(val >= 0, err_msg("Underflow: %d", val)); +- if (val == 0) { +- if (delete_immediately) { +- if (last == NULL) { +- *deps = b->next(); +- } else { +- last->set_next(b->next()); +- } +- delete b; +- } +- } +- return true; +- } +- last = b; +- } +- +-#ifdef ASSERT +- tty->print_raw_cr("### can't find dependent nmethod"); +- nm->print(); +-#endif // ASSERT +- ShouldNotReachHere(); +- return false; +-} +- +-// Convenience overload, for callers that don't want to delete the nmethodBucket entry. +-bool nmethodBucket::remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { +- nmethodBucket** deps_addr = &deps; +- return remove_dependent_nmethod(deps_addr, nm, false /* Don't delete */); +-} +- +-// +-// Reclaim all unused buckets. Returns new head of the list. +-// +-nmethodBucket* nmethodBucket::clean_dependent_nmethods(nmethodBucket* deps) { +- nmethodBucket* first = deps; +- nmethodBucket* last = NULL; +- nmethodBucket* b = first; +- +- while (b != NULL) { +- assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); +- nmethodBucket* next = b->next(); +- if (b->count() == 0) { +- if (last == NULL) { +- first = next; +- } else { +- last->set_next(next); +- } +- delete b; +- // last stays the same. +- } else { +- last = b; +- } +- b = next; +- } +- return first; +-} +- +-#ifndef PRODUCT +-void nmethodBucket::print_dependent_nmethods(nmethodBucket* deps, bool verbose) { +- int idx = 0; +- for (nmethodBucket* b = deps; b != NULL; b = b->next()) { +- nmethod* nm = b->get_nmethod(); +- tty->print("[%d] count=%d { ", idx++, b->count()); +- if (!verbose) { +- nm->print_on(tty, "nmethod"); +- tty->print_cr(" } "); +- } else { +- nm->print(); +- nm->print_dependencies(); +- tty->print_cr("--- } "); +- } +- } ++inline DependencyContext InstanceKlass::dependencies() { ++ DependencyContext dep_context(&_dep_context); ++ return dep_context; + } + +-bool nmethodBucket::is_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { +- for (nmethodBucket* b = deps; b != NULL; b = b->next()) { +- if (nm == b->get_nmethod()) { +-#ifdef ASSERT +- int count = b->count(); +- assert(count >= 0, err_msg("count shouldn't be negative: %d", count)); +-#endif +- return true; +- } +- } +- return false; +-} +-#endif //PRODUCT +- + int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { +- assert_locked_or_safepoint(CodeCache_lock); +- return nmethodBucket::mark_dependent_nmethods(_dependencies, changes); +-} +- +-void InstanceKlass::clean_dependent_nmethods() { +- assert_locked_or_safepoint(CodeCache_lock); +- +- if (has_unloaded_dependent()) { +- _dependencies = nmethodBucket::clean_dependent_nmethods(_dependencies); +- set_has_unloaded_dependent(false); +- } +-#ifdef ASSERT +- else { +- // Verification +- for (nmethodBucket* b = _dependencies; b != NULL; b = b->next()) { +- assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); +- assert(b->count() != 0, "empty buckets need to be cleaned"); +- } +- } +-#endif ++ return dependencies().mark_dependent_nmethods(changes); + } + + void InstanceKlass::add_dependent_nmethod(nmethod* nm) { +- assert_locked_or_safepoint(CodeCache_lock); +- _dependencies = nmethodBucket::add_dependent_nmethod(_dependencies, nm); ++ dependencies().add_dependent_nmethod(nm); + } + + void InstanceKlass::remove_dependent_nmethod(nmethod* nm, bool delete_immediately) { +- assert_locked_or_safepoint(CodeCache_lock); +- +- if (nmethodBucket::remove_dependent_nmethod(&_dependencies, nm, delete_immediately)) { +- set_has_unloaded_dependent(true); +- } ++ dependencies().remove_dependent_nmethod(nm, delete_immediately); + } + + #ifndef PRODUCT + void InstanceKlass::print_dependent_nmethods(bool verbose) { +- nmethodBucket::print_dependent_nmethods(_dependencies, verbose); ++ dependencies().print_dependent_nmethods(verbose); + } + + + bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { +- return nmethodBucket::is_dependent_nmethod(_dependencies, nm); ++ return dependencies().is_dependent_nmethod(nm); + } + #endif //PRODUCT + +@@ -2583,7 +2413,9 @@ void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive) + clean_implementors_list(is_alive); + clean_method_data(is_alive); + +- clean_dependent_nmethods(); ++ // Since GC iterates InstanceKlasses sequentially, it is safe to remove stale entries here. ++ DependencyContext dep_context(&_dep_context); ++ dep_context.expunge_stale_entries(); + } + + void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { +@@ -2630,6 +2462,8 @@ void InstanceKlass::remove_unshareable_info() { + + constants()->remove_unshareable_info(); + ++ assert(_dep_context == DependencyContext::EMPTY, "dependency context is not shareable"); ++ + for (int i = 0; i < methods()->length(); i++) { + Method* m = methods()->at(i); + m->remove_unshareable_info(); +@@ -2654,7 +2488,6 @@ void InstanceKlass::remove_unshareable_info() { + array_klasses_do(remove_unshareable_in_class); + // These are not allocated from metaspace. They are safe to set to NULL. + _member_names = NULL; +- _dependencies = NULL; + _osr_nmethods_head = NULL; + _init_thread = NULL; + } +@@ -2796,12 +2629,10 @@ void InstanceKlass::release_C_heap_structures() { + } + + // release dependencies +- nmethodBucket* b = _dependencies; +- _dependencies = NULL; +- while (b != NULL) { +- nmethodBucket* next = b->next(); +- delete b; +- b = next; ++ { ++ DependencyContext ctx(&_dep_context); ++ int marked = ctx.remove_all_dependents(); ++ assert(marked == 0, "all dependencies should be already invalidated"); + } + + // Deallocate breakpoint records +diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp +index 9750ae56..14556a38 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.hpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.hpp +@@ -83,15 +83,15 @@ + + + // forward declaration for class -- see below for definition +-class SuperTypeClosure; +-class JNIid; +-class jniIdMapBase; + class BreakpointInfo; +-class fieldDescriptor; + class DepChange; +-class nmethodBucket; ++class DependencyContext; ++class fieldDescriptor; ++class jniIdMapBase; ++class JNIid; + class JvmtiCachedClassFieldMap; + class MemberNameTable; ++class SuperTypeClosure; + + // This is used in iterators below. + class FieldClosure: public StackObj { +@@ -227,7 +227,6 @@ class InstanceKlass: public Klass { + // _misc_flags. + bool _is_marked_dependent; // used for marking during flushing and deoptimization + bool _is_being_redefined; // used for locking redefinition +- bool _has_unloaded_dependent; + + enum { + _misc_rewritten = 1 << 0, // methods rewritten. +@@ -249,7 +248,7 @@ class InstanceKlass: public Klass { + MemberNameTable* _member_names; // Member names + JNIid* _jni_ids; // First JNI identifier for static fields in this class + jmethodID* _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none +- nmethodBucket* _dependencies; // list of dependent nmethods ++ intptr_t _dep_context; // packed DependencyContext structure + nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class + BreakpointInfo* _breakpoints; // bpt lists, managed by Method* + // Linked instanceKlasses of previous versions +@@ -480,9 +479,6 @@ class InstanceKlass: public Klass { + bool is_marked_dependent() const { return _is_marked_dependent; } + void set_is_marked_dependent(bool value) { _is_marked_dependent = value; } + +- bool has_unloaded_dependent() const { return _has_unloaded_dependent; } +- void set_has_unloaded_dependent(bool value) { _has_unloaded_dependent = value; } +- + // initialization (virtuals from Klass) + bool should_be_initialized() const; // means that initialize should be called + void initialize(TRAPS); +@@ -831,7 +827,8 @@ class InstanceKlass: public Klass { + JNIid* jni_id_for(int offset); + + // maintenance of deoptimization dependencies +- int mark_dependent_nmethods(DepChange& changes); ++ inline DependencyContext dependencies(); ++ int mark_dependent_nmethods(DepChange& changes); + void add_dependent_nmethod(nmethod* nm); + void remove_dependent_nmethod(nmethod* nm, bool delete_immediately); + +@@ -1026,7 +1023,6 @@ class InstanceKlass: public Klass { + void clean_weak_instanceklass_links(BoolObjectClosure* is_alive); + void clean_implementors_list(BoolObjectClosure* is_alive); + void clean_method_data(BoolObjectClosure* is_alive); +- void clean_dependent_nmethods(); + + // Explicit metaspace deallocation of fields + // For RedefineClasses and class file parsing errors, we need to deallocate +@@ -1258,48 +1254,6 @@ class JNIid: public CHeapObj { + void verify(Klass* holder); + }; + +- +-// +-// nmethodBucket is used to record dependent nmethods for +-// deoptimization. nmethod dependencies are actually +-// pairs but we really only care about the klass part for purposes of +-// finding nmethods which might need to be deoptimized. Instead of +-// recording the method, a count of how many times a particular nmethod +-// was recorded is kept. This ensures that any recording errors are +-// noticed since an nmethod should be removed as many times are it's +-// added. +-// +-class nmethodBucket: public CHeapObj { +- friend class VMStructs; +- private: +- nmethod* _nmethod; +- int _count; +- nmethodBucket* _next; +- +- public: +- nmethodBucket(nmethod* nmethod, nmethodBucket* next) { +- _nmethod = nmethod; +- _next = next; +- _count = 1; +- } +- int count() { return _count; } +- int increment() { _count += 1; return _count; } +- int decrement(); +- nmethodBucket* next() { return _next; } +- void set_next(nmethodBucket* b) { _next = b; } +- nmethod* get_nmethod() { return _nmethod; } +- +- static int mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes); +- static nmethodBucket* add_dependent_nmethod(nmethodBucket* deps, nmethod* nm); +- static bool remove_dependent_nmethod(nmethodBucket** deps, nmethod* nm, bool delete_immediately); +- static bool remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm); +- static nmethodBucket* clean_dependent_nmethods(nmethodBucket* deps); +-#ifndef PRODUCT +- static void print_dependent_nmethods(nmethodBucket* deps, bool verbose); +- static bool is_dependent_nmethod(nmethodBucket* deps, nmethod* nm); +-#endif //PRODUCT +-}; +- + // An iterator that's used to access the inner classes indices in the + // InstanceKlass::_inner_classes array. + class InnerClassesIterator : public StackObj { +diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp +index c0d789b4..bfb902d5 100644 +--- a/hotspot/src/share/vm/prims/jni.cpp ++++ b/hotspot/src/share/vm/prims/jni.cpp +@@ -5107,6 +5107,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { + unit_test_function_call + + // Forward declaration ++void TestDependencyContext_test(); + void TestOS_test(); + void TestReservedSpace_test(); + void TestReserveMemorySpecial_test(); +@@ -5132,6 +5133,7 @@ void ChunkManager_test_list_index(); + void execute_internal_vm_tests() { + if (ExecuteInternalVMTests) { + tty->print_cr("Running internal VM tests"); ++ run_unit_test(TestDependencyContext_test()); + run_unit_test(TestOS_test()); + run_unit_test(TestReservedSpace_test()); + run_unit_test(TestReserveMemorySpecial_test()); +diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp +index d950d4f3..231d62d2 100644 +--- a/hotspot/src/share/vm/prims/methodHandles.cpp ++++ b/hotspot/src/share/vm/prims/methodHandles.cpp +@@ -24,6 +24,7 @@ + + #include "precompiled.hpp" + #include "classfile/symbolTable.hpp" ++#include "code/dependencyContext.hpp" + #include "compiler/compileBroker.hpp" + #include "interpreter/interpreter.hpp" + #include "interpreter/oopMapCache.hpp" +@@ -946,30 +947,33 @@ int MethodHandles::find_MemberNames(KlassHandle k, + return rfill + overflow; + } + ++// Is it safe to remove stale entries from a dependency list? ++static bool safe_to_expunge() { ++ // Since parallel GC threads can concurrently iterate over a dependency ++ // list during safepoint, it is safe to remove entries only when ++ // CodeCache lock is held. ++ return CodeCache_lock->owned_by_self(); ++} ++ + void MethodHandles::add_dependent_nmethod(oop call_site, nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + + oop context = java_lang_invoke_CallSite::context(call_site); +- nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); +- +- nmethodBucket* new_deps = nmethodBucket::add_dependent_nmethod(deps, nm); +- if (deps != new_deps) { +- java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); +- } ++ DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); ++ // Try to purge stale entries on updates. ++ // Since GC doesn't clean dependency contexts rooted at CallSiteContext objects, ++ // in order to avoid memory leak, stale entries are purged whenever a dependency list ++ // is changed (both on addition and removal). Though memory reclamation is delayed, ++ // it avoids indefinite memory usage growth. ++ deps.add_dependent_nmethod(nm, /*expunge_stale_entries=*/safe_to_expunge()); + } + + void MethodHandles::remove_dependent_nmethod(oop call_site, nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + + oop context = java_lang_invoke_CallSite::context(call_site); +- nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); +- +- if (nmethodBucket::remove_dependent_nmethod(deps, nm)) { +- nmethodBucket* new_deps = nmethodBucket::clean_dependent_nmethods(deps); +- if (deps != new_deps) { +- java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); +- } +- } ++ DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); ++ deps.remove_dependent_nmethod(nm, /*expunge_stale_entries=*/safe_to_expunge()); + } + + void MethodHandles::flush_dependent_nmethods(Handle call_site, Handle target) { +@@ -978,21 +982,15 @@ void MethodHandles::flush_dependent_nmethods(Handle call_site, Handle target) { + int marked = 0; + CallSiteDepChange changes(call_site(), target()); + { ++ No_Safepoint_Verifier nsv; + MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + oop context = java_lang_invoke_CallSite::context(call_site()); +- nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); +- +- marked = nmethodBucket::mark_dependent_nmethods(deps, changes); +- if (marked > 0) { +- nmethodBucket* new_deps = nmethodBucket::clean_dependent_nmethods(deps); +- if (deps != new_deps) { +- java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); +- } +- } ++ DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); ++ marked = deps.mark_dependent_nmethods(changes); + } + if (marked > 0) { +- // At least one nmethod has been marked for deoptimization ++ // At least one nmethod has been marked for deoptimization. + VM_Deoptimize op; + VMThread::execute(&op); + } +@@ -1379,6 +1377,8 @@ JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobjec + } + JVM_END + ++// It is called by a Cleaner object which ensures that dropped CallSites properly ++// deallocate their dependency information. + JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject context_jh)) { + Handle context(THREAD, JNIHandles::resolve_non_null(context_jh)); + { +@@ -1387,19 +1387,11 @@ JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject con + + int marked = 0; + { ++ No_Safepoint_Verifier nsv; + MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); +- nmethodBucket* b = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context()); +- while(b != NULL) { +- nmethod* nm = b->get_nmethod(); +- if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) { +- nm->mark_for_deoptimization(); +- marked++; +- } +- nmethodBucket* next = b->next(); +- delete b; +- b = next; +- } +- java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context(), NULL); // reset context ++ assert(safe_to_expunge(), "removal is not safe"); ++ DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context()); ++ marked = deps.remove_all_dependents(); + } + if (marked > 0) { + // At least one nmethod has been marked for deoptimization +diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp +index b1854092..f709db94 100644 +--- a/hotspot/src/share/vm/runtime/init.cpp ++++ b/hotspot/src/share/vm/runtime/init.cpp +@@ -71,6 +71,7 @@ void InlineCacheBuffer_init(); + void compilerOracle_init(); + void compilationPolicy_init(); + void compileBroker_init(); ++void dependencyContext_init(); + + // Initialization after compiler initialization + bool universe_post_init(); // must happen after compiler_init +@@ -127,6 +128,7 @@ jint init_globals() { + compilerOracle_init(); + compilationPolicy_init(); + compileBroker_init(); ++ dependencyContext_init(); + VMRegImpl::set_regName(); + + if (!universe_post_init()) { +diff --git a/hotspot/src/share/vm/runtime/perfData.hpp b/hotspot/src/share/vm/runtime/perfData.hpp +index 4a62d2e0..b9f5c1a7 100644 +--- a/hotspot/src/share/vm/runtime/perfData.hpp ++++ b/hotspot/src/share/vm/runtime/perfData.hpp +@@ -424,6 +424,7 @@ class PerfLongVariant : public PerfLong { + public: + inline void inc() { (*(jlong*)_valuep)++; } + inline void inc(jlong val) { (*(jlong*)_valuep) += val; } ++ inline void dec(jlong val) { inc(-val); } + inline void add(jlong val) { (*(jlong*)_valuep) += val; } + void clear_sample_helper() { _sample_helper = NULL; } + }; +diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp +index 744c43e0..5140c015 100644 +--- a/hotspot/src/share/vm/runtime/vmStructs.cpp ++++ b/hotspot/src/share/vm/runtime/vmStructs.cpp +@@ -330,10 +330,6 @@ typedef OffsetCompactHashtable*) \ + nonstatic_field(InstanceKlass, _default_vtable_indices, Array*) \ + nonstatic_field(Klass, _super_check_offset, juint) \ +@@ -1472,7 +1468,6 @@ typedef OffsetCompactHashtablenext(); ++ delete b; ++ b = next; ++ } ++} ++ + #ifndef PRODUCT + void DependencyContext::print_dependent_nmethods(bool verbose) { + int idx = 0; +@@ -271,28 +283,31 @@ class TestDependencyContext { + + intptr_t _dependency_context; + ++ DependencyContext dependencies() { ++ DependencyContext depContext(&_dependency_context); ++ return depContext; ++ } ++ + TestDependencyContext() : _dependency_context(DependencyContext::EMPTY) { + CodeCache_lock->lock_without_safepoint_check(); + +- DependencyContext depContext(&_dependency_context); +- + _nmethods[0] = reinterpret_cast(0x8 * 0); + _nmethods[1] = reinterpret_cast(0x8 * 1); + _nmethods[2] = reinterpret_cast(0x8 * 2); + +- depContext.add_dependent_nmethod(_nmethods[2]); +- depContext.add_dependent_nmethod(_nmethods[1]); +- depContext.add_dependent_nmethod(_nmethods[0]); ++ dependencies().add_dependent_nmethod(_nmethods[2]); ++ dependencies().add_dependent_nmethod(_nmethods[1]); ++ dependencies().add_dependent_nmethod(_nmethods[0]); + } + + ~TestDependencyContext() { +- wipe(); ++ dependencies().wipe(); + CodeCache_lock->unlock(); + } + + static void testRemoveDependentNmethod(int id, bool delete_immediately) { + TestDependencyContext c; +- DependencyContext depContext(&c._dependency_context); ++ DependencyContext depContext = c.dependencies(); + assert(!has_stale_entries(depContext), "check"); + + nmethod* nm = c._nmethods[id]; +@@ -327,17 +342,6 @@ class TestDependencyContext { + return ctx.has_stale_entries(); + } + +- void wipe() { +- DependencyContext ctx(&_dependency_context); +- nmethodBucket* b = ctx.dependencies(); +- ctx.set_dependencies(NULL); +- ctx.set_has_stale_entries(false); +- while (b != NULL) { +- nmethodBucket* next = b->next(); +- delete b; +- b = next; +- } +- } + }; + + void TestDependencyContext_test() { +diff --git a/hotspot/src/share/vm/code/dependencyContext.hpp b/hotspot/src/share/vm/code/dependencyContext.hpp +index 533112b8..414ce0c0 100644 +--- a/hotspot/src/share/vm/code/dependencyContext.hpp ++++ b/hotspot/src/share/vm/code/dependencyContext.hpp +@@ -143,6 +143,10 @@ class DependencyContext : public StackObj { + + void expunge_stale_entries(); + ++ // Unsafe deallocation of nmethodBuckets. Used in IK::release_C_heap_structures ++ // to clean up the context possibly containing live entries pointing to unloaded nmethods. ++ void wipe(); ++ + #ifndef PRODUCT + void print_dependent_nmethods(bool verbose); + bool is_dependent_nmethod(nmethod* nm); +diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp +index 1bff1309..df44e531 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.cpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.cpp +@@ -2628,12 +2628,16 @@ void InstanceKlass::release_C_heap_structures() { + } + } + +- // release dependencies +- { +- DependencyContext ctx(&_dep_context); +- int marked = ctx.remove_all_dependents(); +- assert(marked == 0, "all dependencies should be already invalidated"); +- } ++ // Release dependencies. ++ // It is desirable to use DC::remove_all_dependents() here, but, unfortunately, ++ // it is not safe (see JDK-8143408). The problem is that the klass dependency ++ // context can contain live dependencies, since there's a race between nmethod & ++ // klass unloading. If the klass is dead when nmethod unloading happens, relevant ++ // dependencies aren't removed from the context associated with the class (see ++ // nmethod::flush_dependencies). It ends up during klass unloading as seemingly ++ // live dependencies pointing to unloaded nmethods and causes a crash in ++ // DC::remove_all_dependents() when it touches unloaded nmethod. ++ dependencies().wipe(); + + // Deallocate breakpoint records + if (breakpoints() != 0x0) { +-- +2.17.1 + diff --git a/8149343-assert-rp-num_q-no_of_gc_workers-failed-sani.patch b/8149343-assert-rp-num_q-no_of_gc_workers-failed-sani.patch new file mode 100644 index 0000000000000000000000000000000000000000..3264beb7813820c9936cea38a5677ffbd9a84ab3 --- /dev/null +++ b/8149343-assert-rp-num_q-no_of_gc_workers-failed-sani.patch @@ -0,0 +1,144 @@ +Date: Sat, 30 Mar 2024 07:12:06 +0000 +Subject: 8149343: assert(rp->num_q() == no_of_gc_workers) failed: + sanity + +--- + .../gc_implementation/g1/g1CollectedHeap.cpp | 20 +++++++++++-------- + .../share/vm/memory/referenceProcessor.cpp | 9 +++++++-- + .../share/vm/memory/referenceProcessor.hpp | 4 +++- + .../TestDynamicNumberOfGCThreads.java | 8 ++++++++ + 4 files changed, 30 insertions(+), 11 deletions(-) + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +index 84d5d4d8..5b156f99 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +@@ -5462,7 +5462,7 @@ public: + _workers(workers), + _active_workers(n_workers) + { +- assert(n_workers > 0, "shouldn't call this otherwise"); ++ g1h->ref_processor_stw()->set_active_mt_degree(n_workers); + } + + // Executes the given task using concurrent marking worker threads. +@@ -5595,7 +5595,9 @@ public: + _queues(task_queues), + _terminator(workers, _queues), + _n_workers(workers) +- { } ++ { ++ g1h->ref_processor_cm()->set_active_mt_degree(workers); ++ } + + void work(uint worker_id) { + ResourceMark rm; +@@ -5760,8 +5762,10 @@ void G1CollectedHeap::process_discovered_references(uint no_of_gc_workers) { + _gc_tracer_stw->gc_id()); + } else { + // Parallel reference processing +- assert(rp->num_q() == no_of_gc_workers, "sanity"); +- assert(no_of_gc_workers <= rp->max_num_q(), "sanity"); ++ assert(no_of_gc_workers <= rp->max_num_q(), ++ err_msg( ++ "Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u", ++ no_of_gc_workers, rp->max_num_q())); + + G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, no_of_gc_workers); + stats = rp->process_discovered_references(&is_alive, +@@ -5796,10 +5800,10 @@ void G1CollectedHeap::enqueue_discovered_references(uint no_of_gc_workers) { + } else { + // Parallel reference enqueueing + +- assert(no_of_gc_workers == workers()->active_workers(), +- "Need to reset active workers"); +- assert(rp->num_q() == no_of_gc_workers, "sanity"); +- assert(no_of_gc_workers <= rp->max_num_q(), "sanity"); ++ assert(no_of_gc_workers <= rp->max_num_q(), ++ err_msg( ++ "Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u", ++ no_of_gc_workers, rp->max_num_q())); + + G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, no_of_gc_workers); + rp->enqueue_discovered_references(&par_task_executor); +diff --git a/hotspot/src/share/vm/memory/referenceProcessor.cpp b/hotspot/src/share/vm/memory/referenceProcessor.cpp +index b916e696..823fd49c 100644 +--- a/hotspot/src/share/vm/memory/referenceProcessor.cpp ++++ b/hotspot/src/share/vm/memory/referenceProcessor.cpp +@@ -136,7 +136,7 @@ void ReferenceProcessor::verify_no_references_recorded() { + guarantee(!_discovering_refs, "Discovering refs?"); + for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { + guarantee(_discovered_refs[i].is_empty(), +- "Found non-empty discovered list"); ++ err_msg("Found non-empty discovered list at %u", i)); + } + } + #endif +@@ -780,6 +780,11 @@ private: + bool _clear_referent; + }; + ++void ReferenceProcessor::set_active_mt_degree(uint v) { ++ _num_q = v; ++ _next_id = 0; ++} ++ + // Balances reference queues. + // Move entries from all queues[0, 1, ..., _max_num_q-1] to + // queues[0, 1, ..., _num_q-1] because only the first _num_q +@@ -862,7 +867,7 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[]) + } + #ifdef ASSERT + size_t balanced_total_refs = 0; +- for (uint i = 0; i < _max_num_q; ++i) { ++ for (uint i = 0; i < _num_q; ++i) { + balanced_total_refs += ref_lists[i].length(); + if (TraceReferenceGC && PrintGCDetails) { + gclog_or_tty->print("%d ", ref_lists[i].length()); +diff --git a/hotspot/src/share/vm/memory/referenceProcessor.hpp b/hotspot/src/share/vm/memory/referenceProcessor.hpp +index 470503ee..da148a6c 100644 +--- a/hotspot/src/share/vm/memory/referenceProcessor.hpp ++++ b/hotspot/src/share/vm/memory/referenceProcessor.hpp +@@ -270,7 +270,7 @@ class ReferenceProcessor : public CHeapObj { + + uint num_q() { return _num_q; } + uint max_num_q() { return _max_num_q; } +- void set_active_mt_degree(uint v) { _num_q = v; } ++ void set_active_mt_degree(uint v); + + DiscoveredList* discovered_refs() { return _discovered_refs; } + +@@ -385,9 +385,11 @@ class ReferenceProcessor : public CHeapObj { + // round-robin mod _num_q (not: _not_ mode _max_num_q) + uint next_id() { + uint id = _next_id; ++ assert(!_discovery_is_mt, "Round robin should only be used in serial discovery"); + if (++_next_id == _num_q) { + _next_id = 0; + } ++ assert(_next_id < _num_q, err_msg("_next_id %u _num_q %u _max_num_q %u", _next_id, _num_q, _max_num_q)); + return id; + } + DiscoveredList* get_discovered_list(ReferenceType rt); +diff --git a/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java b/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java +index f4a6625a..2005a67e 100644 +--- a/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java ++++ b/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java +@@ -63,6 +63,14 @@ public class TestDynamicNumberOfGCThreads { + System.arraycopy(baseArgs, 0, finalArgs, extraArgs.length, baseArgs.length); + pb_enabled = ProcessTools.createJavaProcessBuilder(finalArgs); + verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start())); ++ ++ // Turn on parallel reference processing ++ String[] parRefProcArg = {"-XX:+ParallelRefProcEnabled", "-XX:-ShowMessageBoxOnError"}; ++ String[] parRefArgs = new String[baseArgs.length + parRefProcArg.length]; ++ System.arraycopy(parRefProcArg, 0, parRefArgs, 0, parRefProcArg.length); ++ System.arraycopy(baseArgs, 0, parRefArgs, parRefProcArg.length, baseArgs.length); ++ pb_enabled = ProcessTools.createJavaProcessBuilder(parRefArgs); ++ verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start())); + } + + static class GCTest { +-- +2.17.1 + diff --git a/8220175-serviceability-dcmd-framework-VMVersionTest..patch b/8220175-serviceability-dcmd-framework-VMVersionTest..patch new file mode 100644 index 0000000000000000000000000000000000000000..6c149dcc9c84e3fca7cc713012fa7074d5cfb42c --- /dev/null +++ b/8220175-serviceability-dcmd-framework-VMVersionTest..patch @@ -0,0 +1,24 @@ +Date: Sat, 30 Mar 2024 07:11:17 +0000 +Subject: 8220175: serviceability/dcmd/framework/VMVersionTest.java + fails with a timeout + +--- + hotspot/src/os/linux/vm/perfMemory_linux.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hotspot/src/os/linux/vm/perfMemory_linux.cpp b/hotspot/src/os/linux/vm/perfMemory_linux.cpp +index b45032ed..4746531f 100644 +--- a/hotspot/src/os/linux/vm/perfMemory_linux.cpp ++++ b/hotspot/src/os/linux/vm/perfMemory_linux.cpp +@@ -659,7 +659,7 @@ static int get_namespace_pid(int vmid) { + if (fp) { + int pid, nspid; + int ret; +- while (!feof(fp)) { ++ while (!feof(fp) && !ferror(fp)) { + ret = fscanf(fp, "NSpid: %d %d", &pid, &nspid); + if (ret == 1) { + break; +-- +2.17.1 + diff --git a/8223485-C2-PhaseIdealLoop-create_new_if_for_predicat.patch b/8223485-C2-PhaseIdealLoop-create_new_if_for_predicat.patch new file mode 100644 index 0000000000000000000000000000000000000000..aa9142cca3b26cc0a7789a715206bc85a8f80061 --- /dev/null +++ b/8223485-C2-PhaseIdealLoop-create_new_if_for_predicat.patch @@ -0,0 +1,21 @@ +Subject: 8223485: C2:PhaseIdealLoop::create_new_if_for_predicate() computes wrong IDOM +--- + hotspot/src/share/vm/opto/loopPredicate.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hotspot/src/share/vm/opto/loopPredicate.cpp b/hotspot/src/share/vm/opto/loopPredicate.cpp +index a21702e98..b2a3e86eb 100644 +--- a/hotspot/src/share/vm/opto/loopPredicate.cpp ++++ b/hotspot/src/share/vm/opto/loopPredicate.cpp +@@ -143,7 +143,7 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + Node* ridom = idom(rgn); +- Node* nrdom = dom_lca(ridom, new_iff); ++ Node* nrdom = dom_lca_internal(ridom, new_iff); + set_idom(rgn, nrdom, dom_depth(rgn)); + } + +-- +2.19.1 + diff --git a/8223486-split-if-update_uses-accesses-stale-idom-dat.patch b/8223486-split-if-update_uses-accesses-stale-idom-dat.patch new file mode 100644 index 0000000000000000000000000000000000000000..a98f9e5d45787424808f755473a0feb0c0c3780a --- /dev/null +++ b/8223486-split-if-update_uses-accesses-stale-idom-dat.patch @@ -0,0 +1,38 @@ +Subject: 8223486: split-if update_uses accesses stale idom data +--- + hotspot/src/share/vm/opto/split_if.cpp | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/hotspot/src/share/vm/opto/split_if.cpp b/hotspot/src/share/vm/opto/split_if.cpp +index 94d680c11..636af191d 100644 +--- a/hotspot/src/share/vm/opto/split_if.cpp ++++ b/hotspot/src/share/vm/opto/split_if.cpp +@@ -486,7 +486,9 @@ void PhaseIdealLoop::do_split_if( Node *iff ) { + } + _igvn.remove_dead_node(new_iff); + // Lazy replace IDOM info with the region's dominator +- lazy_replace( iff, region_dom ); ++ lazy_replace(iff, region_dom); ++ lazy_update(region, region_dom); // idom must be update before handle_uses ++ region->set_req(0, NULL); // Break the self-cycle. Required for lazy_update to work on region + + // Now make the original merge point go dead, by handling all its uses. + small_cache region_cache; +@@ -529,13 +531,8 @@ void PhaseIdealLoop::do_split_if( Node *iff ) { + --k; + } // End of while merge point has phis + +- assert(region->outcnt() == 1, "Only self reference should remain"); // Just Self on the Region +- region->set_req(0, NULL); // Break the self-cycle ++ _igvn.remove_dead_node(region); + +- // Any leftover bits in the splitting block must not have depended on local +- // Phi inputs (these have already been split-up). Hence it's safe to hoist +- // these guys to the dominating point. +- lazy_replace( region, region_dom ); + #ifndef PRODUCT + if( VerifyLoopOptimizations ) verify(); + #endif +-- +2.19.1 + diff --git a/8256488-Use-ldpq-stpq-instead-of-ld4-st4-for-small-c.patch b/8256488-Use-ldpq-stpq-instead-of-ld4-st4-for-small-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..a9289985bab6548fe402a26ee4557bb18fbad134 --- /dev/null +++ b/8256488-Use-ldpq-stpq-instead-of-ld4-st4-for-small-c.patch @@ -0,0 +1,60 @@ +Subject: 8256488: Use ldpq/stpq instead of ld4/st4 for small copies in StubGenerator::copy_memory + +-- + .../cpu/aarch64/vm/stubGenerator_aarch64.cpp | 30 ++++++++++++++++--- + 1 file changed, 26 insertions(+), 4 deletions(-) + +diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +index f61028d5007..cf66df296e4 100644 +--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp ++++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +@@ -1149,10 +1149,10 @@ class StubGenerator: public StubCodeGenerator { + Register count, Register tmp, int step) { + copy_direction direction = step < 0 ? copy_backwards : copy_forwards; + bool is_backwards = step < 0; +- int granularity = uabs(step); ++ unsigned granularity = uabs(step); + const Register t0 = r3, t1 = r4; + +- // <= 96 bytes do inline. Direction doesn't matter because we always ++ // <= 80 (or 96 for SIMD) bytes do inline. Direction doesn't matter because we always + // load all the data before writing anything + Label copy4, copy8, copy16, copy32, copy80, copy128, copy_big, finish; + const Register t2 = r5, t3 = r6, t4 = r7, t5 = r8; +@@ -1207,9 +1207,31 @@ class StubGenerator: public StubCodeGenerator { + // (96 bytes if SIMD because we do 32 byes per instruction) + __ bind(copy80); + if (UseSIMDForMemoryOps) { +- __ ld4(v0, v1, v2, v3, __ T16B, Address(s, 0)); ++ __ ldpq(v0, v1, Address(s, 0)); ++ __ ldpq(v2, v3, Address(s, 32)); ++ // Unaligned pointers can be an issue for copying. ++ // The issue has more chances to happen when granularity of data is ++ // less than 4(sizeof(jint)). Pointers for arrays of jint are at least ++ // 4 byte aligned. Pointers for arrays of jlong are 8 byte aligned. ++ // The most performance drop has been seen for the range 65-80 bytes. ++ // For such cases using the pair of ldp/stp instead of the third pair of ++ // ldpq/stpq fixes the performance issue. ++ if (granularity < sizeof (jint)) { ++ Label copy96; ++ __ cmp(count, u1(80/granularity)); ++ __ br(Assembler::HI, copy96); ++ __ ldp(t0, t1, Address(send, -16)); ++ ++ __ stpq(v0, v1, Address(d, 0)); ++ __ stpq(v2, v3, Address(d, 32)); ++ __ stp(t0, t1, Address(dend, -16)); ++ __ b(finish); ++ ++ __ bind(copy96); ++ } + __ ldpq(v4, v5, Address(send, -32)); +- __ st4(v0, v1, v2, v3, __ T16B, Address(d, 0)); ++ __ stpq(v0, v1, Address(d, 0)); ++ __ stpq(v2, v3, Address(d, 32)); + __ stpq(v4, v5, Address(dend, -32)); + } else { + __ ldp(t0, t1, Address(s, 0)); +-- +2.19.1 + diff --git a/GCC-12-reports-some-compiler-warnings.patch b/GCC-12-reports-some-compiler-warnings.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef232eaa39e64e7f17c3b3873650655e7df755ff --- /dev/null +++ b/GCC-12-reports-some-compiler-warnings.patch @@ -0,0 +1,41 @@ +Subject: fix GCC 12 fails to compile AArch64 due to -Wstringop-overflow + +--- + hotspot/make/linux/makefiles/gcc.make | 2 +- + hotspot/src/share/vm/opto/type.cpp | 7 +++++-- + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make +index 7dde7f096..d122f0eae 100644 +--- a/hotspot/make/linux/makefiles/gcc.make ++++ b/hotspot/make/linux/makefiles/gcc.make +@@ -212,7 +212,7 @@ ifeq ($(USE_CLANG), true) + WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body + endif + +-WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value -Wformat=2 -Wreturn-type ++WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value -Wformat=2 -Wreturn-type -Wno-stringop-overflow + + ifeq ($(USE_CLANG),) + # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit +diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp +index 58572f137..92d4e6b70 100644 +--- a/hotspot/src/share/vm/opto/type.cpp ++++ b/hotspot/src/share/vm/opto/type.cpp +@@ -2553,8 +2553,11 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o + _offset >= InstanceMirrorKlass::offset_of_static_fields()) { + // Static fields + assert(o != NULL, "must be constant"); +- ciInstanceKlass* k = o->as_instance()->java_lang_Class_klass()->as_instance_klass(); +- ciField* field = k->get_field_by_offset(_offset, true); ++ ciField* field = NULL; ++ if (o != NULL) { ++ ciInstanceKlass* k = o->as_instance()->java_lang_Class_klass()->as_instance_klass(); ++ field = k->get_field_by_offset(_offset, true); ++ } + assert(field != NULL, "missing field"); + BasicType basic_elem_type = field->layout_type(); + _is_ptr_to_narrowoop = UseCompressedOops && (basic_elem_type == T_OBJECT || +-- +2.22.0 + diff --git a/add-missing-test-case.patch b/add-missing-test-case.patch index 1cdbfb9f33a1775e29ecf4a5b93848b7f68468b5..6e71d6cb01256f2e8fc579b861751c8500bc7c4f 100644 --- a/add-missing-test-case.patch +++ b/add-missing-test-case.patch @@ -91,7 +91,7 @@ index 00000000..9b614024 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ -+8.402.8.0.13 ++8.412.8.0.13 -- 2.23.0 diff --git a/fix-GCC-12-build-jdk8-fastdebug-error.patch b/fix-GCC-12-build-jdk8-fastdebug-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..1120a3a5856586ddd8322d9d4dd205fa31863ab9 --- /dev/null +++ b/fix-GCC-12-build-jdk8-fastdebug-error.patch @@ -0,0 +1,45 @@ +Subject: Fix GCC 12 build jdk8 fastdebug error +--- + .../vm/gc_implementation/g1/concurrentMark.cpp | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +index df901a52d..1347a7e16 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +@@ -2914,13 +2914,23 @@ void ConcurrentMark::print_reachable(const char* str, + return; + } + +- char file_name[JVM_MAXPATHLEN]; ++ // fix gcc 12 build jdk8 fastdebug compiler error: ++ // directive writing up to 4096 bytes into a region of size between 0 and 4096 [-Werror=format-overflow=] ++ // about old code: ++ // char file_name[JVM_MAXPATHLEN]; ++ // Leave L 2911~2915 code unchanged, so not affect original logic. ++ char *file_name = (char *) NEW_C_HEAP_ARRAY(char, strlen(G1PrintReachableBaseFile) + 2 + strlen(str), mtGC); ++ if (NULL == file_name) { ++ gclog_or_tty->print_cr(" #### error: NEW_C_HEAP_ARRAY failed."); ++ return; ++ } + sprintf(file_name, "%s.%s", G1PrintReachableBaseFile, str); + gclog_or_tty->print_cr(" dumping to file %s", file_name); + + fileStream fout(file_name); + if (!fout.is_open()) { + gclog_or_tty->print_cr(" #### error: could not open file"); ++ FREE_C_HEAP_ARRAY(char, file_name, mtGC); + return; + } + +@@ -2936,6 +2946,7 @@ void ConcurrentMark::print_reachable(const char* str, + + gclog_or_tty->print_cr(" done"); + gclog_or_tty->flush(); ++ FREE_C_HEAP_ARRAY(char, file_name, mtGC); + } + + #endif // PRODUCT +-- +2.22.0 + diff --git a/fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch b/fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch deleted file mode 100644 index d1490858b052c1c8b8b231d470b42651663622f5..0000000000000000000000000000000000000000 --- a/fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 102b398cc59e95cb4f5327b9c8fc9a3c5594acce Mon Sep 17 00:00:00 2001 -From: eapen -Date: Tue, 29 Nov 2022 09:23:01 +0800 -Subject: [PATCH 29/33] I68TO2: fix the length value of ciBlock in ciMethodBlocks.cpp ---- - hotspot/src/share/vm/ci/ciMethodBlocks.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp -index 614e75d..3ce828e 100644 ---- a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp -+++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp -@@ -372,7 +372,7 @@ static const char *flagnames[] = { - - void ciBlock::dump() { - tty->print(" [%d .. %d), {", _start_bci, _limit_bci); -- for (int i = 0; i < 8; i++) { -+ for (int i = 0; i < 7; i++) { - if ((_flags & (1 << i)) != 0) { - tty->print(" %s", flagnames[i]); - } --- -1.8.3.1 diff --git a/fix_X509TrustManagerImpl_symantec_distrust.patch b/fix_X509TrustManagerImpl_symantec_distrust.patch index 83426e6ae5e3a329c39b1e5ad9760d05bcb97ff2..65eeab574e11fab612e15f7535da3be6218528fa 100644 --- a/fix_X509TrustManagerImpl_symantec_distrust.patch +++ b/fix_X509TrustManagerImpl_symantec_distrust.patch @@ -40,16 +40,16 @@ index 54e1bfa0d..c1423dc5b 100644 // The numbers of certs now. - private static final int COUNT = 83; -+ private static final int COUNT = 100; ++ private static final int COUNT = 102; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 private static final String CHECKSUM - = "2D:04:88:6C:52:53:54:EB:38:2D:BC:E0:AF:B7:82:F4:9E:32:A8:1A:1B:A3:AE:CF:25:CB:C2:F6:0F:4E:E1:20"; -+ = "30:6A:9A:00:BF:95:59:BC:FB:4C:ED:89:F6:DB:50:25:8D:F6:D6:F0:BC:C8:FC:A3:E6:AF:62:7A:FD:F6:89:51"; ++ = "2F:92:41:50:3B:2B:F2:AD:86:54:AB:2B:D4:AB:A2:92:8B:B6:1C:2B:58:A1:E3:1A:CE:43:43:FB:3E:94:2E:7E"; + // map of cert alias to SHA-256 fingerprint @SuppressWarnings("serial") - private static final Map FINGERPRINT_MAP @@ -111,7 +111,9 @@ public class VerifyCACerts { "7E:37:CB:8B:4C:47:09:0C:AB:36:55:1B:A6:F4:5D:B8:40:68:0F:BA:16:6A:95:2D:B1:00:71:7F:43:05:3F:C2"); put("digicerthighassuranceevrootca [jdk]", diff --git a/jdk8u-jdk8u402-b06.tar.xz b/jdk8u-jdk8u412-b08.tar.xz similarity index 82% rename from jdk8u-jdk8u402-b06.tar.xz rename to jdk8u-jdk8u412-b08.tar.xz index f7e09c919061fab0a2f8a0a4b2092fda656b8fa5..41cfa2c9f1415ac1eb687d9ce7f4919ee9e95725 100644 Binary files a/jdk8u-jdk8u402-b06.tar.xz and b/jdk8u-jdk8u412-b08.tar.xz differ diff --git a/kae-phase2.patch b/kae-phase2.patch index 0717b274e592b9adf25250913ac8c37addbef25e..3bdc0cafc73cdcdd911e045ad2d61f20f400c3d3 100644 --- a/kae-phase2.patch +++ b/kae-phase2.patch @@ -6480,8 +6480,8 @@ index 9733e17c..d1b13922 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -180,6 +180,9 @@ jdk_security = \ - jdk_security_infra = \ - security/infra/java/security/cert/CertPathValidator/certification + security/infra/java/security/cert/CertPathValidator/certification \ + sun/security/lib/cacerts +jdk_kae_security = \ + org/openeuler/security/openssl diff --git a/openjdk-1.8.0.spec b/openjdk-1.8.0.spec index 592a1d5f0ca0274d26c1c4e12a7f18ebc5e2c7c6..6a970e740d299604640759f98420abcf99aa0059 100644 --- a/openjdk-1.8.0.spec +++ b/openjdk-1.8.0.spec @@ -166,13 +166,13 @@ %global origin_nice OpenJDK %global top_level_dir_name %{origin} %global repo jdk8u -%global revision jdk8u402-b06 +%global revision jdk8u412-b08 %global full_revision %{repo}-%{revision} # Define IcedTea version used for SystemTap tapsets and desktop files %global icedteaver 3.15.0 -%global updatever 402 -%global buildver b06 +%global updatever 412 +%global buildver b08 # priority must be 7 digits in total. The expression is workarounding tip %global priority 1800%{updatever} @@ -936,7 +936,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 3 +Release: 0 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1185,7 +1185,6 @@ Patch288: 8200720-Print-additional-information-in-thread-dump-.patch Patch289: support-numactl-for-hadoop-yarn.patch Patch290: 8232069-enable-shutdown-UseCompressedClassPointers-U.patch Patch291: 8065402-G1-does-not-expand-marking-stack-when-mark-s.patch -Patch292: fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch Patch293: 8140594-Various-minor-code-improvements-compiler.patch Patch294: Fix-the-crash-that-occurs-when-the-process-exits-due.patch Patch295: Fix-AsyncGCLog-s-content-consistent-bug.patch @@ -1309,6 +1308,18 @@ Patch416: 8260923-Add-more-tests-for-SSLSocket-input-output-sh.patch Patch417: 8057967-CallSite-dependency-tracking-scales-devastat.patch Patch418: 8079205-CallSite-dependency-tracking-is-broken-after.patch +#402 +Patch421: 8220175-serviceability-dcmd-framework-VMVersionTest..patch +Patch422: 8149343-assert-rp-num_q-no_of_gc_workers-failed-sani.patch +Patch423: 8139595-MethodHandles-remove_dependent_nmethod-is-no.patch +Patch424: 8143408-Crash-during-InstanceKlass-unloading-when-cl.patch +Patch425: GCC-12-reports-some-compiler-warnings.patch +Patch426: fix-GCC-12-build-jdk8-fastdebug-error.patch +Patch427: 8223485-C2-PhaseIdealLoop-create_new_if_for_predicat.patch +Patch428: 8223486-split-if-update_uses-accesses-stale-idom-dat.patch + +#412 +Patch429: 8256488-Use-ldpq-stpq-instead-of-ld4-st4-for-small-c.patch ############################################# # # Upstreamable patches @@ -1828,7 +1839,6 @@ pushd %{top_level_dir_name} %patch289 -p1 %patch290 -p1 %patch291 -p1 -%patch292 -p1 %patch293 -p1 %patch294 -p1 %patch295 -p1 @@ -1943,6 +1953,15 @@ pushd %{top_level_dir_name} %patch416 -p1 %patch417 -p1 %patch418 -p1 +%patch421 -p1 +%patch422 -p1 +%patch423 -p1 +%patch424 -p1 +%patch425 -p1 +%patch426 -p1 +%patch427 -p1 +%patch428 -p1 +%patch429 -p1 %endif %ifarch loongarch64 @@ -2601,6 +2620,33 @@ cjc.mainProgram(arg) %endif %changelog +* Sun Apr 28 2024 Autistic_boyya -1:1.8.0.412-b08.1 +- add 8256488-Use-ldpq-stpq-instead-of-ld4-st4-for-small-c.patch + +* Thu Apr 18 2024 Autistic_boyya -1:1.8.0.412-b08.0 +- del 8322725-tz-Update-Timezone-Data-to-2023d.patch +- del 8325150-tz-Update-Timezone-Data-to-2024a.patch +- del fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch +- modified 8014628-Support-AES-Encryption-with-HMAC-SHA2-for-Ke.patch +- modified 8057743-process-Synchronize-exiting-of-threads-and-p.patch +- modified add-missing-test-case.patch +- modified fix_X509TrustManagerImpl_symantec_distrust.patch +- modified kae-phase2.patch +- modified support-numactl-for-hadoop-yarn.patch +- modified update-cacerts-and-VerifyCACerts.java-test.patch + +* Tue Apr 2 2024 kuenking111 - 1:1.8.0.402-b06.5 +- add fix-GCC-12-build-jdk8-fastdebug-error.patch + +* Sat Mar 30 2024 Benshuai5D - 1:1.8.0.402-b06.4 +- add 8322725-tz-Update-Timezone-Data-to-2023d.patch +- add 8325150-tz-Update-Timezone-Data-to-2024a.patch +- add 8220175-serviceability-dcmd-framework-VMVersionTest..patch +- add 8149343-assert-rp-num_q-no_of_gc_workers-failed-sani.patch +- add 8139595-MethodHandles-remove_dependent_nmethod-is-no.patch +- add 8143408-Crash-during-InstanceKlass-unloading-when-cl.patch +- add GCC-12-reports-some-compiler-warnings.patch + * Tue Mar 12 2024 jiahua.yu - 1:1.8.0.402-b06.3 - Init support for arch ppc64le diff --git a/support-numactl-for-hadoop-yarn.patch b/support-numactl-for-hadoop-yarn.patch index 80c7d61fa13f5eab38bce6fb487f306596605014..bd619d3c8d41e69bdc71b7d7876f347053f0ea21 100644 --- a/support-numactl-for-hadoop-yarn.patch +++ b/support-numactl-for-hadoop-yarn.patch @@ -353,7 +353,7 @@ index dde3975..dd40c2c 100644 + argv_for_execvp = (const char**)raw_argv; +} + - _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) { + static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { #ifndef USDT2 HS_DTRACE_PROBE3(hotspot_jni, CreateJavaVM__entry, vm, penv, args); diff --git a/hotspot/src/share/vm/prims/jni.h b/hotspot/src/share/vm/prims/jni.h diff --git a/update-cacerts-and-VerifyCACerts.java-test.patch b/update-cacerts-and-VerifyCACerts.java-test.patch index 22fc8c65fd42e99ff7b432222aea0a87311afdb2..4128a07b63afd355bbe18e3a7cfd327cd31e7e86 100644 --- a/update-cacerts-and-VerifyCACerts.java-test.patch +++ b/update-cacerts-and-VerifyCACerts.java-test.patch @@ -257,17 +257,17 @@ index dd107fc..791ddb6 100644 + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. -- private static final int COUNT = 106; +- private static final int COUNT = 108; + private static final int COUNT = 83; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 private static final String CHECKSUM -- = "61:5F:6D:C5:9C:A3:8A:65:3F:CB:F9:F5:26:04:23:F4:53:A6:8C:B3:8B:2B:0A:F0:66:7D:9E:67:B9:4D:AC:B7"; +- = "81:D4:84:F6:92:78:A4:82:25:06:DC:42:25:C9:5D:6C:63:E4:99:CE:BC:ED:66:B3:8C:BA:E6:BA:6B:34:0F:01"; + = "2D:04:88:6C:52:53:54:EB:38:2D:BC:E0:AF:B7:82:F4:9E:32:A8:1A:1B:A3:AE:CF:25:CB:C2:F6:0F:4E:E1:20"; + // map of cert alias to SHA-256 fingerprint @SuppressWarnings("serial") - private static final Map FINGERPRINT_MAP @@ -93,12 +93,6 @@ public class VerifyCACerts { "E7:93:C9:B0:2F:D8:AA:13:E2:1C:31:22:8A:CC:B0:81:19:64:3B:74:9C:89:89:64:B1:74:6D:46:C3:D4:CB:D2"); put("usertrusteccca [jdk]",