< prev index next >
src/share/vm/prims/jni.cpp
Print this page
@@ -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 */
- GC_locker::lock_critical(thread);
- if (isCopy != NULL) {
- *isCopy = JNI_FALSE;
+ 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);
+ if (s_len > 0) {
+ ret = s_value->char_at_addr(s_offset);
+ } else {
+ ret = (jchar*) s_value->base(T_CHAR);
+ }
}
- 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 */
- // The str and chars arguments are ignored
- GC_locker::unlock_critical(thread);
+ 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(
);
< prev index next >