11/*
2- * Copyright (c) 1997, 2018 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 1997, 2021 , Oracle and/or its affiliates. All rights reserved.
33 * Copyright (c) 2012 Red Hat, Inc.
44 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55 *
3737#include " classfile/systemDictionary.hpp"
3838#include " classfile/vmSymbols.hpp"
3939#include " gc/shared/gcLocker.inline.hpp"
40+ #include " gc/shared/stringdedup/stringDedup.hpp"
4041#include " interpreter/linkResolver.hpp"
4142#include " jfr/jfrEvents.hpp"
4243#include " jfr/support/jfrThreadId.hpp"
@@ -3212,30 +3213,62 @@ JNI_ENTRY(void, jni_ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, voi
32123213HOTSPOT_JNI_RELEASEPRIMITIVEARRAYCRITICAL_RETURN ();
32133214JNI_END
32143215
3216+ // If a copy of string value should be returned instead
3217+ static bool should_copy_string_value (oop str) {
3218+ return java_lang_String::is_latin1 (str) ||
3219+ // To prevent deduplication from replacing the value array while setting up or in
3220+ // the critical section. That would lead to the release operation
3221+ // unpinning the wrong object.
3222+ (Universe::heap ()->supports_object_pinning () && StringDedup::is_enabled ());
3223+ }
3224+
3225+ static typeArrayOop lock_gc_or_pin_string_value (JavaThread* thread, oop str) {
3226+ if (Universe::heap ()->supports_object_pinning ()) {
3227+ typeArrayOop s_value = java_lang_String::value (str);
3228+ return (typeArrayOop) Universe::heap ()->pin_object (thread, s_value);
3229+ } else {
3230+ Handle h (thread, str); // Handlize across potential safepoint.
3231+ GCLocker::lock_critical (thread);
3232+ return java_lang_String::value (h ());
3233+ }
3234+ }
3235+
3236+ static void unlock_gc_or_unpin_string_value (JavaThread* thread, oop str) {
3237+ if (Universe::heap ()->supports_object_pinning ()) {
3238+ typeArrayOop s_value = java_lang_String::value (str);
3239+ Universe::heap ()->unpin_object (thread, s_value);
3240+ } else {
3241+ GCLocker::unlock_critical (thread);
3242+ }
3243+ }
32153244
32163245JNI_ENTRY (const jchar*, jni_GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy))
32173246 JNIWrapper(" GetStringCritical" );
32183247 HOTSPOT_JNI_GETSTRINGCRITICAL_ENTRY (env, string, (uintptr_t *) isCopy);
3219- oop s = lock_gc_or_pin_object(thread, string);
3220- typeArrayOop s_value = java_lang_String::value(s);
3221- bool is_latin1 = java_lang_String::is_latin1(s);
3222- if (isCopy != NULL ) {
3223- *isCopy = is_latin1 ? JNI_TRUE : JNI_FALSE;
3224- }
3248+ oop s = JNIHandles::resolve_non_null(string);
32253249 jchar* ret;
3226- if (!is_latin1) {
3227- ret = (jchar*) s_value->base (T_CHAR);
3228- } else {
3229- // Inflate latin1 encoded string to UTF16
3250+ if (should_copy_string_value(s)) {
3251+ typeArrayOop s_value = java_lang_String::value (s);
32303252 int s_len = java_lang_String::length (s);
32313253 ret = NEW_C_HEAP_ARRAY_RETURN_NULL (jchar, s_len + 1 , mtInternal); // add one for zero termination
32323254 /* JNI Specification states return NULL on OOM */
32333255 if (ret != NULL ) {
3234- for (int i = 0 ; i < s_len; i++) {
3235- ret[i] = ((jchar) s_value->byte_at (i)) & 0xff ;
3256+ bool is_latin1 = java_lang_String::is_latin1 (s);
3257+ // Inflate latin1 encoded string to UTF16
3258+ if (is_latin1) {
3259+ for (int i = 0 ; i < s_len; i++) {
3260+ ret[i] = ((jchar) s_value->byte_at (i)) & 0xff ;
3261+ }
3262+ } else {
3263+ memcpy (ret, s_value->char_at_addr (0 ), s_len * sizeof (jchar));
32363264 }
32373265 ret[s_len] = 0 ;
32383266 }
3267+ if (isCopy != NULL ) *isCopy = JNI_TRUE;
3268+ } else {
3269+ typeArrayOop s_value = lock_gc_or_pin_string_value (thread, s);
3270+ ret = (jchar*) s_value->base (T_CHAR);
3271+ if (isCopy != NULL ) *isCopy = JNI_FALSE;
32393272 }
32403273 HOTSPOT_JNI_GETSTRINGCRITICAL_RETURN ((uint16_t *) ret);
32413274 return ret;
@@ -3247,13 +3280,14 @@ JNI_ENTRY(void, jni_ReleaseStringCritical(JNIEnv *env, jstring str, const jchar
32473280 HOTSPOT_JNI_RELEASESTRINGCRITICAL_ENTRY (env, str, (uint16_t *) chars);
32483281 // The str and chars arguments are ignored for UTF16 strings
32493282 oop s = JNIHandles::resolve_non_null(str);
3250- bool is_latin1 = java_lang_String::is_latin1(s);
3251- if (is_latin1) {
3252- // For latin1 string, free jchar array allocated by earlier call to GetStringCritical.
3283+ if (should_copy_string_value(s)) {
3284+ // For copied string value, free jchar array allocated by earlier call to GetStringCritical.
32533285 // This assumes that ReleaseStringCritical bookends GetStringCritical.
32543286 FREE_C_HEAP_ARRAY (jchar, chars);
3287+ } else {
3288+ // For not copied string value, drop the associated gc-locker/pin.
3289+ unlock_gc_or_unpin_string_value (thread, s);
32553290 }
3256- unlock_gc_or_unpin_object (thread, str);
32573291HOTSPOT_JNI_RELEASESTRINGCRITICAL_RETURN ();
32583292JNI_END
32593293
0 commit comments