Skip to content

Commit 9825c33

Browse files
schlosnaMandy Chung
authored and
Mandy Chung
committed
8291641: Optimize StackTraceElement.toString()
Reviewed-by: rriggs, mchung
1 parent cb37282 commit 9825c33

File tree

3 files changed

+133
-16
lines changed

3 files changed

+133
-16
lines changed

src/java.base/share/classes/java/lang/StackTraceElement.java

+40-15
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import jdk.internal.module.ModuleHashes;
3131
import jdk.internal.module.ModuleReferenceImpl;
3232

33-
import java.lang.module.ModuleDescriptor.Version;
3433
import java.lang.module.ModuleReference;
3534
import java.lang.module.ResolvedModule;
3635
import java.util.HashSet;
@@ -52,6 +51,9 @@
5251
*/
5352
public final class StackTraceElement implements java.io.Serializable {
5453

54+
private static final String NATIVE_METHOD = "Native Method";
55+
private static final String UNKNOWN_SOURCE = "Unknown Source";
56+
5557
// For Throwables and StackWalker, the VM initially sets this field to a
5658
// reference to the declaring Class. The Class reference is used to
5759
// construct the 'format' bitmap, and then is cleared.
@@ -355,27 +357,50 @@ public boolean isNativeMethod() {
355357
* @revised 9
356358
* @see Throwable#printStackTrace()
357359
*/
360+
@Override
358361
public String toString() {
359-
String s = "";
360-
if (!dropClassLoaderName() && classLoaderName != null &&
361-
!classLoaderName.isEmpty()) {
362-
s += classLoaderName + "/";
362+
int estimatedLength = length(classLoaderName) + 1
363+
+ length(moduleName) + 1
364+
+ length(moduleVersion) + 1
365+
+ declaringClass.length() + 1
366+
+ methodName.length() + 1
367+
+ Math.max(UNKNOWN_SOURCE.length(), length(fileName)) + 1
368+
+ 12;
369+
370+
StringBuilder sb = new StringBuilder(estimatedLength);
371+
if (!dropClassLoaderName() && classLoaderName != null && !classLoaderName.isEmpty()) {
372+
sb.append(classLoaderName).append('/');
363373
}
374+
364375
if (moduleName != null && !moduleName.isEmpty()) {
365-
s += moduleName;
376+
sb.append(moduleName);
377+
if (!dropModuleVersion() && moduleVersion != null && !moduleVersion.isEmpty()) {
378+
sb.append('@').append(moduleVersion);
379+
}
380+
}
366381

367-
if (!dropModuleVersion() && moduleVersion != null &&
368-
!moduleVersion.isEmpty()) {
369-
s += "@" + moduleVersion;
382+
if (sb.length() > 0) {
383+
sb.append('/');
384+
}
385+
386+
sb.append(declaringClass).append('.').append(methodName).append('(');
387+
if (isNativeMethod()) {
388+
sb.append(NATIVE_METHOD);
389+
} else if (fileName == null) {
390+
sb.append(UNKNOWN_SOURCE);
391+
} else {
392+
sb.append(fileName);
393+
if (lineNumber >= 0) {
394+
sb.append(':').append(lineNumber);
370395
}
371396
}
372-
s = s.isEmpty() ? declaringClass : s + "/" + declaringClass;
397+
sb.append(')');
398+
399+
return sb.toString();
400+
}
373401

374-
return s + "." + methodName + "(" +
375-
(isNativeMethod() ? "Native Method)" :
376-
(fileName != null && lineNumber >= 0 ?
377-
fileName + ":" + lineNumber + ")" :
378-
(fileName != null ? ""+fileName+")" : "Unknown Source)")));
402+
private static int length(String s) {
403+
return (s == null) ? 0 : s.length();
379404
}
380405

381406
/**

test/jdk/java/lang/StackTraceElement/SerialTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 6479237
26+
* @bug 6479237 8291641
2727
* @summary Test the format of StackTraceElement::toString and its serial form
2828
* @modules java.logging
2929
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright (c) 2022, 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+
package org.openjdk.bench.java.lang;
24+
25+
import java.io.FilterOutputStream;
26+
import java.io.IOException;
27+
import java.io.OutputStream;
28+
import java.io.PrintStream;
29+
import java.io.PrintWriter;
30+
import java.io.StringWriter;
31+
import java.util.concurrent.TimeUnit;
32+
import java.util.stream.IntStream;
33+
import org.openjdk.jmh.annotations.Benchmark;
34+
import org.openjdk.jmh.annotations.BenchmarkMode;
35+
import org.openjdk.jmh.annotations.Fork;
36+
import org.openjdk.jmh.annotations.Measurement;
37+
import org.openjdk.jmh.annotations.Mode;
38+
import org.openjdk.jmh.annotations.OutputTimeUnit;
39+
import org.openjdk.jmh.annotations.Param;
40+
import org.openjdk.jmh.annotations.Scope;
41+
import org.openjdk.jmh.annotations.Setup;
42+
import org.openjdk.jmh.annotations.State;
43+
import org.openjdk.jmh.annotations.Warmup;
44+
45+
/**
46+
* Benchmarks for java.lang.StackTraceElement
47+
*/
48+
@State(value = Scope.Benchmark)
49+
@BenchmarkMode(Mode.AverageTime)
50+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
51+
@Warmup(iterations = 5, time = 1)
52+
@Measurement(iterations = 5, time = 1)
53+
@Fork(3)
54+
public class StackTraceElementBench {
55+
56+
private StackTraceElement element;
57+
private Throwable throwable;
58+
59+
@Setup
60+
public void setup() {
61+
StackTraceElement[] elements = IntStream.range(0, 500)
62+
.mapToObj(i -> new StackTraceElement(
63+
"classloader" + i,
64+
"module" + i,
65+
"version" + i,
66+
"class" + i,
67+
"method" + i,
68+
"file" + i + ".java",
69+
i))
70+
.toArray(StackTraceElement[]::new);
71+
this.element = elements[0];
72+
this.throwable = new RuntimeException("benchmark") {
73+
@Override
74+
public synchronized Throwable fillInStackTrace() {
75+
setStackTrace(elements);
76+
return this;
77+
}
78+
};
79+
}
80+
81+
@Benchmark
82+
public String toString() {
83+
return element.toString();
84+
}
85+
86+
@Benchmark
87+
public String printStackTrace() {
88+
StringWriter sw = new StringWriter();
89+
throwable.printStackTrace(new PrintWriter(sw));
90+
return sw.toString();
91+
}
92+
}

0 commit comments

Comments
 (0)