Skip to content

Commit 2a3d908

Browse files
committed
8269661: JNI_GetStringCritical does not lock char array
8269650: Optimize gc-locker in [Get|Release]StringCritical for latin string Reviewed-by: shade Backport-of: 0f4e07b
1 parent 6762216 commit 2a3d908

File tree

1 file changed

+51
-17
lines changed

1 file changed

+51
-17
lines changed

src/hotspot/share/prims/jni.cpp

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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
*
@@ -37,6 +37,7 @@
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
32123213
HOTSPOT_JNI_RELEASEPRIMITIVEARRAYCRITICAL_RETURN();
32133214
JNI_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

32163245
JNI_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);
32573291
HOTSPOT_JNI_RELEASESTRINGCRITICAL_RETURN();
32583292
JNI_END
32593293

0 commit comments

Comments
 (0)