diff --git a/0019-8040213-C2-does-not-put-all-modified-nodes-on-IGVN-w.patch b/0019-8040213-C2-does-not-put-all-modified-nodes-on-IGVN-w.patch index 4fdf7099b177a19e30069aee92f2ee1b538acbf0..9d3d8889b55d97f6ada3b75615d6b73f5e96e249 100644 --- a/0019-8040213-C2-does-not-put-all-modified-nodes-on-IGVN-w.patch +++ b/0019-8040213-C2-does-not-put-all-modified-nodes-on-IGVN-w.patch @@ -361,16 +361,6 @@ index d8143821b..1b7c768df 100644 _igvn.hash_insert(n); } -@@ -541,8 +540,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { - assert(check_iff->in(1)->Opcode() == Op_Conv2B && - check_iff->in(1)->in(1)->Opcode() == Op_Opaque1, ""); - Node* opq = check_iff->in(1)->in(1); -- _igvn.hash_delete(opq); -- opq->set_req(1, bol); -+ _igvn.replace_input_of(opq, 1, bol); - // Update ctrl. - set_ctrl(opq, check_iff->in(0)); - set_ctrl(check_iff->in(1), check_iff->in(0)); @@ -712,7 +710,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { incr->set_req(2,stride); incr = _igvn.register_new_node_with_optimizer(incr); diff --git a/8057967-CallSite-dependency-tracking-scales-devastat.patch b/8057967-CallSite-dependency-tracking-scales-devastat.patch new file mode 100644 index 0000000000000000000000000000000000000000..e5c7cd2e5c26e0527027e3dd830e572b86dbc022 --- /dev/null +++ b/8057967-CallSite-dependency-tracking-scales-devastat.patch @@ -0,0 +1,753 @@ +From 1059c5d5f9d1e50607c726b619f39ac68954bda7 Mon Sep 17 00:00:00 2001 +From: zhangyipeng +Date: Mon, 15 Jan 2024 11:40:07 +0800 +Subject: [PATCH] [Backport]8057967: CallSite dependency tracking scales devastatingly + poorly +--- + hotspot/src/share/vm/ci/ciCallSite.cpp | 19 +++ + hotspot/src/share/vm/ci/ciCallSite.hpp | 1 + + hotspot/src/share/vm/classfile/javaClasses.cpp | 48 +++++- + hotspot/src/share/vm/classfile/javaClasses.hpp | 9 +- + hotspot/src/share/vm/classfile/vmSymbols.hpp | 4 +- + hotspot/src/share/vm/code/dependencies.cpp | 27 ++-- + hotspot/src/share/vm/code/dependencies.hpp | 7 +- + hotspot/src/share/vm/memory/universe.cpp | 8 +- + hotspot/src/share/vm/prims/methodHandles.cpp | 50 +++++- + hotspot/src/share/vm/prims/methodHandles.hpp | 3 + + .../compiler/jsr292/CallSiteDepContextTest.java | 179 +++++++++++++++++++++ + .../share/classes/java/lang/invoke/CallSite.java | 55 ++++++- + .../java/lang/invoke/MethodHandleNatives.java | 4 + + 13 files changed, 385 insertions(+), 29 deletions(-) + create mode 100644 hotspot/test/compiler/jsr292/CallSiteDepContextTest.java + +diff --git a/hotspot/src/share/vm/ci/ciCallSite.cpp b/hotspot/src/share/vm/ci/ciCallSite.cpp +index 794042a79..f58346aea 100644 +--- a/hotspot/src/share/vm/ci/ciCallSite.cpp ++++ b/hotspot/src/share/vm/ci/ciCallSite.cpp +@@ -49,6 +49,25 @@ ciMethodHandle* ciCallSite::get_target() const { + } + + // ------------------------------------------------------------------ ++// ciCallSite::get_context ++// ++// Return the target MethodHandle of this CallSite. ++ciKlass* ciCallSite::get_context() { ++ assert(!is_constant_call_site(), ""); ++ ++ VM_ENTRY_MARK; ++ oop call_site_oop = get_oop(); ++ InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site_oop); ++ if (ctxk == NULL) { ++ // The call site doesn't have a context associated. Set it to the default context. ++ oop def_context_oop = java_lang_invoke_CallSite::default_context(); ++ java_lang_invoke_CallSite::set_context_cas(call_site_oop, def_context_oop, /*expected=*/NULL); ++ ctxk = MethodHandles::get_call_site_context(call_site_oop); ++ } ++ return (CURRENT_ENV->get_metadata(ctxk))->as_klass(); ++} ++ ++// ------------------------------------------------------------------ + // ciCallSite::print + // + // Print debugging information about the CallSite. +diff --git a/hotspot/src/share/vm/ci/ciCallSite.hpp b/hotspot/src/share/vm/ci/ciCallSite.hpp +index 063f1e3a5..040e894d0 100644 +--- a/hotspot/src/share/vm/ci/ciCallSite.hpp ++++ b/hotspot/src/share/vm/ci/ciCallSite.hpp +@@ -43,6 +43,7 @@ public: + + // Return the target MethodHandle of this CallSite. + ciMethodHandle* get_target() const; ++ ciKlass* get_context(); + + void print(); + }; +diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp +index 9db88611b..fc4165b04 100644 +--- a/hotspot/src/share/vm/classfile/javaClasses.cpp ++++ b/hotspot/src/share/vm/classfile/javaClasses.cpp +@@ -100,21 +100,22 @@ InjectedField* JavaClasses::get_injected(Symbol* class_name, int* field_count) { + static bool find_field(InstanceKlass* ik, + Symbol* name_symbol, Symbol* signature_symbol, + fieldDescriptor* fd, +- bool allow_super = false) { +- if (allow_super) +- return ik->find_field(name_symbol, signature_symbol, fd) != NULL; +- else ++ bool is_static = false, bool allow_super = false) { ++ if (allow_super || is_static) { ++ return ik->find_field(name_symbol, signature_symbol, is_static, fd) != NULL; ++ } else { + return ik->find_local_field(name_symbol, signature_symbol, fd); ++ } + } + + // Helpful routine for computing field offsets at run time rather than hardcoding them + static void + compute_offset(int &dest_offset, + Klass* klass_oop, Symbol* name_symbol, Symbol* signature_symbol, +- bool allow_super = false) { ++ bool is_static = false, bool allow_super = false) { + fieldDescriptor fd; + InstanceKlass* ik = InstanceKlass::cast(klass_oop); +- if (!find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) { ++ if (!find_field(ik, name_symbol, signature_symbol, &fd, is_static, allow_super)) { + ResourceMark rm; + tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string()); + #ifndef PRODUCT +@@ -3002,15 +3003,50 @@ int java_lang_invoke_MethodType::rtype_slot_count(oop mt) { + // Support for java_lang_invoke_CallSite + + int java_lang_invoke_CallSite::_target_offset; ++int java_lang_invoke_CallSite::_context_offset; ++int java_lang_invoke_CallSite::_default_context_offset; + + void java_lang_invoke_CallSite::compute_offsets() { + if (!EnableInvokeDynamic) return; + Klass* k = SystemDictionary::CallSite_klass(); + if (k != NULL) { + compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_lang_invoke_MethodHandle_signature()); ++ compute_offset(_context_offset, k, vmSymbols::context_name(), vmSymbols::sun_misc_Cleaner_signature()); ++ compute_offset(_default_context_offset, k, ++ vmSymbols::DEFAULT_CONTEXT_name(), vmSymbols::sun_misc_Cleaner_signature(), ++ /*is_static=*/true, /*allow_super=*/false); + } + } + ++oop java_lang_invoke_CallSite::context_volatile(oop call_site) { ++ assert(java_lang_invoke_CallSite::is_instance(call_site), ""); ++ ++ oop dep_oop = call_site->obj_field_volatile(_context_offset); ++ return dep_oop; ++} ++ ++void java_lang_invoke_CallSite::set_context_volatile(oop call_site, oop context) { ++ assert(java_lang_invoke_CallSite::is_instance(call_site), ""); ++ call_site->obj_field_put_volatile(_context_offset, context); ++} ++ ++bool java_lang_invoke_CallSite::set_context_cas(oop call_site, oop context, oop expected) { ++ assert(java_lang_invoke_CallSite::is_instance(call_site), ""); ++ HeapWord* context_addr = call_site->obj_field_addr(_context_offset); ++ oop res = oopDesc::atomic_compare_exchange_oop(context, context_addr, expected, true); ++ bool success = (res == expected); ++ if (success) { ++ update_barrier_set((void*)context_addr, context); ++ } ++ return success; ++} ++ ++oop java_lang_invoke_CallSite::default_context() { ++ InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::CallSite_klass()); ++ oop def_context_oop = ik->java_mirror()->obj_field(_default_context_offset); ++ assert(!oopDesc::is_null(def_context_oop), ""); ++ return def_context_oop; ++} + + // Support for java_security_AccessControlContext + +diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp +index d6e288fb8..35934319d 100644 +--- a/hotspot/src/share/vm/classfile/javaClasses.hpp ++++ b/hotspot/src/share/vm/classfile/javaClasses.hpp +@@ -1212,6 +1212,9 @@ class java_lang_invoke_CallSite: AllStatic { + + private: + static int _target_offset; ++ static int _context_offset; ++ static int _default_context_offset; ++ + + static void compute_offsets(); + +@@ -1222,6 +1225,11 @@ public: + + static volatile oop target_volatile(oop site) { return oop((oopDesc *)(site->obj_field_volatile(_target_offset))); } + static void set_target_volatile(oop site, oop target) { site->obj_field_put_volatile(_target_offset, target); } ++ static oop context_volatile(oop site); ++ static void set_context_volatile(oop site, oop context); ++ static bool set_context_cas (oop site, oop context, oop expected); ++ ++ static oop default_context(); + + // Testers + static bool is_subclass(Klass* klass) { +@@ -1235,7 +1243,6 @@ public: + static int target_offset_in_bytes() { return _target_offset; } + }; + +- + // Interface to java.security.AccessControlContext objects + + class java_security_AccessControlContext: AllStatic { +diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp +index 494fd9bdf..f92b709ed 100644 +--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp ++++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp +@@ -301,6 +301,7 @@ + template(setTargetNormal_name, "setTargetNormal") \ + template(setTargetVolatile_name, "setTargetVolatile") \ + template(setTarget_signature, "(Ljava/lang/invoke/MethodHandle;)V") \ ++ template(DEFAULT_CONTEXT_name, "DEFAULT_CONTEXT") \ + NOT_LP64( do_alias(intptr_signature, int_signature) ) \ + LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ + \ +@@ -517,6 +518,7 @@ + template(string_signature, "Ljava/lang/String;") \ + template(reference_signature, "Ljava/lang/ref/Reference;") \ + template(referencequeue_signature, "Ljava/lang/ref/ReferenceQueue;") \ ++ template(sun_misc_Cleaner_signature, "Lsun/misc/Cleaner;") \ + template(executable_signature, "Ljava/lang/reflect/Executable;") \ + template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ + template(String_StringBuilder_signature, "(Ljava/lang/String;)Ljava/lang/StringBuilder;") \ +@@ -570,7 +572,7 @@ + template(createGarbageCollectorMBean_signature, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/management/GarbageCollectorMBean;") \ + template(trigger_name, "trigger") \ + template(clear_name, "clear") \ +- template(trigger_method_signature, "(ILjava/lang/management/MemoryUsage;)V") \ ++ template(trigger_method_signature, "(ILjava/lang/management/MemoryUsage;)V") \ + template(startAgent_name, "startAgent") \ + template(startRemoteAgent_name, "startRemoteManagementAgent") \ + template(startLocalAgent_name, "startLocalManagementAgent") \ +diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp +index d1fe08b54..decbce8be 100644 +--- a/hotspot/src/share/vm/code/dependencies.cpp ++++ b/hotspot/src/share/vm/code/dependencies.cpp +@@ -123,8 +123,9 @@ void Dependencies::assert_has_no_finalizable_subclasses(ciKlass* ctxk) { + } + + void Dependencies::assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle) { +- check_ctxk(call_site->klass()); +- assert_common_2(call_site_target_value, call_site, method_handle); ++ ciKlass* ctxk = call_site->get_context(); ++ check_ctxk(ctxk); ++ assert_common_3(call_site_target_value, ctxk, call_site, method_handle); + } + + // Helper function. If we are adding a new dep. under ctxk2, +@@ -396,7 +397,7 @@ int Dependencies::_dep_args[TYPE_LIMIT] = { + 3, // unique_concrete_methods_2 ctxk, m1, m2 + 2, // unique_implementor ctxk, implementor + 1, // no_finalizable_subclasses ctxk +- 2 // call_site_target_value call_site, method_handle ++ 3 // call_site_target_value ctxk, call_site, method_handle + }; + + const char* Dependencies::dep_name(Dependencies::DepType dept) { +@@ -598,7 +599,7 @@ void Dependencies::DepStream::log_dependency(Klass* witness) { + const int nargs = argument_count(); + GrowableArray* args = new GrowableArray(nargs); + for (int j = 0; j < nargs; j++) { +- if (type() == call_site_target_value) { ++ if (is_oop_argument(j)) { + args->push(argument_oop(j)); + } else { + args->push(argument(j)); +@@ -726,7 +727,7 @@ Klass* Dependencies::DepStream::context_type() { + } + + // Some dependencies are using the klass of the first object +- // argument as implicit context type (e.g. call_site_target_value). ++ // argument as implicit context type. + { + int ctxkj = dep_implicit_context_arg(type()); + if (ctxkj >= 0) { +@@ -1647,9 +1648,16 @@ Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepCh + return find_finalizable_subclass(search_at); + } + +-Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) { +- assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity"); +- assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity"); ++Klass* Dependencies::check_call_site_target_value(Klass* recorded_ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes) { ++ assert(call_site->is_a(SystemDictionary::CallSite_klass()), "sanity"); ++ assert(!oopDesc::is_null(method_handle), "sanity"); ++ ++ Klass* call_site_ctxk = MethodHandles::get_call_site_context(call_site); ++ assert(!Klass::is_null(call_site_ctxk), "call site context should be initialized already"); ++ if (recorded_ctxk != call_site_ctxk) { ++ // Stale context ++ return recorded_ctxk; ++ } + if (changes == NULL) { + // Validate all CallSites + if (java_lang_invoke_CallSite::target(call_site) != method_handle) +@@ -1664,7 +1672,6 @@ Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_hand + return NULL; // assertion still valid + } + +- + void Dependencies::DepStream::trace_and_log_witness(Klass* witness) { + if (witness != NULL) { + if (TraceDependencies) { +@@ -1728,7 +1735,7 @@ Klass* Dependencies::DepStream::check_call_site_dependency(CallSiteDepChange* ch + Klass* witness = NULL; + switch (type()) { + case call_site_target_value: +- witness = check_call_site_target_value(argument_oop(0), argument_oop(1), changes); ++ witness = check_call_site_target_value(context_type(), argument_oop(1), argument_oop(2), changes); + break; + default: + witness = NULL; +diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp +index 0392d4e3d..da2201c3f 100644 +--- a/hotspot/src/share/vm/code/dependencies.hpp ++++ b/hotspot/src/share/vm/code/dependencies.hpp +@@ -176,7 +176,7 @@ class Dependencies: public ResourceObj { + klass_types = all_types & ~non_klass_types, + + non_ctxk_types = (1 << evol_method), +- implicit_ctxk_types = (1 << call_site_target_value), ++ implicit_ctxk_types = 0, + explicit_ctxk_types = all_types & ~(non_ctxk_types | implicit_ctxk_types), + + max_arg_count = 3, // current maximum number of arguments (incl. ctxk) +@@ -340,7 +340,7 @@ class Dependencies: public ResourceObj { + static Klass* check_exclusive_concrete_methods(Klass* ctxk, Method* m1, Method* m2, + KlassDepChange* changes = NULL); + static Klass* check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes = NULL); +- static Klass* check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); ++ static Klass* check_call_site_target_value(Klass* recorded_ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); + // A returned Klass* is NULL if the dependency assertion is still + // valid. A non-NULL Klass* is a 'witness' to the assertion + // failure, a point in the class hierarchy where the assertion has +@@ -506,6 +506,7 @@ class Dependencies: public ResourceObj { + bool next(); + + DepType type() { return _type; } ++ bool is_oop_argument(int i) { return type() == call_site_target_value && i > 0; } + int argument_count() { return dep_args(type()); } + int argument_index(int i) { assert(0 <= i && i < argument_count(), "oob"); + return _xi[i]; } +@@ -664,7 +665,7 @@ class CallSiteDepChange : public DepChange { + _method_handle(method_handle) + { + assert(_call_site() ->is_a(SystemDictionary::CallSite_klass()), "must be"); +- assert(_method_handle()->is_a(SystemDictionary::MethodHandle_klass()), "must be"); ++ assert(_method_handle.is_null() || _method_handle()->is_a(SystemDictionary::MethodHandle_klass()), "must be"); + } + + // What kind of DepChange is this? +diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp +index 23433d187..7028d378e 100644 +--- a/hotspot/src/share/vm/memory/universe.cpp ++++ b/hotspot/src/share/vm/memory/universe.cpp +@@ -56,6 +56,7 @@ + #include "oops/oop.inline.hpp" + #include "oops/typeArrayKlass.hpp" + #include "prims/jvmtiRedefineClassesTrace.hpp" ++#include "prims/methodHandles.hpp" + #include "runtime/arguments.hpp" + #include "runtime/deoptimization.hpp" + #include "runtime/fprofiler.hpp" +@@ -1233,8 +1234,11 @@ void Universe::flush_dependents_on(Handle call_site, Handle method_handle) { + int marked = 0; + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); +- InstanceKlass* call_site_klass = InstanceKlass::cast(call_site->klass()); +- marked = call_site_klass->mark_dependent_nmethods(changes); ++ InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site()); ++ if (ctxk == NULL) { ++ return; // No dependencies to invalidate yet. ++ } ++ marked = ctxk->mark_dependent_nmethods(changes); + } + if (marked > 0) { + // At least one nmethod has been marked for deoptimization +diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp +index 29598d500..c1cbabec2 100644 +--- a/hotspot/src/share/vm/prims/methodHandles.cpp ++++ b/hotspot/src/share/vm/prims/methodHandles.cpp +@@ -946,6 +946,24 @@ int MethodHandles::find_MemberNames(KlassHandle k, + return rfill + overflow; + } + ++// Get context class for a CallSite instance: either extract existing context or use default one. ++InstanceKlass* MethodHandles::get_call_site_context(oop call_site) { ++ // In order to extract a context the following traversal is performed: ++ // CallSite.context => Cleaner.referent => Class._klass => Klass ++ assert(java_lang_invoke_CallSite::is_instance(call_site), ""); ++ oop context_oop = java_lang_invoke_CallSite::context_volatile(call_site); ++ if (oopDesc::is_null(context_oop)) { ++ return NULL; // The context hasn't been initialized yet. ++ } ++ oop context_class_oop = java_lang_ref_Reference::referent(context_oop); ++ if (oopDesc::is_null(context_class_oop)) { ++ // The context reference was cleared by GC, so current dependency context ++ // isn't usable anymore. Context should be fetched from CallSite again. ++ return NULL; ++ } ++ return InstanceKlass::cast(java_lang_Class::as_Klass(context_class_oop)); ++} ++ + //------------------------------------------------------------------------------ + // MemberNameTable + // +@@ -1305,7 +1323,7 @@ JVM_END + + JVM_ENTRY(void, MHN_setCallSiteTargetNormal(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) { + Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh)); +- Handle target (THREAD, JNIHandles::resolve(target_jh)); ++ Handle target (THREAD, JNIHandles::resolve_non_null(target_jh)); + { + // Walk all nmethods depending on this call site. + MutexLocker mu(Compile_lock, thread); +@@ -1317,7 +1335,7 @@ JVM_END + + JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) { + Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh)); +- Handle target (THREAD, JNIHandles::resolve(target_jh)); ++ Handle target (THREAD, JNIHandles::resolve_non_null(target_jh)); + { + // Walk all nmethods depending on this call site. + MutexLocker mu(Compile_lock, thread); +@@ -1327,6 +1345,33 @@ JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobjec + } + JVM_END + ++JVM_ENTRY(void, MHN_invalidateDependentNMethods(JNIEnv* env, jobject igcls, jobject call_site_jh)) { ++ Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh)); ++ { ++ // Walk all nmethods depending on this call site. ++ MutexLocker mu1(Compile_lock, thread); ++ ++ CallSiteDepChange changes(call_site(), Handle()); ++ ++ InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site()); ++ if (ctxk == NULL) { ++ return; // No dependencies to invalidate yet. ++ } ++ int marked = 0; ++ { ++ MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); ++ marked = ctxk->mark_dependent_nmethods(changes); ++ } ++ java_lang_invoke_CallSite::set_context_volatile(call_site(), NULL); // Reset call site to initial state ++ if (marked > 0) { ++ // At least one nmethod has been marked for deoptimization ++ VM_Deoptimize op; ++ VMThread::execute(&op); ++ } ++ } ++} ++JVM_END ++ + /** + * Throws a java/lang/UnsupportedOperationException unconditionally. + * This is required by the specification of MethodHandle.invoke if +@@ -1381,6 +1426,7 @@ static JNINativeMethod MHN_methods[] = { + {CC "objectFieldOffset", CC "(" MEM ")J", FN_PTR(MHN_objectFieldOffset)}, + {CC "setCallSiteTargetNormal", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetNormal)}, + {CC "setCallSiteTargetVolatile", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetVolatile)}, ++ {CC"invalidateDependentNMethods", CC"("CS")V", FN_PTR(MHN_invalidateDependentNMethods)}, + {CC "staticFieldOffset", CC "(" MEM ")J", FN_PTR(MHN_staticFieldOffset)}, + {CC "staticFieldBase", CC "(" MEM ")" OBJ, FN_PTR(MHN_staticFieldBase)}, + {CC "getMemberVMInfo", CC "(" MEM ")" OBJ, FN_PTR(MHN_getMemberVMInfo)} +diff --git a/hotspot/src/share/vm/prims/methodHandles.hpp b/hotspot/src/share/vm/prims/methodHandles.hpp +index db6e06180..4b6af60df 100644 +--- a/hotspot/src/share/vm/prims/methodHandles.hpp ++++ b/hotspot/src/share/vm/prims/methodHandles.hpp +@@ -68,6 +68,9 @@ class MethodHandles: AllStatic { + // bit values for suppress argument to expand_MemberName: + enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; + ++ // CallSite support ++ static InstanceKlass* get_call_site_context(oop call_site); ++ + // Generate MethodHandles adapters. + static void generate_adapters(); + +diff --git a/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java +new file mode 100644 +index 000000000..11e46ed03 +--- /dev/null ++++ b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java +@@ -0,0 +1,179 @@ ++/* ++ * 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. ++ */ ++ ++/** ++ * @test ++ * @bug 8057967 ++ * @run main/bootclasspath -Xbatch java.lang.invoke.CallSiteDepContextTest ++ */ ++package java.lang.invoke; ++ ++import java.lang.ref.*; ++import jdk.internal.org.objectweb.asm.*; ++import sun.misc.Unsafe; ++ ++import static jdk.internal.org.objectweb.asm.Opcodes.*; ++ ++public class CallSiteDepContextTest { ++ static final Unsafe UNSAFE = Unsafe.getUnsafe(); ++ static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; ++ static final String CLASS_NAME = "java/lang/invoke/Test"; ++ static final String METHOD_NAME = "m"; ++ static final MethodType TYPE = MethodType.methodType(int.class); ++ ++ static MutableCallSite mcs; ++ static MethodHandle bsmMH; ++ ++ static { ++ try { ++ bsmMH = LOOKUP.findStatic( ++ CallSiteDepContextTest.class, "bootstrap", ++ MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class)); ++ } catch(Throwable e) { ++ throw new InternalError(e); ++ } ++ } ++ ++ public static CallSite bootstrap(MethodHandles.Lookup caller, ++ String invokedName, ++ MethodType invokedType) { ++ return mcs; ++ } ++ ++ static class T { ++ static int f1() { return 1; } ++ static int f2() { return 2; } ++ } ++ ++ static byte[] getClassFile(String suffix) { ++ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ++ MethodVisitor mv; ++ cw.visit(52, ACC_PUBLIC | ACC_SUPER, CLASS_NAME + suffix, null, "java/lang/Object", null); ++ { ++ mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, METHOD_NAME, TYPE.toMethodDescriptorString(), null, null); ++ mv.visitCode(); ++ Handle bsm = new Handle(H_INVOKESTATIC, ++ "java/lang/invoke/CallSiteDepContextTest", "bootstrap", ++ bsmMH.type().toMethodDescriptorString()); ++ mv.visitInvokeDynamicInsn("methodName", TYPE.toMethodDescriptorString(), bsm); ++ mv.visitInsn(IRETURN); ++ mv.visitMaxs(0, 0); ++ mv.visitEnd(); ++ } ++ cw.visitEnd(); ++ return cw.toByteArray(); ++ } ++ ++ private static void execute(int expected, MethodHandle... mhs) throws Throwable { ++ for (int i = 0; i < 20_000; i++) { ++ for (MethodHandle mh : mhs) { ++ int r = (int) mh.invokeExact(); ++ if (r != expected) { ++ throw new Error(r + " != " + expected); ++ } ++ } ++ } ++ } ++ ++ public static void testSharedCallSite() throws Throwable { ++ Class cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_1"), null); ++ Class cls2 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_2"), null); ++ ++ MethodHandle[] mhs = new MethodHandle[] { ++ LOOKUP.findStatic(cls1, METHOD_NAME, TYPE), ++ LOOKUP.findStatic(cls2, METHOD_NAME, TYPE) ++ }; ++ ++ mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); ++ execute(1, mhs); ++ mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); ++ execute(2, mhs); ++ } ++ ++ public static void testNonBoundCallSite() throws Throwable { ++ mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); ++ ++ // mcs.context == null ++ MethodHandle mh = mcs.dynamicInvoker(); ++ execute(1, mh); ++ ++ // mcs.context == cls1 ++ Class cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("NonBound_1"), null); ++ MethodHandle mh1 = LOOKUP.findStatic(cls1, METHOD_NAME, TYPE); ++ ++ execute(1, mh1); ++ ++ mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); ++ ++ execute(2, mh, mh1); ++ } ++ ++ static ReferenceQueue rq = new ReferenceQueue(); ++ static PhantomReference ref; ++ ++ public static void testGC() throws Throwable { ++ mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); ++ ++ Class[] cls = new Class[] { ++ UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1"), null), ++ UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2"), null), ++ }; ++ ++ MethodHandle[] mhs = new MethodHandle[] { ++ LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE), ++ LOOKUP.findStatic(cls[1], METHOD_NAME, TYPE), ++ }; ++ ++ // mcs.context == cls[0] ++ int r = (int) mhs[0].invokeExact(); ++ ++ execute(1, mhs); ++ ++ ref = new PhantomReference<>(cls[0], rq); ++ cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3"), null); ++ mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE); ++ ++ do { ++ System.gc(); ++ try { ++ Reference ref1 = rq.remove(1000); ++ if (ref1 == ref) { ++ ref1.clear(); ++ System.gc(); // Ensure that the stale context is cleared ++ break; ++ } ++ } catch(InterruptedException e) { /* ignore */ } ++ } while (true); ++ ++ execute(1, mhs); ++ mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); ++ execute(2, mhs); ++ } ++ ++ public static void main(String[] args) throws Throwable { ++ testSharedCallSite(); ++ testNonBoundCallSite(); ++ testGC(); ++ System.out.println("TEST PASSED"); ++ } ++} +diff --git a/jdk/src/share/classes/java/lang/invoke/CallSite.java b/jdk/src/share/classes/java/lang/invoke/CallSite.java +index 10ac1c071..11e452b96 100644 +--- a/jdk/src/share/classes/java/lang/invoke/CallSite.java ++++ b/jdk/src/share/classes/java/lang/invoke/CallSite.java +@@ -25,9 +25,10 @@ + + package java.lang.invoke; + +-import sun.invoke.empty.Empty; + import static java.lang.invoke.MethodHandleStatics.*; + import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ++import java.lang.reflect.Field; ++import sun.misc.Cleaner; + + /** + * A {@code CallSite} is a holder for a variable {@link MethodHandle}, +@@ -136,6 +137,50 @@ public class CallSite { + } + + /** ++ * {@code CallSite} dependency context. ++ * VM uses context class to store nmethod dependencies on the call site target. ++ * Can be in 2 states: (a) null; or (b) {@code Cleaner} instance pointing to some Class instance. ++ * Lazily initialized when CallSite instance is linked to some indy call site or VM needs ++ * it to store dependencies. As a corollary, "null" context means there are no dependencies ++ * registered yet. {@code Cleaner} is used in 2 roles: ++ * (a) context class access for VM; ++ * (b) stale context class cleanup. ++ * {@code Cleaner} holds the context class until cleanup action is finished (see {@code PhantomReference}). ++ * Though it's impossible to get the context class using {@code Reference.get()}, VM extracts it directly ++ * from {@code Reference.referent} field. ++ */ ++ private volatile Cleaner context = null; ++ ++ /** ++ * Default context. ++ * VM uses it to initialize non-linked CallSite context. ++ */ ++ private static class DefaultContext {} ++ private static final Cleaner DEFAULT_CONTEXT = makeContext(DefaultContext.class, null); ++ ++ private static Cleaner makeContext(Class referent, final CallSite holder) { ++ return Cleaner.create(referent, ++ new Runnable() { ++ @Override public void run() { ++ MethodHandleNatives.invalidateDependentNMethods(holder); ++ } ++ }); ++ } ++ ++ /** Initialize context class used for nmethod dependency tracking */ ++ /*package-private*/ ++ void initContext(Class newContext) { ++ // If there are concurrent actions, exactly one succeeds. ++ if (context == null) { ++ UNSAFE.compareAndSwapObject(this, CONTEXT_OFFSET, /*expected=*/null, makeContext(newContext, this)); ++ // No need to care about failed CAS attempt. ++ // Since initContext is called from indy call site linkage in newContext class, there's no risk ++ // that the context class becomes dead while corresponding context cleaner is alive (causing cleanup ++ // action in the wrong context). ++ } ++ } ++ ++ /** + * Returns the type of this call site's target. + * Although targets may change, any call site's type is permanent, and can never change to an unequal type. + * The {@code setTarget} method enforces this invariant by refusing any new target that does +@@ -246,11 +291,13 @@ public class CallSite { + } + + // unsafe stuff: +- private static final long TARGET_OFFSET; ++ private static final long TARGET_OFFSET; ++ private static final long CONTEXT_OFFSET; + static { + try { +- TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target")); +- } catch (Exception ex) { throw new Error(ex); } ++ TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target")); ++ CONTEXT_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("context")); ++ } catch (Exception ex) { throw newInternalError(ex); } + } + + /*package-private*/ +diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +index ecc146078..9a1343c50 100644 +--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java ++++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +@@ -71,6 +71,9 @@ class MethodHandleNatives { + static native void setCallSiteTargetNormal(CallSite site, MethodHandle target); + static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target); + ++ /** Invalidate CallSite context: clean up dependent nmethods and reset call site context to initial state (null). */ ++ static native void invalidateDependentNMethods(CallSite site); ++ + private static native void registerNatives(); + static { + registerNatives(); +@@ -314,6 +317,7 @@ class MethodHandleNatives { + return Invokers.linkToTargetMethod(type); + } else { + appendixResult[0] = callSite; ++ callSite.initContext(caller); + return Invokers.linkToCallSiteMethod(type); + } + } +-- +2.12.3 + diff --git a/8079205-CallSite-dependency-tracking-is-broken-after.patch b/8079205-CallSite-dependency-tracking-is-broken-after.patch new file mode 100644 index 0000000000000000000000000000000000000000..34758670be57531b36d7b45803103bd33daf190f --- /dev/null +++ b/8079205-CallSite-dependency-tracking-is-broken-after.patch @@ -0,0 +1,1161 @@ +From 4ec8d45e1a51fb6c4e407052a52762ad3a59fa60 Mon Sep 17 00:00:00 2001 +From: zhangyipeng +Date: Tue, 16 Jan 2024 10:00:09 +0800 +Subject: [PATCH] [Backport]8079205: CallSite dependency tracking is broken after + sun.misc.Cleaner became automatically cleared +--- + hotspot/src/share/vm/ci/ciCallSite.cpp | 19 --- + hotspot/src/share/vm/ci/ciCallSite.hpp | 1 - + hotspot/src/share/vm/ci/ciInstanceKlass.cpp | 8 +- + hotspot/src/share/vm/classfile/javaClasses.cpp | 44 +++--- + hotspot/src/share/vm/classfile/javaClasses.hpp | 37 ++++- + .../src/share/vm/classfile/systemDictionary.hpp | 1 + + hotspot/src/share/vm/classfile/vmSymbols.hpp | 4 +- + hotspot/src/share/vm/code/dependencies.cpp | 20 +-- + hotspot/src/share/vm/code/dependencies.hpp | 6 +- + hotspot/src/share/vm/code/nmethod.cpp | 46 ++++-- + hotspot/src/share/vm/memory/universe.cpp | 34 ---- + hotspot/src/share/vm/memory/universe.hpp | 1 - + hotspot/src/share/vm/oops/instanceKlass.cpp | 176 ++++++++++++--------- + hotspot/src/share/vm/oops/instanceKlass.hpp | 10 ++ + hotspot/src/share/vm/prims/methodHandles.cpp | 93 +++++++---- + hotspot/src/share/vm/prims/methodHandles.hpp | 5 +- + .../compiler/jsr292/CallSiteDepContextTest.java | 41 +++-- + .../share/classes/java/lang/invoke/CallSite.java | 44 +----- + .../java/lang/invoke/MethodHandleNatives.java | 25 ++- + 19 files changed, 335 insertions(+), 280 deletions(-) + +diff --git a/hotspot/src/share/vm/ci/ciCallSite.cpp b/hotspot/src/share/vm/ci/ciCallSite.cpp +index f58346aea..794042a79 100644 +--- a/hotspot/src/share/vm/ci/ciCallSite.cpp ++++ b/hotspot/src/share/vm/ci/ciCallSite.cpp +@@ -49,25 +49,6 @@ ciMethodHandle* ciCallSite::get_target() const { + } + + // ------------------------------------------------------------------ +-// ciCallSite::get_context +-// +-// Return the target MethodHandle of this CallSite. +-ciKlass* ciCallSite::get_context() { +- assert(!is_constant_call_site(), ""); +- +- VM_ENTRY_MARK; +- oop call_site_oop = get_oop(); +- InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site_oop); +- if (ctxk == NULL) { +- // The call site doesn't have a context associated. Set it to the default context. +- oop def_context_oop = java_lang_invoke_CallSite::default_context(); +- java_lang_invoke_CallSite::set_context_cas(call_site_oop, def_context_oop, /*expected=*/NULL); +- ctxk = MethodHandles::get_call_site_context(call_site_oop); +- } +- return (CURRENT_ENV->get_metadata(ctxk))->as_klass(); +-} +- +-// ------------------------------------------------------------------ + // ciCallSite::print + // + // Print debugging information about the CallSite. +diff --git a/hotspot/src/share/vm/ci/ciCallSite.hpp b/hotspot/src/share/vm/ci/ciCallSite.hpp +index 040e894d0..063f1e3a5 100644 +--- a/hotspot/src/share/vm/ci/ciCallSite.hpp ++++ b/hotspot/src/share/vm/ci/ciCallSite.hpp +@@ -43,7 +43,6 @@ public: + + // Return the target MethodHandle of this CallSite. + ciMethodHandle* get_target() const; +- ciKlass* get_context(); + + void print(); + }; +diff --git a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp +index 8b17c9b29..876c869d2 100644 +--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp ++++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp +@@ -485,8 +485,12 @@ int ciInstanceKlass::compute_nonstatic_fields() { + + if (fields == NULL) { + // This can happen if this class (java.lang.Class) has invisible fields. +- _nonstatic_fields = super_fields; +- return super_fields->length(); ++ if (super_fields != NULL) { ++ _nonstatic_fields = super_fields; ++ return super_fields->length(); ++ } else { ++ return 0; ++ } + } + + int flen = fields->length(); +diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp +index fc4165b04..267bbacd3 100644 +--- a/hotspot/src/share/vm/classfile/javaClasses.cpp ++++ b/hotspot/src/share/vm/classfile/javaClasses.cpp +@@ -3004,48 +3004,43 @@ int java_lang_invoke_MethodType::rtype_slot_count(oop mt) { + + int java_lang_invoke_CallSite::_target_offset; + int java_lang_invoke_CallSite::_context_offset; +-int java_lang_invoke_CallSite::_default_context_offset; + + void java_lang_invoke_CallSite::compute_offsets() { + if (!EnableInvokeDynamic) return; + Klass* k = SystemDictionary::CallSite_klass(); + if (k != NULL) { + compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_lang_invoke_MethodHandle_signature()); +- compute_offset(_context_offset, k, vmSymbols::context_name(), vmSymbols::sun_misc_Cleaner_signature()); +- compute_offset(_default_context_offset, k, +- vmSymbols::DEFAULT_CONTEXT_name(), vmSymbols::sun_misc_Cleaner_signature(), +- /*is_static=*/true, /*allow_super=*/false); ++ compute_offset(_context_offset, k, vmSymbols::context_name(), ++ vmSymbols::java_lang_invoke_MethodHandleNatives_CallSiteContext_signature()); + } + } + +-oop java_lang_invoke_CallSite::context_volatile(oop call_site) { ++oop java_lang_invoke_CallSite::context(oop call_site) { + assert(java_lang_invoke_CallSite::is_instance(call_site), ""); + +- oop dep_oop = call_site->obj_field_volatile(_context_offset); ++ oop dep_oop = call_site->obj_field(_context_offset); + return dep_oop; + } + +-void java_lang_invoke_CallSite::set_context_volatile(oop call_site, oop context) { +- assert(java_lang_invoke_CallSite::is_instance(call_site), ""); +- call_site->obj_field_put_volatile(_context_offset, context); +-} ++// Support for java_lang_invoke_MethodHandleNatives_CallSiteContext + +-bool java_lang_invoke_CallSite::set_context_cas(oop call_site, oop context, oop expected) { +- assert(java_lang_invoke_CallSite::is_instance(call_site), ""); +- HeapWord* context_addr = call_site->obj_field_addr(_context_offset); +- oop res = oopDesc::atomic_compare_exchange_oop(context, context_addr, expected, true); +- bool success = (res == expected); +- if (success) { +- update_barrier_set((void*)context_addr, context); ++int java_lang_invoke_MethodHandleNatives_CallSiteContext::_vmdependencies_offset; ++ ++void java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets() { ++ Klass* k = SystemDictionary::Context_klass(); ++ if (k != NULL) { ++ CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); + } +- return success; + } + +-oop java_lang_invoke_CallSite::default_context() { +- InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::CallSite_klass()); +- oop def_context_oop = ik->java_mirror()->obj_field(_default_context_offset); +- assert(!oopDesc::is_null(def_context_oop), ""); +- return def_context_oop; ++nmethodBucket* 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); + } + + // Support for java_security_AccessControlContext +@@ -3441,6 +3436,7 @@ void JavaClasses::compute_offsets() { + java_lang_invoke_LambdaForm::compute_offsets(); + java_lang_invoke_MethodType::compute_offsets(); + java_lang_invoke_CallSite::compute_offsets(); ++ java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets(); + } + java_security_AccessControlContext::compute_offsets(); + // Initialize reflection classes. The layouts of these classes +diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp +index 35934319d..1eb04b968 100644 +--- a/hotspot/src/share/vm/classfile/javaClasses.hpp ++++ b/hotspot/src/share/vm/classfile/javaClasses.hpp +@@ -1213,8 +1213,6 @@ class java_lang_invoke_CallSite: AllStatic { + private: + static int _target_offset; + static int _context_offset; +- static int _default_context_offset; +- + + static void compute_offsets(); + +@@ -1225,11 +1223,8 @@ public: + + static volatile oop target_volatile(oop site) { return oop((oopDesc *)(site->obj_field_volatile(_target_offset))); } + static void set_target_volatile(oop site, oop target) { site->obj_field_put_volatile(_target_offset, target); } +- static oop context_volatile(oop site); +- static void set_context_volatile(oop site, oop context); +- static bool set_context_cas (oop site, oop context, oop expected); + +- static oop default_context(); ++ static oop context(oop site); + + // Testers + static bool is_subclass(Klass* klass) { +@@ -1243,6 +1238,33 @@ public: + static int target_offset_in_bytes() { return _target_offset; } + }; + ++// Interface to java.lang.invoke.MethodHandleNatives$CallSiteContext objects ++ ++#define CALLSITECONTEXT_INJECTED_FIELDS(macro) \ ++ macro(java_lang_invoke_MethodHandleNatives_CallSiteContext, vmdependencies, intptr_signature, false) ++ ++class java_lang_invoke_MethodHandleNatives_CallSiteContext : AllStatic { ++ friend class JavaClasses; ++ ++private: ++ static int _vmdependencies_offset; ++ ++ static void compute_offsets(); ++ ++public: ++ // Accessors ++ static nmethodBucket* vmdependencies(oop context); ++ static void set_vmdependencies(oop context, nmethodBucket* bucket); ++ ++ // Testers ++ static bool is_subclass(Klass* klass) { ++ return klass->is_subclass_of(SystemDictionary::Context_klass()); ++ } ++ static inline bool is_instance(oop obj) { ++ return obj != NULL && is_subclass(obj->klass()); ++ } ++}; ++ + // Interface to java.security.AccessControlContext objects + + class java_security_AccessControlContext: AllStatic { +@@ -1454,7 +1476,8 @@ class InjectedField { + #define ALL_INJECTED_FIELDS(macro) \ + CLASS_INJECTED_FIELDS(macro) \ + CLASSLOADER_INJECTED_FIELDS(macro) \ +- MEMBERNAME_INJECTED_FIELDS(macro) ++ MEMBERNAME_INJECTED_FIELDS(macro) \ ++ CALLSITECONTEXT_INJECTED_FIELDS(macro) + + // Interface to hard-coded offset checking + +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp +index 83ca3794b..ca91f53e7 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp +@@ -159,6 +159,7 @@ class SymbolPropertyTable; + do_klass(MethodType_klass, java_lang_invoke_MethodType, Pre_JSR292 ) \ + do_klass(BootstrapMethodError_klass, java_lang_BootstrapMethodError, Pre_JSR292 ) \ + do_klass(CallSite_klass, java_lang_invoke_CallSite, Pre_JSR292 ) \ ++ do_klass(Context_klass, java_lang_invoke_MethodHandleNatives_CallSiteContext, Pre ) \ + do_klass(ConstantCallSite_klass, java_lang_invoke_ConstantCallSite, Pre_JSR292 ) \ + do_klass(MutableCallSite_klass, java_lang_invoke_MutableCallSite, Pre_JSR292 ) \ + do_klass(VolatileCallSite_klass, java_lang_invoke_VolatileCallSite, Pre_JSR292 ) \ +diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp +index f92b709ed..79f15589f 100644 +--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp ++++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp +@@ -282,6 +282,7 @@ + /* internal classes known only to the JVM: */ \ + template(java_lang_invoke_MemberName, "java/lang/invoke/MemberName") \ + template(java_lang_invoke_MethodHandleNatives, "java/lang/invoke/MethodHandleNatives") \ ++ template(java_lang_invoke_MethodHandleNatives_CallSiteContext, "java/lang/invoke/MethodHandleNatives$CallSiteContext") \ + template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ + template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ + template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ +@@ -289,6 +290,7 @@ + template(java_lang_invoke_Stable_signature, "Ljava/lang/invoke/Stable;") \ + template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ + template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ ++ template(java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, "Ljava/lang/invoke/MethodHandleNatives$CallSiteContext;") \ + /* internal up-calls made only by the JVM, via class sun.invoke.MethodHandleNatives: */ \ + template(findMethodHandleType_name, "findMethodHandleType") \ + template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;") \ +@@ -411,7 +413,7 @@ + template(init_lock_name, "init_lock") \ + template(signers_name, "signers_name") \ + template(loader_data_name, "loader_data") \ +- template(dependencies_name, "dependencies") \ ++ template(vmdependencies_name, "vmdependencies") \ + template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \ + template(getFileURL_name, "getFileURL") \ + template(getFileURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ +diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp +index decbce8be..52ed2f836 100644 +--- a/hotspot/src/share/vm/code/dependencies.cpp ++++ b/hotspot/src/share/vm/code/dependencies.cpp +@@ -123,9 +123,7 @@ void Dependencies::assert_has_no_finalizable_subclasses(ciKlass* ctxk) { + } + + void Dependencies::assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle) { +- ciKlass* ctxk = call_site->get_context(); +- check_ctxk(ctxk); +- assert_common_3(call_site_target_value, ctxk, call_site, method_handle); ++ assert_common_2(call_site_target_value, call_site, method_handle); + } + + // Helper function. If we are adding a new dep. under ctxk2, +@@ -181,7 +179,6 @@ void Dependencies::assert_common_2(DepType dept, + } + } + } else { +- assert(dep_implicit_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; +@@ -397,7 +394,7 @@ int Dependencies::_dep_args[TYPE_LIMIT] = { + 3, // unique_concrete_methods_2 ctxk, m1, m2 + 2, // unique_implementor ctxk, implementor + 1, // no_finalizable_subclasses ctxk +- 3 // call_site_target_value ctxk, call_site, method_handle ++ 2 // call_site_target_value call_site, method_handle + }; + + const char* Dependencies::dep_name(Dependencies::DepType dept) { +@@ -1648,16 +1645,11 @@ Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepCh + return find_finalizable_subclass(search_at); + } + +-Klass* Dependencies::check_call_site_target_value(Klass* recorded_ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes) { +- assert(call_site->is_a(SystemDictionary::CallSite_klass()), "sanity"); ++Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) { ++ assert(!oopDesc::is_null(call_site), "sanity"); + assert(!oopDesc::is_null(method_handle), "sanity"); ++ assert(call_site->is_a(SystemDictionary::CallSite_klass()), "sanity"); + +- Klass* call_site_ctxk = MethodHandles::get_call_site_context(call_site); +- assert(!Klass::is_null(call_site_ctxk), "call site context should be initialized already"); +- if (recorded_ctxk != call_site_ctxk) { +- // Stale context +- return recorded_ctxk; +- } + if (changes == NULL) { + // Validate all CallSites + if (java_lang_invoke_CallSite::target(call_site) != method_handle) +@@ -1735,7 +1727,7 @@ Klass* Dependencies::DepStream::check_call_site_dependency(CallSiteDepChange* ch + Klass* witness = NULL; + switch (type()) { + case call_site_target_value: +- witness = check_call_site_target_value(context_type(), argument_oop(1), argument_oop(2), changes); ++ witness = check_call_site_target_value(argument_oop(0), argument_oop(1), changes); + break; + default: + witness = NULL; +diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp +index da2201c3f..bbe140390 100644 +--- a/hotspot/src/share/vm/code/dependencies.hpp ++++ b/hotspot/src/share/vm/code/dependencies.hpp +@@ -175,7 +175,7 @@ class Dependencies: public ResourceObj { + non_klass_types = (1 << call_site_target_value), + klass_types = all_types & ~non_klass_types, + +- non_ctxk_types = (1 << evol_method), ++ non_ctxk_types = (1 << evol_method) | (1 << call_site_target_value), + implicit_ctxk_types = 0, + explicit_ctxk_types = all_types & ~(non_ctxk_types | implicit_ctxk_types), + +@@ -340,7 +340,7 @@ class Dependencies: public ResourceObj { + static Klass* check_exclusive_concrete_methods(Klass* ctxk, Method* m1, Method* m2, + KlassDepChange* changes = NULL); + static Klass* check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes = NULL); +- static Klass* check_call_site_target_value(Klass* recorded_ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); ++ static Klass* check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); + // A returned Klass* is NULL if the dependency assertion is still + // valid. A non-NULL Klass* is a 'witness' to the assertion + // failure, a point in the class hierarchy where the assertion has +@@ -506,7 +506,7 @@ class Dependencies: public ResourceObj { + bool next(); + + DepType type() { return _type; } +- bool is_oop_argument(int i) { return type() == call_site_target_value && i > 0; } ++ bool is_oop_argument(int i) { return type() == call_site_target_value; } + int argument_count() { return dep_args(type()); } + int argument_index(int i) { assert(0 <= i && i < argument_count(), "oob"); + return _xi[i]; } +diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp +index 01e878022..ba5116575 100644 +--- a/hotspot/src/share/vm/code/nmethod.cpp ++++ b/hotspot/src/share/vm/code/nmethod.cpp +@@ -629,13 +629,18 @@ nmethod* nmethod::new_nmethod(methodHandle method, + // the number of methods compiled. For applications with a lot + // classes the slow way is too slow. + for (Dependencies::DepStream deps(nm); deps.next(); ) { +- Klass* klass = deps.context_type(); +- if (klass == NULL) { +- continue; // ignore things like evol_method ++ 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); ++ } else { ++ Klass* klass = deps.context_type(); ++ if (klass == NULL) { ++ continue; // ignore things like evol_method ++ } ++ // record this nmethod as dependent on this klass ++ InstanceKlass::cast(klass)->add_dependent_nmethod(nm); + } +- +- // record this nmethod as dependent on this klass +- InstanceKlass::cast(klass)->add_dependent_nmethod(nm); + } + NOT_PRODUCT(nmethod_stats.note_nmethod(nm)); + if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) { +@@ -1617,17 +1622,24 @@ void nmethod::flush_dependencies(BoolObjectClosure* is_alive) { + if (!has_flushed_dependencies()) { + set_has_flushed_dependencies(); + for (Dependencies::DepStream deps(this); deps.next(); ) { +- Klass* klass = deps.context_type(); +- if (klass == NULL) continue; // ignore things like evol_method +- +- // During GC the is_alive closure is non-NULL, and is used to +- // determine liveness of dependees that need to be updated. +- if (is_alive == NULL || klass->is_loader_alive(is_alive)) { +- // The GC defers deletion of this entry, since there might be multiple threads +- // iterating over the _dependencies graph. Other call paths are single-threaded +- // and may delete it immediately. +- bool delete_immediately = is_alive == NULL; +- InstanceKlass::cast(klass)->remove_dependent_nmethod(this, delete_immediately); ++ 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::remove_dependent_nmethod(call_site, this); ++ } else { ++ Klass* klass = deps.context_type(); ++ if (klass == NULL) { ++ continue; // ignore things like evol_method ++ } ++ // During GC the is_alive closure is non-NULL, and is used to ++ // determine liveness of dependees that need to be updated. ++ if (is_alive == NULL || klass->is_loader_alive(is_alive)) { ++ // The GC defers deletion of this entry, since there might be multiple threads ++ // iterating over the _dependencies graph. Other call paths are single-threaded ++ // and may delete it immediately. ++ bool delete_immediately = is_alive == NULL; ++ InstanceKlass::cast(klass)->remove_dependent_nmethod(this, delete_immediately); ++ } + } + } + } +diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp +index 7028d378e..d76a10d14 100644 +--- a/hotspot/src/share/vm/memory/universe.cpp ++++ b/hotspot/src/share/vm/memory/universe.cpp +@@ -1213,40 +1213,6 @@ void Universe::flush_dependents_on(instanceKlassHandle dependee) { + } + } + +-// Flushes compiled methods dependent on a particular CallSite +-// instance when its target is different than the given MethodHandle. +-void Universe::flush_dependents_on(Handle call_site, Handle method_handle) { +- assert_lock_strong(Compile_lock); +- +- if (CodeCache::number_of_nmethods_with_dependencies() == 0) return; +- +- // CodeCache can only be updated by a thread_in_VM and they will all be +- // stopped dring the safepoint so CodeCache will be safe to update without +- // holding the CodeCache_lock. +- +- CallSiteDepChange changes(call_site(), method_handle()); +- +- // Compute the dependent nmethods that have a reference to a +- // CallSite object. We use InstanceKlass::mark_dependent_nmethod +- // directly instead of CodeCache::mark_for_deoptimization because we +- // want dependents on the call site class only not all classes in +- // the ContextStream. +- int marked = 0; +- { +- MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); +- InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site()); +- if (ctxk == NULL) { +- return; // No dependencies to invalidate yet. +- } +- marked = ctxk->mark_dependent_nmethods(changes); +- } +- if (marked > 0) { +- // At least one nmethod has been marked for deoptimization +- VM_Deoptimize op; +- VMThread::execute(&op); +- } +-} +- + #ifdef HOTSWAP + // Flushes compiled methods dependent on dependee in the evolutionary sense + void Universe::flush_evol_dependents_on(instanceKlassHandle ev_k_h) { +diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp +index dbba5a021..88ad002fa 100644 +--- a/hotspot/src/share/vm/memory/universe.hpp ++++ b/hotspot/src/share/vm/memory/universe.hpp +@@ -475,7 +475,6 @@ class Universe: AllStatic { + + // Flushing and deoptimization + static void flush_dependents_on(instanceKlassHandle dependee); +- static void flush_dependents_on(Handle call_site, Handle method_handle); + #ifdef HOTSWAP + // Flushing and deoptimization in case of evolution + static void flush_evol_dependents_on(instanceKlassHandle dependee); +diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp +index 00aea4377..ce297b681 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.cpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.cpp +@@ -2102,11 +2102,10 @@ int nmethodBucket::decrement() { + // are dependent on the changes that were passed in and mark them for + // deoptimization. Returns the number of nmethods found. + // +-int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { ++int nmethodBucket::mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes) { + assert_locked_or_safepoint(CodeCache_lock); + int found = 0; +- nmethodBucket* b = _dependencies; +- while (b != NULL) { ++ 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. +@@ -2114,7 +2113,6 @@ int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { + if (TraceDependencies) { + ResourceMark rm; + tty->print_cr("Marked for deoptimization"); +- tty->print_cr(" context = %s", this->external_name()); + changes.print(); + nm->print(); + nm->print_dependencies(); +@@ -2122,115 +2120,102 @@ int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { + nm->mark_for_deoptimization(); + found++; + } +- b = b->next(); + } + return found; + } + +-void InstanceKlass::clean_dependent_nmethods() { +- assert_locked_or_safepoint(CodeCache_lock); +- +- if (has_unloaded_dependent()) { +- nmethodBucket* b = _dependencies; +- nmethodBucket* last = NULL; +- 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) { +- _dependencies = next; +- } else { +- last->set_next(next); +- } +- delete b; +- // last stays the same. +- } else { +- last = b; +- } +- +- b = next; +- } +- 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 +-} +- + // + // 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. ++// deletion of dependencies is consistent. Returns new head of the list. + // +-void InstanceKlass::add_dependent_nmethod(nmethod* nm) { ++nmethodBucket* nmethodBucket::add_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); +- nmethodBucket* b = _dependencies; +- nmethodBucket* last = NULL; +- while (b != NULL) { ++ for (nmethodBucket* b = deps; b != NULL; b = b->next()) { + if (nm == b->get_nmethod()) { + b->increment(); +- return; ++ return deps; + } +- b = b->next(); + } +- _dependencies = new nmethodBucket(nm, _dependencies); ++ return new nmethodBucket(nm, deps); + } + +- + // + // Decrement count of the nmethod in the dependency list and remove +-// the bucket competely when the count goes to 0. This method must ++// 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 dependecies. +-// +-void InstanceKlass::remove_dependent_nmethod(nmethod* nm, bool delete_immediately) { ++// 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* b = _dependencies; ++ ++ nmethodBucket* first = *deps; + nmethodBucket* last = NULL; +- while (b != 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) { +- _dependencies = b->next(); ++ *deps = b->next(); + } else { + last->set_next(b->next()); + } + delete b; +- } else { +- // The deletion of this entry is deferred until a later, potentially parallel GC phase. +- set_has_unloaded_dependent(true); + } + } +- return; ++ return true; + } + last = b; +- b = b->next(); + } ++ + #ifdef ASSERT +- tty->print_cr("### %s can't find dependent nmethod:", this->external_name()); ++ 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 InstanceKlass::print_dependent_nmethods(bool verbose) { +- nmethodBucket* b = _dependencies; ++void nmethodBucket::print_dependent_nmethods(nmethodBucket* deps, bool verbose) { + int idx = 0; +- while (b != NULL) { ++ for (nmethodBucket* b = deps; b != NULL; b = b->next()) { + nmethod* nm = b->get_nmethod(); + tty->print("[%d] count=%d { ", idx++, b->count()); + if (!verbose) { +@@ -2241,14 +2226,11 @@ void InstanceKlass::print_dependent_nmethods(bool verbose) { + nm->print_dependencies(); + tty->print_cr("--- } "); + } +- b = b->next(); + } + } + +- +-bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { +- nmethodBucket* b = _dependencies; +- while (b != NULL) { ++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(); +@@ -2256,12 +2238,58 @@ bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { + #endif + return true; + } +- b = b->next(); + } + 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 ++} ++ ++void InstanceKlass::add_dependent_nmethod(nmethod* nm) { ++ assert_locked_or_safepoint(CodeCache_lock); ++ _dependencies = nmethodBucket::add_dependent_nmethod(_dependencies, 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); ++ } ++} ++ ++#ifndef PRODUCT ++void InstanceKlass::print_dependent_nmethods(bool verbose) { ++ nmethodBucket::print_dependent_nmethods(_dependencies, verbose); ++} ++ ++ ++bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { ++ return nmethodBucket::is_dependent_nmethod(_dependencies, nm); ++} ++#endif //PRODUCT ++ + + // Garbage collection + +diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp +index 973480341..9750ae56d 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.hpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.hpp +@@ -1288,6 +1288,16 @@ class nmethodBucket: public CHeapObj { + 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 +diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp +index c1cbabec2..abd7c0b42 100644 +--- a/hotspot/src/share/vm/prims/methodHandles.cpp ++++ b/hotspot/src/share/vm/prims/methodHandles.cpp +@@ -946,22 +946,56 @@ int MethodHandles::find_MemberNames(KlassHandle k, + return rfill + overflow; + } + +-// Get context class for a CallSite instance: either extract existing context or use default one. +-InstanceKlass* MethodHandles::get_call_site_context(oop call_site) { +- // In order to extract a context the following traversal is performed: +- // CallSite.context => Cleaner.referent => Class._klass => Klass +- assert(java_lang_invoke_CallSite::is_instance(call_site), ""); +- oop context_oop = java_lang_invoke_CallSite::context_volatile(call_site); +- if (oopDesc::is_null(context_oop)) { +- return NULL; // The context hasn't been initialized yet. ++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); + } +- oop context_class_oop = java_lang_ref_Reference::referent(context_oop); +- if (oopDesc::is_null(context_class_oop)) { +- // The context reference was cleared by GC, so current dependency context +- // isn't usable anymore. Context should be fetched from CallSite again. +- return NULL; ++} ++ ++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); ++ } ++ } ++} ++ ++void MethodHandles::flush_dependent_nmethods(Handle call_site, Handle target) { ++ assert_lock_strong(Compile_lock); ++ ++ int marked = 0; ++ CallSiteDepChange changes(call_site(), target()); ++ { ++ 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); ++ } ++ } ++ } ++ if (marked > 0) { ++ // At least one nmethod has been marked for deoptimization ++ VM_Deoptimize op; ++ VMThread::execute(&op); + } +- return InstanceKlass::cast(java_lang_Class::as_Klass(context_class_oop)); + } + + //------------------------------------------------------------------------------ +@@ -1327,7 +1361,7 @@ JVM_ENTRY(void, MHN_setCallSiteTargetNormal(JNIEnv* env, jobject igcls, jobject + { + // Walk all nmethods depending on this call site. + MutexLocker mu(Compile_lock, thread); +- Universe::flush_dependents_on(call_site, target); ++ MethodHandles::flush_dependent_nmethods(call_site, target); + java_lang_invoke_CallSite::set_target(call_site(), target()); + } + } +@@ -1339,30 +1373,34 @@ JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobjec + { + // Walk all nmethods depending on this call site. + MutexLocker mu(Compile_lock, thread); +- Universe::flush_dependents_on(call_site, target); ++ MethodHandles::flush_dependent_nmethods(call_site, target); + java_lang_invoke_CallSite::set_target_volatile(call_site(), target()); + } + } + JVM_END + +-JVM_ENTRY(void, MHN_invalidateDependentNMethods(JNIEnv* env, jobject igcls, jobject call_site_jh)) { +- Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh)); ++JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject context_jh)) { ++ Handle context(THREAD, JNIHandles::resolve_non_null(context_jh)); + { + // Walk all nmethods depending on this call site. + MutexLocker mu1(Compile_lock, thread); + +- CallSiteDepChange changes(call_site(), Handle()); +- +- InstanceKlass* ctxk = MethodHandles::get_call_site_context(call_site()); +- if (ctxk == NULL) { +- return; // No dependencies to invalidate yet. +- } + int marked = 0; + { + MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); +- marked = ctxk->mark_dependent_nmethods(changes); ++ 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 + } +- java_lang_invoke_CallSite::set_context_volatile(call_site(), NULL); // Reset call site to initial state + if (marked > 0) { + // At least one nmethod has been marked for deoptimization + VM_Deoptimize op; +@@ -1408,6 +1446,7 @@ JVM_END + #define MT JLINV "MethodType;" + #define MH JLINV "MethodHandle;" + #define MEM JLINV "MemberName;" ++#define CTX JLINV"MethodHandleNatives$CallSiteContext;" + + #define CC (char*) /*cast a literal from (const char*)*/ + #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) +@@ -1426,7 +1465,7 @@ static JNINativeMethod MHN_methods[] = { + {CC "objectFieldOffset", CC "(" MEM ")J", FN_PTR(MHN_objectFieldOffset)}, + {CC "setCallSiteTargetNormal", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetNormal)}, + {CC "setCallSiteTargetVolatile", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetVolatile)}, +- {CC"invalidateDependentNMethods", CC"("CS")V", FN_PTR(MHN_invalidateDependentNMethods)}, ++ {CC"clearCallSiteContext", CC "(" CTX ")V", FN_PTR(MHN_clearCallSiteContext)}, + {CC "staticFieldOffset", CC "(" MEM ")J", FN_PTR(MHN_staticFieldOffset)}, + {CC "staticFieldBase", CC "(" MEM ")" OBJ, FN_PTR(MHN_staticFieldBase)}, + {CC "getMemberVMInfo", CC "(" MEM ")" OBJ, FN_PTR(MHN_getMemberVMInfo)} +diff --git a/hotspot/src/share/vm/prims/methodHandles.hpp b/hotspot/src/share/vm/prims/methodHandles.hpp +index 4b6af60df..71508d215 100644 +--- a/hotspot/src/share/vm/prims/methodHandles.hpp ++++ b/hotspot/src/share/vm/prims/methodHandles.hpp +@@ -69,7 +69,10 @@ class MethodHandles: AllStatic { + enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 }; + + // CallSite support +- static InstanceKlass* get_call_site_context(oop call_site); ++ static void add_dependent_nmethod(oop call_site, nmethod* nm); ++ static void remove_dependent_nmethod(oop call_site, nmethod* nm); ++ ++ static void flush_dependent_nmethods(Handle call_site, Handle target); + + // Generate MethodHandles adapters. + static void generate_adapters(); +diff --git a/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java +index 11e46ed03..d65bf4242 100644 +--- a/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java ++++ b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java +@@ -24,11 +24,15 @@ + /** + * @test + * @bug 8057967 +- * @run main/bootclasspath -Xbatch java.lang.invoke.CallSiteDepContextTest ++ * @run main/bootclasspath/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceClassUnloading ++ * -XX:+PrintCompilation -XX:+TraceDependencies -XX:+TraceReferenceGC ++ * -verbose:gc java.lang.invoke.CallSiteDepContextTest + */ + package java.lang.invoke; + + import java.lang.ref.*; ++import java.lang.reflect.Field; ++ + import jdk.internal.org.objectweb.asm.*; + import sun.misc.Unsafe; + +@@ -95,6 +99,13 @@ public class CallSiteDepContextTest { + } + } + ++ public static void testHiddenDepField() throws Exception { ++ try { ++ Field f = MethodHandleNatives.CallSiteContext.class.getDeclaredField("vmdependencies"); ++ throw new AssertionError("Context.dependencies field should be hidden"); ++ } catch(NoSuchFieldException e) { /* expected */ } ++ } ++ + public static void testSharedCallSite() throws Throwable { + Class cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_1"), null); + Class cls2 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_2"), null); +@@ -131,12 +142,14 @@ public class CallSiteDepContextTest { + static ReferenceQueue rq = new ReferenceQueue(); + static PhantomReference ref; + +- public static void testGC() throws Throwable { ++ public static void testGC(boolean clear, boolean precompile) throws Throwable { ++ String id = "_" + clear + "_" + precompile; ++ + mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); + + Class[] cls = new Class[] { +- UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1"), null), +- UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2"), null), ++ UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1" + id), null), ++ UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2" + id), null), + }; + + MethodHandle[] mhs = new MethodHandle[] { +@@ -150,30 +163,38 @@ public class CallSiteDepContextTest { + execute(1, mhs); + + ref = new PhantomReference<>(cls[0], rq); +- cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3"), null); ++ cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3" + id), null); + mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE); + + do { + System.gc(); + try { +- Reference ref1 = rq.remove(1000); ++ Reference ref1 = rq.remove(100); + if (ref1 == ref) { +- ref1.clear(); +- System.gc(); // Ensure that the stale context is cleared + break; + } + } catch(InterruptedException e) { /* ignore */ } + } while (true); + +- execute(1, mhs); ++ if (clear) { ++ ref.clear(); ++ System.gc(); // Ensure that the stale context is unloaded ++ } ++ if (precompile) { ++ execute(1, mhs); ++ } + mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); + execute(2, mhs); + } + + public static void main(String[] args) throws Throwable { ++ testHiddenDepField(); + testSharedCallSite(); + testNonBoundCallSite(); +- testGC(); ++ testGC(false, false); ++ testGC(false, true); ++ testGC( true, false); ++ testGC( true, true); + System.out.println("TEST PASSED"); + } + } +diff --git a/jdk/src/share/classes/java/lang/invoke/CallSite.java b/jdk/src/share/classes/java/lang/invoke/CallSite.java +index 11e452b96..13cf24ca0 100644 +--- a/jdk/src/share/classes/java/lang/invoke/CallSite.java ++++ b/jdk/src/share/classes/java/lang/invoke/CallSite.java +@@ -27,8 +27,6 @@ package java.lang.invoke; + + import static java.lang.invoke.MethodHandleStatics.*; + import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; +-import java.lang.reflect.Field; +-import sun.misc.Cleaner; + + /** + * A {@code CallSite} is a holder for a variable {@link MethodHandle}, +@@ -138,47 +136,9 @@ public class CallSite { + + /** + * {@code CallSite} dependency context. +- * VM uses context class to store nmethod dependencies on the call site target. +- * Can be in 2 states: (a) null; or (b) {@code Cleaner} instance pointing to some Class instance. +- * Lazily initialized when CallSite instance is linked to some indy call site or VM needs +- * it to store dependencies. As a corollary, "null" context means there are no dependencies +- * registered yet. {@code Cleaner} is used in 2 roles: +- * (a) context class access for VM; +- * (b) stale context class cleanup. +- * {@code Cleaner} holds the context class until cleanup action is finished (see {@code PhantomReference}). +- * Though it's impossible to get the context class using {@code Reference.get()}, VM extracts it directly +- * from {@code Reference.referent} field. ++ * JVM uses CallSite.context to store nmethod dependencies on the call site target. + */ +- private volatile Cleaner context = null; +- +- /** +- * Default context. +- * VM uses it to initialize non-linked CallSite context. +- */ +- private static class DefaultContext {} +- private static final Cleaner DEFAULT_CONTEXT = makeContext(DefaultContext.class, null); +- +- private static Cleaner makeContext(Class referent, final CallSite holder) { +- return Cleaner.create(referent, +- new Runnable() { +- @Override public void run() { +- MethodHandleNatives.invalidateDependentNMethods(holder); +- } +- }); +- } +- +- /** Initialize context class used for nmethod dependency tracking */ +- /*package-private*/ +- void initContext(Class newContext) { +- // If there are concurrent actions, exactly one succeeds. +- if (context == null) { +- UNSAFE.compareAndSwapObject(this, CONTEXT_OFFSET, /*expected=*/null, makeContext(newContext, this)); +- // No need to care about failed CAS attempt. +- // Since initContext is called from indy call site linkage in newContext class, there's no risk +- // that the context class becomes dead while corresponding context cleaner is alive (causing cleanup +- // action in the wrong context). +- } +- } ++ private final MethodHandleNatives.CallSiteContext context = MethodHandleNatives.CallSiteContext.make(this); + + /** + * Returns the type of this call site's target. +diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +index 9a1343c50..899a409e4 100644 +--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java ++++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +@@ -30,6 +30,7 @@ import java.lang.reflect.Field; + import static java.lang.invoke.MethodHandleNatives.Constants.*; + import static java.lang.invoke.MethodHandleStatics.*; + import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ++import sun.misc.Cleaner; + + /** + * The JVM interface for the method handles package is all here. +@@ -71,8 +72,27 @@ class MethodHandleNatives { + static native void setCallSiteTargetNormal(CallSite site, MethodHandle target); + static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target); + +- /** Invalidate CallSite context: clean up dependent nmethods and reset call site context to initial state (null). */ +- static native void invalidateDependentNMethods(CallSite site); ++ /** Represents a context to track nmethod dependencies on CallSite instance target. */ ++ static class CallSiteContext implements Runnable { ++ //@Injected JVM_nmethodBucket* vmdependencies; ++ ++ static CallSiteContext make(CallSite cs) { ++ final CallSiteContext newContext = new CallSiteContext(); ++ // Cleaner is attached to CallSite instance and it clears native structures allocated for CallSite context. ++ // Though the CallSite can become unreachable, its Context is retained by the Cleaner instance (which is ++ // referenced from Cleaner class) until cleanup is performed. ++ Cleaner.create(cs, newContext); ++ return newContext; ++ } ++ ++ @Override ++ public void run() { ++ MethodHandleNatives.clearCallSiteContext(this); ++ } ++ } ++ ++ /** Invalidate all recorded nmethods. */ ++ private static native void clearCallSiteContext(CallSiteContext context); + + private static native void registerNatives(); + static { +@@ -317,7 +337,6 @@ class MethodHandleNatives { + return Invokers.linkToTargetMethod(type); + } else { + appendixResult[0] = callSite; +- callSite.initContext(caller); + return Invokers.linkToCallSiteMethod(type); + } + } +-- +2.12.3 + diff --git a/8177146-MethodHandles.Lookup-bind-allows-illegal-pro.patch b/8177146-MethodHandles.Lookup-bind-allows-illegal-pro.patch new file mode 100644 index 0000000000000000000000000000000000000000..a168724f9d18123a4effb49c55d2a2c42df2579d --- /dev/null +++ b/8177146-MethodHandles.Lookup-bind-allows-illegal-pro.patch @@ -0,0 +1,221 @@ +From 5fbf4e8b326dd8453822ae40f3c6e4adffbf42ac Mon Sep 17 00:00:00 2001 +From: zhangyipeng +Date: Fri, 3 Nov 2023 16:21:09 +0800 +Subject: [PATCH] [Backport]8177146: MethodHandles.Lookup::bind allows illegal protected + access + +--- + .../classes/java/lang/invoke/MethodHandles.java | 22 +++-- + .../lang/invoke/8177146/TestMethodHandleBind.java | 96 ++++++++++++++++++++++ + jdk/test/java/lang/invoke/8177146/pkg/A.java | 40 +++++++++ + 3 files changed, 149 insertions(+), 9 deletions(-) + create mode 100644 jdk/test/java/lang/invoke/8177146/TestMethodHandleBind.java + create mode 100644 jdk/test/java/lang/invoke/8177146/pkg/A.java + +diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java +index 7b9353ab0..62888c019 100644 +--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java ++++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java +@@ -1148,7 +1148,13 @@ return mh1; + public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { + Class refc = receiver.getClass(); // may get NPE + MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type); +- MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method)); ++ MethodHandle mh = getDirectMethodNoRestrictInvokeSpecial(refc, method, findBoundCallerClass(method)); ++ if (!mh.type().leadingReferenceParameter().isAssignableFrom(receiver.getClass())) { ++ throw new IllegalAccessException("The restricted defining class " + ++ mh.type().leadingReferenceParameter().getName() + ++ " is not assignable from receiver class " + ++ receiver.getClass().getName()); ++ } + return mh.bindArgumentL(0, receiver).setVarargs(method); + } + +@@ -1591,7 +1597,7 @@ return mh1; + throw method.makeAccessException("caller class must be a subclass below the method", caller); + } + MethodType rawType = mh.type(); +- if (rawType.parameterType(0) == caller) return mh; ++ if (caller.isAssignableFrom(rawType.parameterType(0))) return mh; // no need to restrict; already narrow + MethodType narrowType = rawType.changeParameterType(0, caller); + assert(!mh.isVarargsCollector()); // viewAsType will lose varargs-ness + assert(mh.viewAsTypeChecks(narrowType, true)); +@@ -1604,11 +1610,11 @@ return mh1; + final boolean checkSecurity = true; + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass); + } +- /** Check access and get the requested method, eliding receiver narrowing rules. */ +- private MethodHandle getDirectMethodNoRestrict(byte refKind, Class refc, MemberName method, Class callerClass) throws IllegalAccessException { ++ /** Check access and get the requested method, for invokespecial with no restriction on the application of narrowing rules. */ ++ private MethodHandle getDirectMethodNoRestrictInvokeSpecial(Class refc, MemberName method, Class callerClass) throws IllegalAccessException { + final boolean doRestrict = false; + final boolean checkSecurity = true; +- return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass); ++ return getDirectMethodCommon(REF_invokeSpecial, refc, method, checkSecurity, doRestrict, callerClass); + } + /** Check access and get the requested method, eliding security manager checks. */ + private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class refc, MemberName method, Class callerClass) throws IllegalAccessException { +@@ -1660,10 +1666,8 @@ return mh1; + DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method); + MethodHandle mh = dmh; + // Optionally narrow the receiver argument to refc using restrictReceiver. +- if (doRestrict && +- (refKind == REF_invokeSpecial || +- (MethodHandleNatives.refKindHasReceiver(refKind) && +- restrictProtectedReceiver(method)))) { ++ if ((doRestrict && refKind == REF_invokeSpecial) || ++ (MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(method))) { + mh = restrictReceiver(method, dmh, lookupClass()); + } + mh = maybeBindCaller(method, mh, callerClass); +diff --git a/jdk/test/java/lang/invoke/8177146/TestMethodHandleBind.java b/jdk/test/java/lang/invoke/8177146/TestMethodHandleBind.java +new file mode 100644 +index 000000000..134cc9f75 +--- /dev/null ++++ b/jdk/test/java/lang/invoke/8177146/TestMethodHandleBind.java +@@ -0,0 +1,96 @@ ++/* ++ * Copyright (c) 2017, 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 ++ * @bug 8177146 ++ * @run testng/othervm TestMethodHandleBind ++ */ ++ ++import org.testng.annotations.Test; ++ ++import java.lang.invoke.MethodHandle; ++import java.lang.invoke.MethodType; ++ ++import static java.lang.invoke.MethodHandles.lookup; ++ ++import static org.testng.Assert.*; ++ ++public class TestMethodHandleBind extends pkg.A { ++ static class B extends TestMethodHandleBind {} ++ ++ @Test ++ public void testInstanceOfCallerClass() throws Throwable { ++ MethodHandle bound = lookup().bind(new TestMethodHandleBind() , "m1", MethodType.methodType(String.class)); ++ String x = (String)bound.invoke(); ++ assertEquals(x, this.getClass().getSimpleName()); ++ } ++ ++ @Test ++ public void testInstanceOfCallerSubclass() throws Throwable { ++ MethodHandle bound = lookup().bind(new B() , "m1", MethodType.methodType(String.class)); ++ // MethodHandle bound = lookup().findVirtual(B.class, "m1", MethodType.methodType(String.class)).bindTo(new B()); ++ String x = (String)bound.invoke(); ++ assertEquals(x, "B"); ++ } ++ ++ @Test ++ public void testInstanceOfReceiverClass() throws Throwable { ++ try { ++ MethodHandle bound = lookup().bind(new pkg.A() , "m1", MethodType.methodType(String.class)); ++ bound.invoke(); ++ fail("IllegalAccessException expected"); ++ } catch (IllegalAccessException e) { ++ } ++ } ++ ++ @Test ++ public void testPublicMethod() throws Throwable { ++ MethodHandle bound = lookup().bind(new pkg.A() , "m2", MethodType.methodType(String.class)); ++ String x = (String)bound.invoke(); ++ assertEquals(x, "A"); ++ } ++ ++ @Test ++ public void testPublicMethod2() throws Throwable { ++ MethodHandle bound = lookup().bind(new TestMethodHandleBind(), "m2", MethodType.methodType(String.class)); ++ String x = (String)bound.invoke(); ++ assertEquals(x, this.getClass().getSimpleName()); ++ } ++ ++ @Test ++ public void testInstanceOfCallerClassVarargs() throws Throwable { ++ MethodHandle bound = lookup().bind(new TestMethodHandleBind() , "m3", MethodType.methodType(String.class, String[].class)); ++ String x = (String)bound.invoke("a", "b", "c"); ++ assertEquals(x, this.getClass().getSimpleName() + "abc"); ++ } ++ ++ @Test ++ public void testInstanceOfReceiverClassVarargs() throws Throwable { ++ try { ++ MethodHandle bound = lookup().bind(new pkg.A(), "m3", MethodType.methodType(String.class, String[].class)); ++ bound.invoke(); ++ fail("IllegalAccessException expected"); ++ } catch (IllegalAccessException e) { ++ } ++ } ++} +diff --git a/jdk/test/java/lang/invoke/8177146/pkg/A.java b/jdk/test/java/lang/invoke/8177146/pkg/A.java +new file mode 100644 +index 000000000..f34d52b8e +--- /dev/null ++++ b/jdk/test/java/lang/invoke/8177146/pkg/A.java +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2017, 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. ++ */ ++package pkg; ++ ++public class A { ++ protected String m1() { ++ return this.getClass().getSimpleName(); ++ } ++ ++ public String m2() { ++ return this.getClass().getSimpleName(); ++ } ++ ++ protected String m3(String... args) { ++ StringBuilder sb = new StringBuilder(); ++ for (String s : args) ++ sb.append(s); ++ return this.getClass().getSimpleName() + sb.toString(); ++ } ++} +-- +2.12.3 + diff --git a/8203699.patch b/8203699.patch index 02dd88ac4db63332d26926a327065d36715698e9..8c242c983c810bd60b78ba4ef53d715557ab63fa 100644 --- a/8203699.patch +++ b/8203699.patch @@ -12,22 +12,6 @@ Bug url: https://bugs.openjdk.java.net/browse/JDK-8203699 2 files changed, 171 insertions(+) create mode 100644 jdk/test/java/lang/invoke/lookup/TestDefenderMethodLookup.java -diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp -index f771c5f07..70ab1bcb8 100644 ---- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp -+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp -@@ -1209,6 +1209,11 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, - mov(r0, super_klass); - } - -+ // Get super_klass value into r0 (even if it was in r5 or r2) -+ if (super_klass != r0) { -+ mov(r0, super_klass); -+ } -+ - #ifndef PRODUCT - mov(rscratch2, (address)&SharedRuntime::_partial_subtype_ctr); - Address pst_counter_addr(rscratch2); diff --git a/jdk/test/java/lang/invoke/lookup/TestDefenderMethodLookup.java b/jdk/test/java/lang/invoke/lookup/TestDefenderMethodLookup.java new file mode 100644 index 000000000..8ab268b57 diff --git a/8260923-Add-more-tests-for-SSLSocket-input-output-sh.patch b/8260923-Add-more-tests-for-SSLSocket-input-output-sh.patch new file mode 100644 index 0000000000000000000000000000000000000000..c49fe15533ec52962c94bdbeb0adc31580577567 --- /dev/null +++ b/8260923-Add-more-tests-for-SSLSocket-input-output-sh.patch @@ -0,0 +1,131 @@ +From c3aae68d629a3adc02fb0764c95d922e716f0ee3 Mon Sep 17 00:00:00 2001 +From: zhangyipeng +Date: Mon, 15 Jan 2024 11:13:55 +0800 +Subject: [PATCH] [Backport]8260923: Add more tests for SSLSocket input/output shutdown +--- + .../ssl/SSLSocketImpl/SSLSocketCloseHang.java | 69 ++++++++++++++-------- + 1 file changed, 46 insertions(+), 23 deletions(-) + +diff --git a/jdk/test/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java b/jdk/test/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java +index f74c1fe76..ff6334feb 100644 +--- a/jdk/test/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java ++++ b/jdk/test/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java +@@ -23,12 +23,17 @@ + + /* + * @test +- * @bug 8184328 8253368 ++ * @bug 8184328 8253368 8260923 + * @summary JDK8u131-b34-socketRead0 hang at SSL read +- * @run main/othervm SSLSocketCloseHang +- * @run main/othervm SSLSocketCloseHang shutdownInputTest ++ * @run main/othervm SSLSocketCloseHang TLSv1.2 ++ * @run main/othervm SSLSocketCloseHang TLSv1.2 shutdownInput ++ * @run main/othervm SSLSocketCloseHang TLSv1.2 shutdownOutput ++ * @run main/othervm SSLSocketCloseHang TLSv1.3 ++ * @run main/othervm SSLSocketCloseHang TLSv1.3 shutdownInput ++ * @run main/othervm SSLSocketCloseHang TLSv1.3 shutdownOutput + */ + ++ + import java.io.*; + import java.net.*; + import java.util.*; +@@ -36,7 +41,6 @@ import java.security.*; + import javax.net.ssl.*; + + public class SSLSocketCloseHang { +- + /* + * ============================================================= + * Set the various variables needed for the tests, then +@@ -73,7 +77,7 @@ public class SSLSocketCloseHang { + */ + static boolean debug = false; + +- static boolean shutdownInputTest = false; ++ static String socketCloseType; + + /* + * If the client or server is doing some kind of object creation +@@ -148,28 +152,45 @@ public class SSLSocketCloseHang { + Thread.sleep(500); + System.err.println("Client closing: " + System.nanoTime()); + +- if (shutdownInputTest) { +- try { +- sslSocket.shutdownInput(); +- } catch (SSLException e) { +- if (!e.getMessage().contains +- ("closing inbound before receiving peer's close_notify")) { +- throw new RuntimeException("expected different exception message. " + +- e.getMessage()); +- } +- } +- if (!sslSocket.getSession().isValid()) { +- throw new RuntimeException("expected session to remain valid"); +- } ++ closeConnection(sslSocket); ++ ++ clientClosed = true; ++ System.err.println("Client closed: " + System.nanoTime()); ++ } + ++ private void closeConnection(SSLSocket sslSocket) throws IOException { ++ if ("shutdownInput".equals(socketCloseType)) { ++ shutdownInput(sslSocket); ++ // second call to shutdownInput() should just return, ++ // shouldn't throw any exception ++ sslSocket.shutdownInput(); ++ // invoking shutdownOutput() just after shutdownInput() ++ sslSocket.shutdownOutput(); ++ } else if ("shutdownOutput".equals(socketCloseType)) { ++ sslSocket.shutdownOutput(); ++ // second call to shutdownInput() should just return, ++ // shouldn't throw any exception ++ sslSocket.shutdownOutput(); ++ // invoking shutdownInput() just after shutdownOutput() ++ shutdownInput(sslSocket); + } else { + sslSocket.close(); + } ++ } + +- +- +- clientClosed = true; +- System.err.println("Client closed: " + System.nanoTime()); ++ private void shutdownInput(SSLSocket sslSocket) throws IOException { ++ try { ++ sslSocket.shutdownInput(); ++ } catch (SSLException e) { ++ if (!e.getMessage().contains ++ ("closing inbound before receiving peer's close_notify")) { ++ throw new RuntimeException("expected different exception " ++ + "message. " + e.getMessage()); ++ } ++ } ++ if (!sslSocket.getSession().isValid()) { ++ throw new RuntimeException("expected session to remain valid"); ++ } + } + + /* +@@ -197,11 +218,13 @@ public class SSLSocketCloseHang { + System.setProperty("javax.net.ssl.keyStorePassword", passwd); + System.setProperty("javax.net.ssl.trustStore", trustFilename); + System.setProperty("javax.net.ssl.trustStorePassword", passwd); ++ System.setProperty("jdk.tls.client.protocols", args[0]); + + if (debug) + System.setProperty("javax.net.debug", "all"); + +- shutdownInputTest = args.length > 0 ? true : false; ++ socketCloseType = args.length > 1 ? args[1] : ""; ++ + + /* + * Start the tests. +-- +2.12.3 + diff --git a/8273553-sun.security.ssl.SSLEngineImpl.closeInbound-.patch b/8273553-sun.security.ssl.SSLEngineImpl.closeInbound-.patch new file mode 100644 index 0000000000000000000000000000000000000000..fce10484c340ee7e45c3bd871c296e2355cd8344 --- /dev/null +++ b/8273553-sun.security.ssl.SSLEngineImpl.closeInbound-.patch @@ -0,0 +1,581 @@ +From 4e32bc622c1f73c2ab6a4ef4b4bbd92e381a3439 Mon Sep 17 00:00:00 2001 +From: zhangyipeng +Date: Mon, 15 Jan 2024 11:11:41 +0800 +Subject: [PATCH] [Backport]8273553: sun.security.ssl.SSLEngineImpl.closeInbound also has + similar error of JDK-8253368 +--- + .../classes/sun/security/ssl/SSLEngineImpl.java | 24 +- + .../classes/sun/security/ssl/SSLSocketImpl.java | 7 +- + .../SSLSocketSSLEngineCloseInbound.java | 491 +++++++++++++++++++++ + 3 files changed, 508 insertions(+), 14 deletions(-) + create mode 100644 jdk/test/sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java + +diff --git a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java +index 05ffb8a00..a9cc989f2 100644 +--- a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java ++++ b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java +@@ -47,7 +47,7 @@ import javax.net.ssl.SSLProtocolException; + import javax.net.ssl.SSLSession; + + /** +- * Implementation of an non-blocking SSLEngine. ++ * Implementation of a non-blocking SSLEngine. + * + * @author Brad Wetmore + */ +@@ -230,7 +230,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { + if (ciphertext == null && !conContext.isNegotiated && + conContext.isInboundClosed() && + hsStatus == HandshakeStatus.NEED_WRAP) { +- // Even the outboud is open, no futher data could be wrapped as: ++ // Even the outbound is open, no further data could be wrapped as: + // 1. the outbound is empty + // 2. no negotiated connection + // 3. the inbound has closed, cannot complete the handshake +@@ -631,17 +631,19 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { + SSLLogger.finest("Closing inbound of SSLEngine"); + } + +- // Is it ready to close inbound? +- // +- // No need to throw exception if the initial handshake is not started. +- if (!conContext.isInputCloseNotified && +- (conContext.isNegotiated || conContext.handshakeContext != null)) { + +- throw conContext.fatal(Alert.INTERNAL_ERROR, +- "closing inbound before receiving peer's close_notify"); ++ try { ++ // Is it ready to close inbound? ++ // ++ // No need to throw exception if the initial handshake is not started. ++ if (!conContext.isInputCloseNotified && ++ (conContext.isNegotiated || conContext.handshakeContext != null)) { ++ throw new SSLException( ++ "closing inbound before receiving peer's close_notify"); ++ } ++ } finally { ++ conContext.closeInbound(); + } +- +- conContext.closeInbound(); + } + + @Override +diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +index 69c96f226..7e8b131bb 100644 +--- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java ++++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +@@ -742,9 +742,10 @@ public final class SSLSocketImpl + // No need to throw exception if the initial handshake is not started. + try { + if (checkCloseNotify && !conContext.isInputCloseNotified && +- (conContext.isNegotiated || conContext.handshakeContext != null)) { +- throw new SSLException( +- "closing inbound before receiving peer's close_notify"); ++ (conContext.isNegotiated || ++ conContext.handshakeContext != null)) { ++ throw new SSLException( ++ "closing inbound before receiving peer's close_notify"); + } + } finally { + conContext.closeInbound(); +diff --git a/jdk/test/sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java b/jdk/test/sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java +new file mode 100644 +index 000000000..abf1571ca +--- /dev/null ++++ b/jdk/test/sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java +@@ -0,0 +1,491 @@ ++/* ++ * Copyright (c) 2011, 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. ++ */ ++ ++// ++// SunJSSE does not support dynamic system properties, no way to re-use ++// system properties in samevm/agentvm mode. ++// ++ ++/* ++ * @test ++ * @bug 8273553 8253368 ++ * @summary sun.security.ssl.SSLEngineImpl.closeInbound also has similar error ++ * of JDK-8253368 ++ * @run main/othervm SSLSocketSSLEngineCloseInbound TLSv1.3 ++ * @run main/othervm SSLSocketSSLEngineCloseInbound TLSv1.2 ++ * @run main/othervm SSLSocketSSLEngineCloseInbound TLSv1.1 ++ * @run main/othervm SSLSocketSSLEngineCloseInbound TLSv1 ++ * @run main/othervm SSLSocketSSLEngineCloseInbound TLS ++ */ ++ ++/** ++ * A SSLSocket/SSLEngine interop test case. This is not the way to ++ * code SSLEngine-based servers, but works for what we need to do here, ++ * which is to make sure that SSLEngine/SSLSockets can talk to each other. ++ * SSLEngines can use direct or indirect buffers, and different code ++ * is used to get at the buffer contents internally, so we test that here. ++ * ++ * The test creates one SSLSocket (client) and one SSLEngine (server). ++ * The SSLSocket talks to a raw ServerSocket, and the server code ++ * does the translation between byte [] and ByteBuffers that the SSLEngine ++ * can use. The "transport" layer consists of a Socket Input/OutputStream ++ * and two byte buffers for the SSLEngines: think of them ++ * as directly connected pipes. ++ * ++ * Again, this is a *very* simple example: real code will be much more ++ * involved. For example, different threading and I/O models could be ++ * used, transport mechanisms could close unexpectedly, and so on. ++ * ++ * When this application runs, notice that several messages ++ * (wrap/unwrap) pass before any application data is consumed or ++ * produced. (For more information, please see the SSL/TLS ++ * specifications.) There may several steps for a successful handshake, ++ * so it's typical to see the following series of operations: ++ * ++ * client server message ++ * ====== ====== ======= ++ * write() ... ClientHello ++ * ... unwrap() ClientHello ++ * ... wrap() ServerHello/Certificate ++ * read() ... ServerHello/Certificate ++ * write() ... ClientKeyExchange ++ * write() ... ChangeCipherSpec ++ * write() ... Finished ++ * ... unwrap() ClientKeyExchange ++ * ... unwrap() ChangeCipherSpec ++ * ... unwrap() Finished ++ * ... wrap() ChangeCipherSpec ++ * ... wrap() Finished ++ * read() ... ChangeCipherSpec ++ * read() ... Finished ++ */ ++import javax.net.ssl.*; ++import javax.net.ssl.SSLEngineResult.*; ++import java.io.*; ++import java.net.*; ++import java.security.*; ++import java.nio.*; ++ ++public class SSLSocketSSLEngineCloseInbound { ++ ++ /* ++ * Enables logging of the SSL/TLS operations. ++ */ ++ private static final boolean logging = true; ++ ++ /* ++ * Enables the JSSE system debugging system property: ++ * ++ * -Djavax.net.debug=all ++ * ++ * This gives a lot of low-level information about operations underway, ++ * including specific handshake messages, and might be best examined ++ * after gaining some familiarity with this application. ++ */ ++ private static final boolean debug = false; ++ private final SSLContext sslc; ++ private SSLEngine serverEngine; // server-side SSLEngine ++ private SSLSocket clientSocket; ++ ++ private final byte[] serverMsg = ++ "Hi there Client, I'm a Server.".getBytes(); ++ private final byte[] clientMsg = ++ "Hello Server, I'm a Client! Pleased to meet you!".getBytes(); ++ ++ private ByteBuffer serverOut; // write side of serverEngine ++ private ByteBuffer serverIn; // read side of serverEngine ++ ++ private volatile Exception clientException; ++ private volatile Exception serverException; ++ ++ /* ++ * For data transport, this example uses local ByteBuffers. ++ */ ++ private ByteBuffer cTOs; // "reliable" transport client->server ++ private ByteBuffer sTOc; // "reliable" transport server->client ++ ++ /* ++ * The following is to set up the keystores/trust material. ++ */ ++ private static final String pathToStores = "../../../../javax/net/ssl/etc"; ++ private static final String keyStoreFile = "keystore"; ++ private static final String trustStoreFile = "truststore"; ++ private static final String keyFilename = ++ System.getProperty("test.src", ".") + "/" + pathToStores ++ + "/" + keyStoreFile; ++ private static final String trustFilename = ++ System.getProperty("test.src", ".") + "/" + pathToStores ++ + "/" + trustStoreFile; ++ ++ /* ++ * Main entry point for this test. ++ */ ++ public static void main(String[] args) throws Exception { ++ String protocol = args[0]; ++ ++ // reset security properties to make sure that the algorithms ++ // and keys used in this test are not disabled. ++ Security.setProperty("jdk.tls.disabledAlgorithms", ""); ++ Security.setProperty("jdk.certpath.disabledAlgorithms", ""); ++ ++ if (debug) { ++ System.setProperty("javax.net.debug", "all"); ++ } ++ ++ /* ++ * Run the tests with direct and indirect buffers. ++ */ ++ SSLSocketSSLEngineCloseInbound test = ++ new SSLSocketSSLEngineCloseInbound(protocol); ++ log("-------------------------------------"); ++ log("Testing " + protocol + " for direct buffers ..."); ++ test.runTest(true); ++ ++ log("---------------------------------------"); ++ log("Testing " + protocol + " for indirect buffers ..."); ++ test.runTest(false); ++ ++ log("Test Passed."); ++ } ++ ++ /* ++ * Create an initialized SSLContext to use for these tests. ++ */ ++ public SSLSocketSSLEngineCloseInbound(String protocol) throws Exception { ++ ++ KeyStore ks = KeyStore.getInstance("JKS"); ++ KeyStore ts = KeyStore.getInstance("JKS"); ++ ++ char[] passphrase = "passphrase".toCharArray(); ++ ++ try (FileInputStream keyFile = new FileInputStream(keyFilename); ++ FileInputStream trustFile = new FileInputStream(trustFilename)) { ++ ks.load(keyFile, passphrase); ++ ts.load(trustFile, passphrase); ++ } ++ ++ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); ++ kmf.init(ks, passphrase); ++ ++ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); ++ tmf.init(ts); ++ ++ SSLContext sslCtx = SSLContext.getInstance(protocol); ++ ++ sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); ++ ++ sslc = sslCtx; ++ } ++ ++ /* ++ * Run the test. ++ * ++ * Sit in a tight loop, with the server engine calling wrap/unwrap ++ * regardless of whether data is available or not. We do this until ++ * we get the application data. Then we shutdown and go to the next one. ++ * ++ * The main loop handles all the I/O phases of the SSLEngine's ++ * lifetime: ++ * ++ * initial handshaking ++ * application data transfer ++ * engine closing ++ * ++ * One could easily separate these phases into separate ++ * sections of code. ++ */ ++ private void runTest(boolean direct) throws Exception { ++ clientSocket = null; ++ ++ // generates the server-side Socket ++ try (ServerSocket serverSocket = new ServerSocket()) { ++ serverSocket.setReuseAddress(false); ++ serverSocket.bind(null); ++ int port = serverSocket.getLocalPort(); ++ log("Port: " + port); ++ Thread thread = createClientThread(port); ++ ++ createSSLEngine(); ++ createBuffers(direct); ++ ++ // server-side socket that will read ++ try (Socket socket = serverSocket.accept()) { ++ socket.setSoTimeout(500); ++ ++ InputStream is = socket.getInputStream(); ++ OutputStream os = socket.getOutputStream(); ++ ++ SSLEngineResult serverResult; // results from last operation ++ ++ /* ++ * Examining the SSLEngineResults could be much more involved, ++ * and may alter the overall flow of the application. ++ * ++ * For example, if we received a BUFFER_OVERFLOW when trying ++ * to write to the output pipe, we could reallocate a larger ++ * pipe, but instead we wait for the peer to drain it. ++ */ ++ byte[] inbound = new byte[8192]; ++ byte[] outbound = new byte[8192]; ++ ++ while (!isEngineClosed(serverEngine)) { ++ int len; ++ ++ // Inbound data ++ log("================"); ++ ++ // Try reading Client side, even if it's already closed. ++ try { ++ len = is.read(inbound); ++ if (len > 0) { ++ cTOs.put(inbound, 0, len); ++ } ++ } catch (IOException e) { ++ /* ++ * swallow IO/SocketTimeoutExceptions. We'll do ++ * the testing/exit after the unwraps. ++ */ ++ } ++ ++ cTOs.flip(); ++ ++ serverResult = serverEngine.unwrap(cTOs, serverIn); ++ log("server unwrap: ", serverResult); ++ runDelegatedTasks(serverResult, serverEngine); ++ cTOs.compact(); ++ ++ // Outbound data ++ log("----"); ++ ++ // After we've received our app bytes, close input side ++ // and see what happens. Exit the test at the end. ++ if (serverIn.position() != 0) { ++ try { ++ serverEngine.closeInbound(); ++ throw new Exception( ++ "No error shutting down client's input"); ++ } catch (SSLException e) { ++ System.out.println( ++ "Server caught the right Exception"); ++ } ++ ++ if (serverEngine.getSession().isValid()) { ++ System.out.println("Server session is still valid"); ++ } else { ++ throw new Exception("Server session is not valid"); ++ } ++ ++ return; ++ } ++ ++ serverResult = serverEngine.wrap(serverOut, sTOc); ++ log("server wrap: ", serverResult); ++ runDelegatedTasks(serverResult, serverEngine); ++ ++ sTOc.flip(); ++ ++ if ((len = sTOc.remaining()) != 0) { ++ sTOc.get(outbound, 0, len); ++ os.write(outbound, 0, len); ++ // Give the other side a chance to process ++ } ++ ++ sTOc.compact(); ++ } ++ } catch (Exception e) { ++ serverException = e; ++ } finally { ++ // Wait for the client to join up with us. ++ if (thread != null) { ++ thread.join(); ++ } ++ } ++ } finally { ++ if (serverException != null) { ++ if (clientException != null) { ++ serverException.initCause(clientException); ++ } ++ throw serverException; ++ } ++ if (clientException != null) { ++ if (serverException != null) { ++ clientException.initCause(serverException); ++ } ++ throw clientException; ++ } ++ } ++ } ++ ++ /* ++ * Create a client thread which does simple SSLSocket operations. ++ * We'll write and read one data packet. ++ */ ++ private Thread createClientThread(final int port) { ++ ++ Thread t = new Thread("ClientThread") { ++ ++ @Override ++ public void run() { ++ // client-side socket ++ try (SSLSocket sslSocket = (SSLSocket)sslc.getSocketFactory(). ++ createSocket("localhost", port)) { ++ clientSocket = sslSocket; ++ ++ OutputStream os = sslSocket.getOutputStream(); ++ ++ // write(byte[]) goes in one shot. ++ os.write(clientMsg); ++ os.flush(); ++ ++ try { ++ sslSocket.shutdownInput(); ++ throw new Exception( ++ "No error shutting down client's input"); ++ } catch (SSLException e) { ++ System.out.println("Client caught the right Exception"); ++ } ++ ++ if (sslSocket.getSession().isValid()) { ++ System.out.println("Client session is still valid"); ++ } else { ++ throw new Exception("Client's session is not valid"); ++ } ++ ++ // Give server a chance to read before we shutdown via ++ // the try-with-resources block. ++ Thread.sleep(2000); ++ } catch (Exception e) { ++ clientException = e; ++ } ++ } ++ }; ++ t.start(); ++ return t; ++ } ++ ++ /* ++ * Using the SSLContext created during object creation, ++ * create/configure the SSLEngines we'll use for this test. ++ */ ++ private void createSSLEngine() { ++ /* ++ * Configure the serverEngine to act as a server in the SSL/TLS ++ * handshake. ++ */ ++ serverEngine = sslc.createSSLEngine(); ++ serverEngine.setUseClientMode(false); ++ serverEngine.getNeedClientAuth(); ++ } ++ ++ /* ++ * Create and size the buffers appropriately. ++ */ ++ private void createBuffers(boolean direct) { ++ ++ SSLSession session = serverEngine.getSession(); ++ int appBufferMax = session.getApplicationBufferSize(); ++ int netBufferMax = session.getPacketBufferSize(); ++ ++ /* ++ * We'll make the input buffers a bit bigger than the max needed ++ * size, so that unwrap()s following a successful data transfer ++ * won't generate BUFFER_OVERFLOWS. ++ * ++ * We'll use a mix of direct and indirect ByteBuffers for ++ * tutorial purposes only. In reality, only use direct ++ * ByteBuffers when they give a clear performance enhancement. ++ */ ++ if (direct) { ++ serverIn = ByteBuffer.allocateDirect(appBufferMax + 50); ++ cTOs = ByteBuffer.allocateDirect(netBufferMax); ++ sTOc = ByteBuffer.allocateDirect(netBufferMax); ++ } else { ++ serverIn = ByteBuffer.allocate(appBufferMax + 50); ++ cTOs = ByteBuffer.allocate(netBufferMax); ++ sTOc = ByteBuffer.allocate(netBufferMax); ++ } ++ ++ serverOut = ByteBuffer.wrap(serverMsg); ++ } ++ ++ /* ++ * If the result indicates that we have outstanding tasks to do, ++ * go ahead and run them in this thread. ++ */ ++ private static void runDelegatedTasks(SSLEngineResult result, ++ SSLEngine engine) throws Exception { ++ ++ if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { ++ Runnable runnable; ++ while ((runnable = engine.getDelegatedTask()) != null) { ++ log("\trunning delegated task..."); ++ runnable.run(); ++ } ++ HandshakeStatus hsStatus = engine.getHandshakeStatus(); ++ if (hsStatus == HandshakeStatus.NEED_TASK) { ++ throw new Exception( ++ "handshake shouldn't need additional tasks"); ++ } ++ log("\tnew HandshakeStatus: " + hsStatus); ++ } ++ } ++ ++ private static boolean isEngineClosed(SSLEngine engine) { ++ return (engine.isOutboundDone() && engine.isInboundDone()); ++ } ++ ++ /* ++ * Logging code ++ */ ++ private static boolean resultOnce = true; ++ ++ private static void log(String str, SSLEngineResult result) { ++ if (!logging) { ++ return; ++ } ++ if (resultOnce) { ++ resultOnce = false; ++ log("The format of the SSLEngineResult is: \n" ++ + "\t\"getStatus() / getHandshakeStatus()\" +\n" ++ + "\t\"bytesConsumed() / bytesProduced()\"\n"); ++ } ++ HandshakeStatus hsStatus = result.getHandshakeStatus(); ++ log(str ++ + result.getStatus() + "/" + hsStatus + ", " ++ + result.bytesConsumed() + "/" + result.bytesProduced() ++ + " bytes"); ++ if (hsStatus == HandshakeStatus.FINISHED) { ++ log("\t...ready for application data"); ++ } ++ } ++ ++ private static void log(String str) { ++ if (logging) { ++ if (debug) { ++ System.err.println(str); ++ } else { ++ System.out.println(str); ++ } ++ } ++ } ++} +-- +2.12.3 + diff --git a/Add-CaptchaTest-and-fix-KAE-Testcases.patch b/Add-CaptchaTest-and-fix-KAE-Testcases.patch new file mode 100644 index 0000000000000000000000000000000000000000..581ff621bce1f6e83989770face0b9f369ee22c4 --- /dev/null +++ b/Add-CaptchaTest-and-fix-KAE-Testcases.patch @@ -0,0 +1,135 @@ +diff --git a/jdk/test/java/awt/FontClass/CaptchaTest.java b/jdk/test/java/awt/FontClass/CaptchaTest.java +new file mode 100644 +index 000000000..7f2ed1275 +--- /dev/null ++++ b/jdk/test/java/awt/FontClass/CaptchaTest.java +@@ -0,0 +1,53 @@ ++/* ++ * Copyright © 2023 Xiaotao NAN. All rights reserved. ++ */ ++import java.awt.Graphics2D; ++import java.awt.Color; ++import java.awt.Font; ++import java.awt.image.BufferedImage; ++import java.io.IOException; ++import java.util.Random; ++ ++/* ++ * @test ++ * @summary Check if the captcha can be successfully generated ++ * @author XiaotaoNAN ++ * I8ME2N(https://gitee.com/openeuler/bishengjdk-8/issues/I8ME2N?from=project-issue) ++ */ ++ ++public class CaptchaTest { ++ ++ /** ++ * Check if the captcha can be successfully generated. ++ * @param n the number of digits int the captcha. ++ * @param fontName the font name. ++ * @throws IOException ++ */ ++ public static String captchaTest(int n,String fontName) throws IOException { ++ int width = 100, height = 50; ++ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); ++ Graphics2D g = image.createGraphics(); ++ g.setColor(Color.LIGHT_GRAY); ++ g.fillRect(0, 0, width, height); ++ String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; ++ Random random = new Random(); ++ StringBuilder sbuffer = new StringBuilder(); ++ for (int i = 0; i < n; i++) { ++ int index = random.nextInt(chars.length()); ++ char c = chars.charAt(index); ++ sbuffer.append(c); ++ g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255))); ++ g.setFont(new Font(fontName, Font.BOLD, 25)); ++ g.drawString(Character.toString(c), 20 + i * 15, 25); ++ } ++ image.flush(); ++ g.dispose(); ++ return sbuffer.toString(); ++ } ++ ++ public static void main(String[] args) throws IOException { ++ String captcha = captchaTest(4,"Times New Roman"); ++ System.out.println(captcha); ++ } ++ ++} +diff --git a/jdk/test/java/security/Provider/SunJCEValidator.java b/jdk/test/java/security/Provider/SunJCEValidator.java +index 314abb380..e6b9f18ad 100644 +--- a/jdk/test/java/security/Provider/SunJCEValidator.java ++++ b/jdk/test/java/security/Provider/SunJCEValidator.java +@@ -37,10 +37,10 @@ + *- @TestCaseType:Function test + *- @RequirementID:AR.SR.IREQ02758058.001.001 + *- @RequirementName: java.security.Provider.getService() is synchronized and became scalability bottleneck +- *- @Condition:JDK8u302及以后 +- *- @Brief:测试相应provider更改底层架构以后所提供的service是否与原先有差异(以openJDK8u302为准) +- * -#step:比较openJDK8u302 SunJceProvider与此特性修改后的SunJceProvider所提供的service是否一致 +- *- @Expect:正常运行 ++ *- @Condition:JDK8u302 and later ++ *- @Brief:Check whether the service provided by the corresponding provider after changing the underlying architecture is different from the original one (subject to openJDK8u302) ++ * -#step:Compare whether the service provided by openJDK8u302 SunJceProvider is consistent with the modified SunJceProvider with this feature ++ *- @Expect:Normal Running + *- @Priority:Level 1 + */ + +diff --git a/jdk/test/java/security/Provider/SunJSSEValidator.java b/jdk/test/java/security/Provider/SunJSSEValidator.java +index 5817c3b7f..0cf0663a4 100644 +--- a/jdk/test/java/security/Provider/SunJSSEValidator.java ++++ b/jdk/test/java/security/Provider/SunJSSEValidator.java +@@ -37,10 +37,10 @@ + *- @TestCaseType:Function test + *- @RequirementID:AR.SR.IREQ02758058.001.001 + *- @RequirementName: java.security.Provider.getService() is synchronized and became scalability bottleneck +- *- @Condition:JDK8u302及以后 +- *- @Brief:测试相应provider更改底层架构以后所提供的service是否与原先有差异(以openJDK8u302为准) +- * -#step:比较openJDK8u302 SunJSSEProvider与此特性修改后的SunJSSEProvider所提供的service是否一致 +- *- @Expect:正常运行 ++ *- @Condition:JDK8u302 and later ++ *- @Brief:Check whether the service provided by the corresponding provider after changing the underlying architecture is different from the original one (subject to openJDK8u302) ++ * -#step:Compare whether the service provided by openJDK8u302 SunJSSEProvider is consistent with the modified SunJSSEProvider with this feature ++ *- @Expect:Normal Running + *- @Priority:Level 1 + */ + +diff --git a/jdk/test/java/security/Provider/SunRsaSignValidator.java b/jdk/test/java/security/Provider/SunRsaSignValidator.java +index 66fb33a44..ddcf6107b 100644 +--- a/jdk/test/java/security/Provider/SunRsaSignValidator.java ++++ b/jdk/test/java/security/Provider/SunRsaSignValidator.java +@@ -37,10 +37,10 @@ + *- @TestCaseType:Function test + *- @RequirementID:AR.SR.IREQ02758058.001.001 + *- @RequirementName: java.security.Provider.getService() is synchronized and became scalability bottleneck +- *- @Condition:JDK8u302及以后 +- *- @Brief:测试相应provider更改底层架构以后所提供的service是否与原先有差异(以openJDK8u302为准) +- * -#step:比较openJDK8u302 SunRsaSignProvider与此特性修改后的SunRsaSignProvider所提供的service是否一致 +- *- @Expect:正常运行 ++ *- @Condition:JDK8u302 and later ++ *- @Brief:Check whether the service provided by the corresponding provider after changing the underlying architecture is different from the original one (subject to openJDK8u302). ++ * -#step:Compare whether the service provided by openJDK8u302 SunRsaSignProvider is consistent with the modified SunRsaSignProvider with this feature. ++ *- @Expect:Normal Running. + *- @Priority:Level 1 + */ + +diff --git a/jdk/test/java/security/Provider/SunValidator.java b/jdk/test/java/security/Provider/SunValidator.java +index 3f4b81222..b1fc38303 100644 +--- a/jdk/test/java/security/Provider/SunValidator.java ++++ b/jdk/test/java/security/Provider/SunValidator.java +@@ -37,10 +37,10 @@ + *- @TestCaseType:Function test + *- @RequirementID:AR.SR.IREQ02758058.001.001 + *- @RequirementName: java.security.Provider.getService() is synchronized and became scalability bottleneck +- *- @Condition:JDK8u302及以后 +- *- @Brief:测试相应provider更改底层架构以后所提供的service是否与原先有差异(以openJDK8u302为准) +- * -#step:比较openJDK8u302 SunProvider与此特性修改后的SunProvider所提供的service是否一致 +- *- @Expect:正常运行 ++ *- @Condition:JDK8u302 and later ++ *- @Brief:Check whether the service provided by the corresponding provider after changing the underlying architecture is different from the original one (subject to openJDK8u302). ++ * -#step:Compare whether the service provided by openJDK8u302 SunProvider is consistent with the modified SunProvider with this feature. ++ *- @Expect:Normal Running. + *- @Priority:Level 1 + */ + diff --git a/Add-compiling-option-GS-when-building-windows-JDK.patch b/Add-compiling-option-GS-when-building-windows-JDK.patch new file mode 100644 index 0000000000000000000000000000000000000000..04480d79789ed773053ccc52b1ec9ddeb105e2d3 --- /dev/null +++ b/Add-compiling-option-GS-when-building-windows-JDK.patch @@ -0,0 +1,38 @@ +From 73ef8a1178d64c213de7f02c007fa35db391dac3 Mon Sep 17 00:00:00 2001 +From: zhangyipeng +Date: Sun, 12 Nov 2023 13:04:57 +0000 +Subject: [PATCH] [Huawei]Add compiling option /GS when building windows JDK +--- + common/autoconf/flags.m4 | 2 +- + common/autoconf/generated-configure.sh | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 +index 71703a155..6474a0a47 100644 +--- a/common/autoconf/flags.m4 ++++ b/common/autoconf/flags.m4 +@@ -566,7 +566,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], + CXXFLAGS_JDK="$CXXFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + CCXXFLAGS_JDK="$CCXXFLAGS $CCXXFLAGS_JDK \ +- -Zi -MD -Zc:wchar_t- -W3 -wd4800 \ ++ -GS -Zi -MD -Zc:wchar_t- -W3 -wd4800 \ + -DWIN32_LEAN_AND_MEAN \ + -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE \ + -DWIN32 -DIAL" +diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh +index 8fa28b61f..b296f81c2 100644 +--- a/common/autoconf/generated-configure.sh ++++ b/common/autoconf/generated-configure.sh +@@ -43598,7 +43598,7 @@ $as_echo "$supports" >&6; } + CXXFLAGS_JDK="$CXXFLAGS_JDK -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC" + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + CCXXFLAGS_JDK="$CCXXFLAGS $CCXXFLAGS_JDK \ +- -Zi -MD -Zc:wchar_t- -W3 -wd4800 \ ++ -GS -Zi -MD -Zc:wchar_t- -W3 -wd4800 \ + -DWIN32_LEAN_AND_MEAN \ + -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE \ + -DWIN32 -DIAL" +-- +2.12.3 + diff --git a/Fix-for-JDK-8137099-for-G1-is-to-not-return-null-unt.patch b/Fix-for-JDK-8137099-for-G1-is-to-not-return-null-unt.patch new file mode 100644 index 0000000000000000000000000000000000000000..eedab379f9f5147b65790936e8c09fbfa718231c --- /dev/null +++ b/Fix-for-JDK-8137099-for-G1-is-to-not-return-null-unt.patch @@ -0,0 +1,30 @@ +From ee7c3b3d5baee0a4d2de273c753e0b6b4a8b9b42 Mon Sep 17 00:00:00 2001 +From: zhangyipeng +Date: Fri, 12 Jan 2024 10:53:02 +0800 +Subject: [PATCH] [Huawei]Fix for JDK-8137099 for G1 is to not return null until full + GC has happened +--- + hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +index 1ce641cae..84d5d4d8b 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +@@ -876,9 +876,10 @@ G1CollectedHeap::mem_allocate(size_t word_size, + } + return result; + } else { +- if (gclocker_retry_count > GCLockerRetryAllocationCount) { +- return NULL; +- } ++ // Fix for JDK-8137099 for G1 is to not return null until full GC has happened ++ // if (gclocker_retry_count > GCLockerRetryAllocationCount) { ++ // return NULL; ++ // } + assert(op.result() == NULL, + "the result should be NULL if the VM op did not succeed"); + } +-- +2.12.3 + diff --git a/Improve_AlgorithmConstraints_checkAlgorithm_performance.patch b/Improve_AlgorithmConstraints_checkAlgorithm_performance.patch index cf5c5e4aec61758983d6babbaea063ed07d2f9ae..aa252e4726c72c0d352f4c5ff2b59077619228db 100644 --- a/Improve_AlgorithmConstraints_checkAlgorithm_performance.patch +++ b/Improve_AlgorithmConstraints_checkAlgorithm_performance.patch @@ -64,15 +64,15 @@ diff --git a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraint index 51e62563..6ff26bf2 100644 --- a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +++ b/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java -@@ -96,7 +96,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { +@@ -99,7 +99,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { new DisabledAlgorithmConstraints(PROPERTY_JAR_DISABLED_ALGS); } - private final List disabledAlgorithms; + private final Set disabledAlgorithms; private final Constraints algorithmConstraints; - - public static DisabledAlgorithmConstraints certPathConstraints() { + private volatile SoftReference> cacheRef = + new SoftReference<>(null); @@ -128,11 +128,11 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { public DisabledAlgorithmConstraints(String propertyName, AlgorithmDecomposer decomposer) { diff --git a/add-missing-test-case.patch b/add-missing-test-case.patch index 312f3bb488f64b7eeadc74e6c8edd0beea0fc269..1cdbfb9f33a1775e29ecf4a5b93848b7f68468b5 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.392.8.0.13 ++8.402.8.0.13 -- 2.23.0 diff --git a/fix_X509TrustManagerImpl_symantec_distrust.patch b/fix_X509TrustManagerImpl_symantec_distrust.patch index 1365d836e2bbee6e1a5340869a2908dd606bf91c..83426e6ae5e3a329c39b1e5ad9760d05bcb97ff2 100644 --- a/fix_X509TrustManagerImpl_symantec_distrust.patch +++ b/fix_X509TrustManagerImpl_symantec_distrust.patch @@ -40,13 +40,13 @@ index 54e1bfa0d..c1423dc5b 100644 // The numbers of certs now. - private static final int COUNT = 83; -+ private static final int COUNT = 91; ++ private static final int COUNT = 100; // 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"; -+ = "C2:9A:86:5C:47:0F:15:58:FB:D8:31:B5:29:BB:BE:A1:09:6F:9B:60:10:AF:8E:77:4A:AE:B7:66:BB:B1:58:34"; ++ = "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"; // map of cert alias to SHA-256 fingerprint @SuppressWarnings("serial") private static final Map FINGERPRINT_MAP diff --git a/g1gc-numa-aware-Implementation.patch b/g1gc-numa-aware-Implementation.patch index 56dfe67c8974cf0cce0b847fb4a05167f78da6fa..0240697c17656cf956e7812ae01738480f9594f2 100755 --- a/g1gc-numa-aware-Implementation.patch +++ b/g1gc-numa-aware-Implementation.patch @@ -3549,10 +3549,10 @@ index 000000000..c5322849e + } + } +} -diff --git a/jdk/test/lib/sun/hotspot/WhiteBox.java b/jdk/test/lib/sun/hotspot/WhiteBox.java +diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 9497c9530..a6d773bc8 100644 ---- a/jdk/test/lib/sun/hotspot/WhiteBox.java -+++ b/jdk/test/lib/sun/hotspot/WhiteBox.java +--- a/test/lib/sun/hotspot/WhiteBox.java ++++ b/test/lib/sun/hotspot/WhiteBox.java @@ -141,6 +141,8 @@ public class WhiteBox { public native int g1RegionSize(); public native MemoryUsage g1AuxiliaryMemoryUsage(); diff --git a/jdk8u-jdk8u392-b08.tar.xz b/jdk8u-jdk8u402-b06.tar.xz similarity index 82% rename from jdk8u-jdk8u392-b08.tar.xz rename to jdk8u-jdk8u402-b06.tar.xz index e026d3b0934c8a2353ecb81a39316f1f9aa7985d..f7e09c919061fab0a2f8a0a4b2092fda656b8fa5 100644 Binary files a/jdk8u-jdk8u392-b08.tar.xz and b/jdk8u-jdk8u402-b06.tar.xz differ diff --git a/openjdk-1.8.0.spec b/openjdk-1.8.0.spec index 415c611613744c42a61bf7e35cc5781ced33b559..c76b57c2c2dff9a6fb1a622963336933a2998380 100644 --- a/openjdk-1.8.0.spec +++ b/openjdk-1.8.0.spec @@ -155,13 +155,13 @@ %global origin_nice OpenJDK %global top_level_dir_name %{origin} %global repo jdk8u -%global revision jdk8u392-b08 +%global revision jdk8u402-b06 %global full_revision %{repo}-%{revision} # Define IcedTea version used for SystemTap tapsets and desktop files %global icedteaver 3.15.0 -%global updatever 392 -%global buildver b08 +%global updatever 402 +%global buildver b06 # priority must be 7 digits in total. The expression is workarounding tip %global priority 1800%{updatever} @@ -925,7 +925,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 4 +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 @@ -1289,6 +1289,14 @@ Patch407: 8278794-Infinite-loop-in-DeflaterOutputStream.finish.patch Patch408: 8312065-Socket.connect-does-not-timeout-when-profili.patch Patch409: Add-Problemlist.patch Patch410: Fix-an-error-caused-by-anonymous-when-AppCDS-generat.patch +Patch411: Add-CaptchaTest-and-fix-KAE-Testcases.patch +Patch412: 8177146-MethodHandles.Lookup-bind-allows-illegal-pro.patch +Patch413: Add-compiling-option-GS-when-building-windows-JDK.patch +Patch414: Fix-for-JDK-8137099-for-G1-is-to-not-return-null-unt.patch +Patch415: 8273553-sun.security.ssl.SSLEngineImpl.closeInbound-.patch +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 ############################################# # @@ -1904,6 +1912,14 @@ pushd %{top_level_dir_name} %patch408 -p1 %patch409 -p1 %patch410 -p1 +%patch411 -p1 +%patch412 -p1 +%patch413 -p1 +%patch414 -p1 +%patch415 -p1 +%patch416 -p1 +%patch417 -p1 +%patch418 -p1 %ifarch riscv64 %patch2000 -p1 @@ -2555,6 +2571,23 @@ cjc.mainProgram(arg) %endif %changelog +* Wed Jan 17 2024 Autistic_boyya - 1:1.8.0.402-b06.0 +- modified 0019-8040213-C2-does-not-put-all-modified-nodes-on-IGVN-w.patch +- modified Improve_AlgorithmConstraints_checkAlgorithm_performance.patch +- modified add-missing-test-case.patch +- modified fix_X509TrustManagerImpl_symantec_distrust.patch +- modified g1gc-numa-aware-Implementation.patch +- modified update-cacerts-and-VerifyCACerts.java-test.patch +- modified 8203699.patch +- add Add-CaptchaTest-and-fix-KAE-Testcases.patch +- add 8177146-MethodHandles.Lookup-bind-allows-illegal-pro.patch +- add Add-compiling-option-GS-when-building-windows-JDK.patch +- add Fix-for-JDK-8137099-for-G1-is-to-not-return-null-unt.patch +- add 8273553-sun.security.ssl.SSLEngineImpl.closeInbound-.patch +- add 8260923-Add-more-tests-for-SSLSocket-input-output-sh.patch +- add 8057967-CallSite-dependency-tracking-scales-devastat.patch +- add 8079205-CallSite-dependency-tracking-is-broken-after.patch + * Wed Dec 20 2023 kuenking111 - 1:1.8.0.392-b08.4 - Add Fix-an-error-caused-by-anonymous-when-AppCDS-generat.patch diff --git a/update-cacerts-and-VerifyCACerts.java-test.patch b/update-cacerts-and-VerifyCACerts.java-test.patch index dc4681f3d1e961831d4358d4a3e3a4d6b3370108..22fc8c65fd42e99ff7b432222aea0a87311afdb2 100644 --- a/update-cacerts-and-VerifyCACerts.java-test.patch +++ b/update-cacerts-and-VerifyCACerts.java-test.patch @@ -257,13 +257,13 @@ index dd107fc..791ddb6 100644 + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. -- private static final int COUNT = 97; +- private static final int COUNT = 106; + 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 -- = "88:72:92:56:FF:E5:A3:E4:39:98:6D:18:0B:BA:CC:0B:66:CB:1D:6D:52:CE:D7:C8:AD:63:B7:F1:5F:02:24:52"; +- = "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"; + = "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") @@ -290,10 +290,10 @@ index dd107fc..791ddb6 100644 put("geotrustprimaryca [jdk]", "37:D5:10:06:C5:12:EA:AB:62:64:21:F1:EC:8C:92:01:3F:C5:F8:2A:E9:8E:E5:33:EB:46:19:B8:DE:B4:D0:6C"); put("geotrustprimarycag2 [jdk]", -@@ -163,10 +147,6 @@ public class VerifyCACerts { - "5D:56:49:9B:E4:D2:E0:8B:CF:CA:D0:8A:3E:38:72:3D:50:50:3B:DE:70:69:48:E4:2F:55:60:30:19:E5:28:AE"); - put("letsencryptisrgx1 [jdk]", +@@ -165,10 +149,6 @@ public class VerifyCACerts { "96:BC:EC:06:26:49:76:F3:74:60:77:9A:CF:28:C5:A7:CF:E8:A3:C0:AA:E1:1A:8F:FC:EE:05:C0:BD:DF:08:C6"); + put("letsencryptisrgx2 [jdk]", + "69:72:9B:8E:15:A8:6E:FC:17:7A:57:AF:B7:17:1D:FC:64:AD:D2:8C:2F:CA:8C:F1:50:7E:34:45:3C:CB:14:70"); - put("luxtrustglobalrootca [jdk]", - "A1:B2:DB:EB:64:E7:06:C6:16:9E:3C:41:18:B2:3B:AA:09:01:8A:84:27:66:6D:8B:F0:E2:88:91:EC:05:19:50"); - put("quovadisrootca [jdk]",