diff -r 2bcd260edd04 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Mon Aug 23 14:33:11 2021 +0100 +++ b/src/share/vm/prims/jni.cpp Thu Oct 07 11:36:50 2021 +0200 @@ -36,10 +36,11 @@ #include "jfr/support/jfrThreadId.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#include "gc_implementation/shenandoah/shenandoahStringDedup.hpp" #endif // INCLUDE_ALL_GCS #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/gcLocker.inline.hpp" #include "memory/oopFactory.hpp" @@ -2628,11 +2629,11 @@ jobject ret = JNIHandles::make_local(env, o->obj_field(offset)); #if INCLUDE_ALL_GCS // If G1 is enabled and we are accessing the value of the referent // field in a reference object then we need to register a non-null // referent with the SATB barrier. - if (UseG1GC) { + if (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) { bool needs_barrier = false; if (ret != NULL && offset == java_lang_ref_Reference::referent_offset && InstanceKlass::cast(k)->reference_type() != REF_NONE) { @@ -4249,24 +4250,41 @@ } } } JNI_END +static oop lock_gc_or_pin_object(JavaThread* thread, jobject obj) { + if (Universe::heap()->supports_object_pinning()) { + const oop o = JNIHandles::resolve_non_null(obj); + return Universe::heap()->pin_object(thread, o); + } else { + GC_locker::lock_critical(thread); + return JNIHandles::resolve_non_null(obj); + } +} + +static void unlock_gc_or_unpin_object(JavaThread* thread, jobject obj) { + if (Universe::heap()->supports_object_pinning()) { + const oop o = JNIHandles::resolve_non_null(obj); + return Universe::heap()->unpin_object(thread, o); + } else { + GC_locker::unlock_critical(thread); + } +} JNI_ENTRY(void*, jni_GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy)) JNIWrapper("GetPrimitiveArrayCritical"); #ifndef USDT2 DTRACE_PROBE3(hotspot_jni, GetPrimitiveArrayCritical__entry, env, array, isCopy); #else /* USDT2 */ HOTSPOT_JNI_GETPRIMITIVEARRAYCRITICAL_ENTRY( env, array, (uintptr_t *) isCopy); #endif /* USDT2 */ - GC_locker::lock_critical(thread); if (isCopy != NULL) { *isCopy = JNI_FALSE; } - oop a = JNIHandles::resolve_non_null(array); + oop a = lock_gc_or_pin_object(thread, array); assert(a->is_array(), "just checking"); BasicType type; if (a->is_objArray()) { type = T_OBJECT; } else { @@ -4290,11 +4308,11 @@ #else /* USDT2 */ HOTSPOT_JNI_RELEASEPRIMITIVEARRAYCRITICAL_ENTRY( env, array, carray, mode); #endif /* USDT2 */ // The array, carray and mode arguments are ignored - GC_locker::unlock_critical(thread); + unlock_gc_or_unpin_object(thread, array); #ifndef USDT2 DTRACE_PROBE(hotspot_jni, ReleasePrimitiveArrayCritical__return); #else /* USDT2 */ HOTSPOT_JNI_RELEASEPRIMITIVEARRAYCRITICAL_RETURN( ); @@ -4308,24 +4326,52 @@ DTRACE_PROBE3(hotspot_jni, GetStringCritical__entry, env, string, isCopy); #else /* USDT2 */ HOTSPOT_JNI_GETSTRINGCRITICAL_ENTRY( env, string, (uintptr_t *) isCopy); #endif /* USDT2 */ + jchar* ret; + if (!UseShenandoahGC) { GC_locker::lock_critical(thread); if (isCopy != NULL) { *isCopy = JNI_FALSE; } oop s = JNIHandles::resolve_non_null(string); int s_len = java_lang_String::length(s); typeArrayOop s_value = java_lang_String::value(s); int s_offset = java_lang_String::offset(s); - const jchar* ret; if (s_len > 0) { ret = s_value->char_at_addr(s_offset); } else { ret = (jchar*) s_value->base(T_CHAR); } + } +#if INCLUDE_ALL_GCS + else { + assert(UseShenandoahGC, "This path should only be taken with Shenandoah"); + oop s = JNIHandles::resolve_non_null(string); + if (ShenandoahStringDedup::is_enabled()) { + typeArrayOop s_value = java_lang_String::value(s); + int s_len = java_lang_String::length(s); + ret = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal); // add one for zero termination + /* JNI Specification states return NULL on OOM */ + if (ret != NULL) { + memcpy(ret, s_value->char_at_addr(0), s_len * sizeof(jchar)); + ret[s_len] = 0; + } + if (isCopy != NULL) *isCopy = JNI_TRUE; + } else { + typeArrayOop s_value = java_lang_String::value(s); + s_value = (typeArrayOop) Universe::heap()->pin_object(thread, s_value); + ret = (jchar *) s_value->base(T_CHAR); + if (isCopy != NULL) *isCopy = JNI_FALSE; + } + } +#else + else { + ShouldNotReachHere(); + } +#endif #ifndef USDT2 DTRACE_PROBE1(hotspot_jni, GetStringCritical__return, ret); #else /* USDT2 */ HOTSPOT_JNI_GETSTRINGCRITICAL_RETURN( (uint16_t *) ret); @@ -4340,12 +4386,32 @@ DTRACE_PROBE3(hotspot_jni, ReleaseStringCritical__entry, env, str, chars); #else /* USDT2 */ HOTSPOT_JNI_RELEASESTRINGCRITICAL_ENTRY( env, str, (uint16_t *) chars); #endif /* USDT2 */ + if (!UseShenandoahGC) { // The str and chars arguments are ignored GC_locker::unlock_critical(thread); + } +#if INCLUDE_ALL_GCS + else if (ShenandoahStringDedup::is_enabled()) { + assert(UseShenandoahGC, "This path should only be taken with Shenandoah"); + // For copied string value, free jchar array allocated by earlier call to GetStringCritical. + // This assumes that ReleaseStringCritical bookends GetStringCritical. + FREE_C_HEAP_ARRAY(jchar, chars, mtInternal); + } else { + assert(UseShenandoahGC, "This path should only be taken with Shenandoah"); + oop s = JNIHandles::resolve_non_null(str); + // For not copied string value, drop the associated gc-locker/pin. + typeArrayOop s_value = java_lang_String::value(s); + Universe::heap()->unpin_object(thread, s_value); + } +#else + else { + ShouldNotReachHere(); + } +#endif #ifndef USDT2 DTRACE_PROBE(hotspot_jni, ReleaseStringCritical__return); #else /* USDT2 */ HOTSPOT_JNI_RELEASESTRINGCRITICAL_RETURN( );