< prev index next >

src/share/vm/prims/jni.cpp

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2012 Red Hat, Inc.
  * 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

@@ -40,10 +40,11 @@
 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
 #endif // INCLUDE_ALL_GCS
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/gcLocker.inline.hpp"
+#include "gc_implementation/shenandoah/shenandoahStringDedup.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/universe.inline.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/instanceOop.hpp"
 #include "oops/markOop.hpp"

@@ -4316,31 +4317,62 @@
 HOTSPOT_JNI_RELEASEPRIMITIVEARRAYCRITICAL_RETURN(
 );
 #endif /* USDT2 */
 JNI_END
 
+// If a copy of string value should be returned instead
+static bool should_copy_string_value() {
+  // To prevent deduplication from replacing the value array while setting up or in
+  // the critical section. That would lead to the release operation
+  // unpinning the wrong object.
+  return Universe::heap()->supports_object_pinning() && ShenandoahStringDedup::is_enabled();
+}
+
+static typeArrayOop lock_gc_or_pin_string_value(JavaThread* thread, oop str) {
+  if (Universe::heap()->supports_object_pinning()) {
+    typeArrayOop s_value = java_lang_String::value(str);
+    return (typeArrayOop) Universe::heap()->pin_object(thread, s_value);
+  } else {
+    Handle h(thread, str);      // Handlize across potential safepoint.
+    GC_locker::lock_critical(thread);
+    return java_lang_String::value(h());
+  }
+}
+
+static void unlock_gc_or_unpin_string_value(JavaThread* thread, oop str) {
+  if (Universe::heap()->supports_object_pinning()) {
+    typeArrayOop s_value = java_lang_String::value(str);
+    Universe::heap()->unpin_object(thread, s_value);
+  } else {
+    GC_locker::unlock_critical(thread);
+  }
+}
 
 JNI_ENTRY(const jchar*, jni_GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy))
   JNIWrapper("GetStringCritical");
 #ifndef USDT2
   DTRACE_PROBE3(hotspot_jni, GetStringCritical__entry, env, string, isCopy);
 #else /* USDT2 */
   HOTSPOT_JNI_GETSTRINGCRITICAL_ENTRY(
                                       env, string, (uintptr_t *) isCopy);
 #endif /* USDT2 */
-  if (isCopy != NULL) {
-    *isCopy = JNI_FALSE;
-  }
-  oop s = lock_gc_or_pin_object(thread, 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);
+  oop s = JNIHandles::resolve_non_null(string);
+  jchar* ret;
+  if (should_copy_string_value()) {
+    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 = lock_gc_or_pin_string_value(thread, s);
     ret = (jchar*) s_value->base(T_CHAR);
+    if (isCopy != NULL) *isCopy = JNI_FALSE;
   }
 #ifndef USDT2
   DTRACE_PROBE1(hotspot_jni, GetStringCritical__return, ret);
 #else /* USDT2 */
  HOTSPOT_JNI_GETSTRINGCRITICAL_RETURN(

@@ -4356,12 +4388,19 @@
   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
-  unlock_gc_or_unpin_object(thread, str);
+  if (should_copy_string_value()) {
+    // 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 {
+    oop s = JNIHandles::resolve_non_null(str);
+    // For not copied string value, drop the associated gc-locker/pin.
+    unlock_gc_or_unpin_string_value(thread, s);
+  }
 #ifndef USDT2
   DTRACE_PROBE(hotspot_jni, ReleaseStringCritical__return);
 #else /* USDT2 */
 HOTSPOT_JNI_RELEASESTRINGCRITICAL_RETURN(
 );
< prev index next >