Skip to content

Commit 9a191f0

Browse files
committed
pulled string truncation into general util class and added more testing
1 parent 23cd908 commit 9a191f0

File tree

4 files changed

+155
-31
lines changed

4 files changed

+155
-31
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2025, 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. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package jdk.graal.compiler.core.common.test;
26+
27+
import jdk.graal.compiler.core.common.util.Util;
28+
import org.junit.Assert;
29+
import org.junit.Test;
30+
31+
/**
32+
* Tests for {@link jdk.graal.compiler.core.common.util.Util}.
33+
*/
34+
public class UtilTest {
35+
36+
@Test
37+
public void truncateStringTest1() {
38+
for (int max = 1; max < 1024; max++) {
39+
40+
String[] inputs = {
41+
"X".repeat(max - 1),
42+
"X".repeat(max),
43+
"X".repeat(max + 1),
44+
};
45+
for (String s : inputs) {
46+
if (max <= Util.TRUNCATION_PLACEHOLDER.length()) {
47+
try {
48+
Util.truncateString(s, max);
49+
throw new AssertionError("expected " + IllegalArgumentException.class.getName());
50+
} catch (IllegalArgumentException e) {
51+
// expected
52+
}
53+
} else {
54+
String cs = Util.truncateString(s, max);
55+
if (s.length() <= max) {
56+
Assert.assertEquals(s, cs);
57+
} else {
58+
Assert.assertNotEquals(s, cs);
59+
Assert.assertTrue(cs, cs.contains("<truncated"));
60+
}
61+
}
62+
}
63+
}
64+
}
65+
66+
@Test
67+
public void truncateStringTest2() {
68+
int max = 40;
69+
70+
// Tests example from javadoc
71+
String s = "123456789_123456789_123456789_123456789_123456789_";
72+
String cs = Util.truncateString(s, max);
73+
Assert.assertEquals(50, s.length());
74+
Assert.assertEquals(32, cs.length());
75+
Assert.assertEquals("123<truncated(43, c285d1fd)>789_", cs);
76+
}
77+
}

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/TruffleInstalledCodeTest.java

+27-8
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,44 @@
3131
import jdk.graal.compiler.truffle.TruffleCompilerImpl;
3232
import jdk.vm.ci.code.InstalledCode;
3333

34+
import java.util.Objects;
35+
3436
public class TruffleInstalledCodeTest extends PartialEvaluationTest {
3537

38+
/**
39+
* Creates a string of length {@code len} whose prefix is repeated 'X's and whose suffix is
40+
* {@code suffix}.
41+
*/
42+
private static String makeLongName(int len, String suffix) {
43+
return "X".repeat(len - suffix.length()) + suffix;
44+
}
45+
3646
/**
3747
* Tests that {@link TruffleCompilerImpl#asInstalledCodeName(String)} returns a valid name for
3848
* {@link InstalledCode#InstalledCode(String)}.
3949
*/
4050
@Test
4151
public void testLongName() {
42-
String prefix = "test__";
43-
String middle = new String(new char[Character.MAX_VALUE]).replace('\0', 'X');
4452
String[] suffixes = {TruffleCompiler.FIRST_TIER_COMPILATION_SUFFIX, TruffleCompiler.SECOND_TIER_COMPILATION_SUFFIX};
4553
for (String suffix : suffixes) {
46-
String name = prefix + middle + suffix;
47-
String installedCodeName = TruffleCompilerImpl.asInstalledCodeName(name);
48-
Assert.assertTrue(installedCodeName, installedCodeName.length() <= name.length());
49-
Assert.assertTrue(installedCodeName, installedCodeName.endsWith(suffix));
54+
String[] names = {
55+
makeLongName(TruffleCompilerImpl.MAX_NAME_LENGTH - 1, suffix),
56+
makeLongName(TruffleCompilerImpl.MAX_NAME_LENGTH, suffix),
57+
makeLongName(TruffleCompilerImpl.MAX_NAME_LENGTH + 1, suffix)
58+
};
59+
for (String name : names) {
60+
String installedCodeName = TruffleCompilerImpl.asInstalledCodeName(name);
61+
Assert.assertTrue(installedCodeName, installedCodeName.endsWith(suffix));
62+
if (name.length() <= TruffleCompilerImpl.MAX_NAME_LENGTH) {
63+
Assert.assertEquals("unexpected truncation", installedCodeName, name);
64+
} else {
65+
Assert.assertNotEquals("unexpected truncation", installedCodeName, name);
66+
}
5067

51-
// Must not throw an exception
52-
new InstalledCode(installedCodeName);
68+
// Must not throw an exception
69+
InstalledCode obj = new InstalledCode(installedCodeName);
70+
Objects.requireNonNull(obj);
71+
}
5372
}
5473
}
5574
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/util/Util.java

+46-4
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public static <T> void atPutGrow(List<T> list, int pos, T x, T filler) {
7272
* possibly non-empty line following the final newline.
7373
*/
7474
public static String indent(String lines, String indentation) {
75-
if (lines.length() == 0) {
75+
if (lines.isEmpty()) {
7676
return lines;
7777
}
7878
final String newLine = "\n";
@@ -95,9 +95,7 @@ public static void printInlining(final ResolvedJavaMethod method, final int bci,
9595
sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' '));
9696
sb.append(" "); // more indent
9797
sb.append(" "); // initial inlining indent
98-
for (int i = 0; i < inliningDepth; i++) {
99-
sb.append(" ");
100-
}
98+
sb.append(" ".repeat(Math.max(0, inliningDepth)));
10199
sb.append(String.format("@ %d %s %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args)));
102100
TTY.println(sb.toString());
103101
}
@@ -116,4 +114,48 @@ public static String toString(StackTraceElement[] ste) {
116114
}
117115
return sb.toString();
118116
}
117+
118+
/**
119+
* Transforms {@code s} to be no longer than {code max} via truncation. The truncation replaces
120+
* the middle section of {@code s} with {@code "<truncated(" + L + ", " + H + ")>"} where
121+
* {@code L} is the length of the cut-out part of {@code s} and H is its hash code in lowercase
122+
* hex. Note that if truncation is performed, the returned value may be shorter than
123+
* {@code max}. For example:
124+
*
125+
* <pre>
126+
* var s = "123456789_123456789_123456789_123456789_123456789_";
127+
* var cs = truncateString(s, 40);
128+
* assert s.length() == 50;
129+
* assert cs.length() == 32;
130+
* assert cs.equals("123<truncated(43, c285d1fd)>789_");
131+
* </pre>
132+
*
133+
* @param max must be greater than the length of {@link #TRUNCATION_PLACEHOLDER}
134+
* @throws IllegalArgumentException if {@code max <= TRUNCATION_PLACEHOLDER.length()}
135+
*/
136+
public static String truncateString(String s, int max) {
137+
if (max <= TRUNCATION_PLACEHOLDER.length()) {
138+
throw new IllegalArgumentException(max + " <= " + TRUNCATION_PLACEHOLDER.length());
139+
}
140+
if (s.length() > max) {
141+
int preservedLen = max - TRUNCATION_PLACEHOLDER.length();
142+
int prefixEnd = preservedLen / 2;
143+
int suffixStart = (s.length() - preservedLen / 2) - 1;
144+
String prefix = s.substring(0, prefixEnd);
145+
String middle = s.substring(prefixEnd, suffixStart);
146+
middle = TRUNCATION_FORMAT.formatted(middle.length(), middle.hashCode());
147+
String suffix = s.substring(suffixStart);
148+
return "%s%s%s".formatted(prefix, middle, suffix);
149+
}
150+
return s;
151+
}
152+
153+
private static final String TRUNCATION_FORMAT = "<truncated(%d, %x)>";
154+
155+
/**
156+
* The placeholder for the value embedded in the value returned by
157+
* {@link #truncateString(String, int)} if truncation is performed describing the truncation
158+
* performed.
159+
*/
160+
public static final String TRUNCATION_PLACEHOLDER = TRUNCATION_FORMAT.formatted(Integer.MAX_VALUE, String.valueOf(Integer.MAX_VALUE).hashCode());
119161
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java

+5-19
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
import java.util.concurrent.ThreadFactory;
4343
import java.util.function.Consumer;
4444

45-
import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
45+
import jdk.graal.compiler.core.common.util.Util;
4646
import org.graalvm.collections.EconomicMap;
4747
import org.graalvm.collections.UnmodifiableEconomicMap;
4848

@@ -554,7 +554,7 @@ private void compileAST(TruffleCompilationWrapper wrapper, DebugContext debug) {
554554
* Copy of {@code InstalledCode.MAX_NAME_LENGTH} initialized by reflection that can be removed
555555
* once JDK 21 support is removed.
556556
*/
557-
private static final int MAX_NAME_LENGTH;
557+
public static final int MAX_NAME_LENGTH;
558558
static {
559559
int len = 2048;
560560
try {
@@ -567,25 +567,11 @@ private void compileAST(TruffleCompilationWrapper wrapper, DebugContext debug) {
567567

568568
/**
569569
* Transforms {@code name} to be usable as an {@linkplain InstalledCode#getName() installed code
570-
* name}. The value is truncated if too long. The truncation replaces the middle section of the
571-
* string with {@code "<truncated(" + L + ", " + H + ")>"} where {@code L} is the length of the
572-
* cut-out part of the string and H is its hash code in lowercase hex.
570+
* name}. The value is {@linkplain Util#truncateString(String, int) truncated} if its length is
571+
* greater than {@link #MAX_NAME_LENGTH}.
573572
*/
574573
public static String asInstalledCodeName(String name) {
575-
String truncationFormat = "<truncated(%d, %x)>";
576-
int truncationReserved = (truncationFormat.formatted(Integer.MAX_VALUE, String.valueOf(Integer.MAX_VALUE).hashCode())).length();
577-
if (name.length() > MAX_NAME_LENGTH) {
578-
int len = MAX_NAME_LENGTH - truncationReserved;
579-
int prefixEnd = len / 2;
580-
int suffixStart = (name.length() - len / 2) - 1;
581-
String prefix = name.substring(0, prefixEnd);
582-
String middle = name.substring(prefixEnd, suffixStart);
583-
middle = truncationFormat.formatted(middle.length(), middle.hashCode());
584-
GraalError.guarantee(truncationReserved >= middle.length(), "%d < %d", truncationReserved, middle.length());
585-
String suffix = name.substring(suffixStart);
586-
return "%s%s%s".formatted(prefix, middle, suffix);
587-
}
588-
return name;
574+
return Util.truncateString(name, MAX_NAME_LENGTH);
589575
}
590576

591577
@SuppressWarnings("try")

0 commit comments

Comments
 (0)