Skip to content

Commit d776de4

Browse files
author
duke
committedJul 19, 2024
Automatic merge of jdk:master into master
2 parents 3df8b99 + 10fcad7 commit d776de4

File tree

6 files changed

+166
-3
lines changed

6 files changed

+166
-3
lines changed
 

‎src/hotspot/share/classfile/javaClasses.cpp

+22-1
Original file line numberDiff line numberDiff line change
@@ -751,8 +751,16 @@ bool java_lang_String::equals(oop str1, oop str2) {
751751
return value_equals(value1, value2);
752752
}
753753

754-
void java_lang_String::print(oop java_string, outputStream* st) {
754+
// Print the given string to the given outputStream, limiting the output to
755+
// at most max_length of the string's characters. If the length exceeds the
756+
// limit we print an abridged version of the string with the "middle" elided
757+
// and replaced by " ... (N characters ommitted) ... ". If max_length is odd
758+
// it is treated as max_length-1.
759+
void java_lang_String::print(oop java_string, outputStream* st, int max_length) {
755760
assert(java_string->klass() == vmClasses::String_klass(), "must be java_string");
761+
// We need at least two characters to print A ... B
762+
assert(max_length > 1, "invalid max_length: %d", max_length);
763+
756764
typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
757765

758766
if (value == nullptr) {
@@ -765,8 +773,17 @@ void java_lang_String::print(oop java_string, outputStream* st) {
765773
int length = java_lang_String::length(java_string, value);
766774
bool is_latin1 = java_lang_String::is_latin1(java_string);
767775

776+
bool abridge = length > max_length;
777+
768778
st->print("\"");
769779
for (int index = 0; index < length; index++) {
780+
// If we need to abridge and we've printed half the allowed characters
781+
// then jump to the tail of the string.
782+
if (abridge && index >= max_length / 2) {
783+
st->print(" ... (%d characters ommitted) ... ", length - 2 * (max_length / 2));
784+
index = length - (max_length / 2);
785+
abridge = false; // only do this once
786+
}
770787
jchar c = (!is_latin1) ? value->char_at(index) :
771788
((jchar) value->byte_at(index)) & 0xff;
772789
if (c < ' ') {
@@ -776,6 +793,10 @@ void java_lang_String::print(oop java_string, outputStream* st) {
776793
}
777794
}
778795
st->print("\"");
796+
797+
if (length > max_length) {
798+
st->print(" (abridged) ");
799+
}
779800
}
780801

781802
// java_lang_Class

‎src/hotspot/share/classfile/javaClasses.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ class java_lang_String : AllStatic {
194194
static inline bool is_instance(oop obj);
195195

196196
// Debugging
197-
static void print(oop java_string, outputStream* st);
197+
static void print(oop java_string, outputStream* st, int max_length = MaxStringPrintSize);
198198
friend class JavaClasses;
199199
friend class StringTable;
200200
};

‎src/hotspot/share/prims/whitebox.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,14 @@ WB_ENTRY(jlong, WB_GetVMLargePageSize(JNIEnv* env, jobject o))
179179
return os::large_page_size();
180180
WB_END
181181

182+
WB_ENTRY(jstring, WB_PrintString(JNIEnv* env, jobject wb, jstring str, jint max_length))
183+
ResourceMark rm(THREAD);
184+
stringStream sb;
185+
java_lang_String::print(JNIHandles::resolve(str), &sb, max_length);
186+
oop result = java_lang_String::create_oop_from_str(sb.as_string(), THREAD);
187+
return (jstring) JNIHandles::make_local(THREAD, result);
188+
WB_END
189+
182190
class WBIsKlassAliveClosure : public LockedClassesDo {
183191
Symbol* _name;
184192
int _count;
@@ -2961,6 +2969,7 @@ static JNINativeMethod methods[] = {
29612969
{CC"preTouchMemory", CC"(JJ)V", (void*)&WB_PreTouchMemory},
29622970
{CC"cleanMetaspaces", CC"()V", (void*)&WB_CleanMetaspaces},
29632971
{CC"rss", CC"()J", (void*)&WB_Rss},
2972+
{CC"printString", CC"(Ljava/lang/String;I)Ljava/lang/String;", (void*)&WB_PrintString},
29642973
};
29652974

29662975

‎src/hotspot/share/runtime/globals.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,12 @@ const int ObjectAlignmentInBytes = 8;
13041304
develop(int, MaxElementPrintSize, 256, \
13051305
"maximum number of elements to print") \
13061306
\
1307+
develop(int, MaxStringPrintSize, 256, \
1308+
"maximum number of characters to print for a java.lang.String " \
1309+
"in the VM. If exceeded, an abridged version of the string is " \
1310+
"printed with the middle of the string elided.") \
1311+
range(2, O_BUFLEN) \
1312+
\
13071313
develop(intx, MaxSubklassPrintSize, 4, \
13081314
"maximum number of subklasses to print when printing klass") \
13091315
\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/**
25+
* @test
26+
* @bug 8325945
27+
* @summary Test abridged VM String printing
28+
* @library /test/lib
29+
* @build jdk.test.whitebox.WhiteBox
30+
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
31+
* @run main/othervm -Xbootclasspath/a:. -XX:+WhiteBoxAPI StringPrinting
32+
*/
33+
34+
import jdk.test.whitebox.WhiteBox;
35+
36+
public class StringPrinting {
37+
38+
private static final WhiteBox WB = WhiteBox.getWhiteBox();
39+
40+
static void checkEqual(String s1, String s2) {
41+
if (!s1.equals(s2)) {
42+
throw new RuntimeException("Different strings: " + s1 + " vs " + s2);
43+
}
44+
}
45+
46+
static void checkEqual(int len1, int len2) {
47+
if (len1 != len2) {
48+
throw new RuntimeException("Different lengths: " + len1 + " vs " + len2);
49+
}
50+
}
51+
52+
public static void main(String[] args) {
53+
// Modified string format is "xxx ... (N characters ommitted) ... xxx" (abridged)
54+
final String elipse = " ... ";
55+
final String text = " characters ommitted)";
56+
final String abridged = "\" (abridged) ";
57+
58+
// Define a set of maxLengths for ease of inspection in the test outout
59+
// Note: maxLength must be >= 2
60+
int[] maxLengths = new int[] { 2, 3, 16, 256, 512 };
61+
for (int maxLength : maxLengths) {
62+
// Test string lengths around maxLength and "much" bigger
63+
// than maxLength
64+
int[] strLengths = new int[] { maxLength - 1,
65+
maxLength,
66+
maxLength + 1,
67+
2 * maxLength
68+
};
69+
for (int length : strLengths) {
70+
System.out.println("Testing string length " + length + " with maxLength " + maxLength);
71+
String s = "x".repeat(length);
72+
String r = WB.printString(s, maxLength);
73+
if (length <= maxLength) {
74+
// Strip off the double-quotes that surround the string
75+
if (r.charAt(0) == '\"' && r.charAt(r.length() - 1) == '\"') {
76+
r = r.substring(1, r.length() - 1);
77+
} else {
78+
throw new RuntimeException("String was not quoted as expected: " + r);
79+
}
80+
checkEqual(s, r);
81+
} else {
82+
// Strip off leading double-quote
83+
if (r.charAt(0) == '\"') {
84+
r = r.substring(1, r.length());
85+
} else {
86+
throw new RuntimeException("String was not quoted as expected: " + r);
87+
}
88+
89+
// Strip off abridged
90+
if (r.endsWith(abridged)) {
91+
r = r.substring(0, r.length() - abridged.length());
92+
} else {
93+
throw new RuntimeException("String was not marked abridged as expected: " + r);
94+
}
95+
96+
// Now extract the two "halves"
97+
int elipseStart = r.indexOf(elipse);
98+
String firstHalf = r.substring(0, elipseStart);
99+
int secondElipseStart = r.lastIndexOf(elipse);
100+
String secondHalf = r.substring(secondElipseStart + elipse.length(), r.length());
101+
102+
System.out.println("S1: >" + firstHalf + "<");
103+
System.out.println("S2: >" + secondHalf + "<");
104+
105+
checkEqual(firstHalf.length(), maxLength / 2);
106+
checkEqual(secondHalf.length(), maxLength /2);
107+
108+
// Now check number of characters ommitted
109+
String tail = r.substring(r.indexOf("("), r.length());
110+
int numberEnd = tail.indexOf(" ");
111+
String nChars = tail.substring(1, numberEnd);
112+
System.out.println("N: >" + nChars + "<");
113+
114+
// Now add all the bits back together to get the expected full length
115+
int fullLength = maxLength / 2 + elipse.length() + 1 /* for ( */
116+
+ nChars.length() + text.length() + elipse.length() + maxLength / 2;
117+
checkEqual(r.length(), fullLength);
118+
}
119+
}
120+
}
121+
}
122+
}

‎test/lib/jdk/test/whitebox/WhiteBox.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,13 @@ public long getObjectSize(Object o) {
9999
}
100100

101101
// Runtime
102-
// Make sure class name is in the correct format
102+
103+
// Returns the potentially abridged form of `str` as it would be
104+
// printed by the VM.
105+
public native String printString(String str, int maxLength);
106+
103107
public int countAliveClasses(String name) {
108+
// Make sure class name is in the correct format
104109
return countAliveClasses0(name.replace('.', '/'));
105110
}
106111
private native int countAliveClasses0(String name);

0 commit comments

Comments
 (0)
Please sign in to comment.