1 /*
2 * Copyright (c) 2000, 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
26 package java.lang;
27
28 import jdk.internal.loader.BuiltinClassLoader;
29 import jdk.internal.misc.VM;
30 import jdk.internal.module.ModuleHashes;
31 import jdk.internal.module.ModuleReferenceImpl;
32
33 import java.lang.constant.ConstantDescs;
34 import java.lang.module.ModuleReference;
35 import java.lang.module.ResolvedModule;
36 import java.util.HashSet;
37 import java.util.Objects;
38 import java.util.Optional;
39 import java.util.Set;
40
41 /**
42 * An element in a stack trace, as returned by {@link
43 * Throwable#getStackTrace()}. Each element represents a single stack frame.
44 * All stack frames except for the one at the top of the stack represent
45 * a method invocation. The frame at the top of the stack represents the
46 * execution point at which the stack trace was generated. Typically,
47 * this is the point at which the throwable corresponding to the stack trace
48 * was created.
49 *
50 * @since 1.4
51 * @author Josh Bloch
52 */
53 public final class StackTraceElement implements java.io.Serializable {
54
55 private static final String NATIVE_METHOD = "Native Method";
56 private static final String UNKNOWN_SOURCE = "Unknown Source";
57
58 // For Throwables and StackWalker, the VM initially sets this field to a
59 // reference to the declaring Class. The Class reference is used to
60 // construct the 'format' bitmap, and then is cleared.
61 //
62 // For STEs constructed using the public constructors, this field is not used.
63 private transient Class<?> declaringClassObject;
64
65 // Normally initialized by VM
66 /**
67 * @serial The name of the class loader.
68 */
69 private String classLoaderName;
70 /**
71 * @serial The module name.
72 */
73 private String moduleName;
74 /**
75 * @serial The module version.
76 */
77 private String moduleVersion;
78 /**
79 * @serial The declaring class.
80 */
81 private String declaringClass;
82 /**
83 * @serial The method name.
84 */
85 private String methodName;
86 /**
87 * @serial The source file name.
88 */
89 private String fileName;
90 /**
91 * @serial The source line number.
92 */
93 private int lineNumber;
94 /**
95 * @serial Control to show full or partial module, package, and class names.
96 */
97 private byte format = 0; // Default to show all
98
99 /**
100 * Creates a stack trace element representing the specified execution
101 * point. The {@link #getModuleName module name} and {@link
102 * #getModuleVersion module version} of the stack trace element will
103 * be {@code null}.
104 *
105 * @param declaringClass the {@linkplain ClassLoader##binary-name binary name}
106 * of the class containing the execution point represented by
107 * the stack trace element
108 * @param methodName the name of the method containing the execution point
109 * represented by the stack trace element
110 * @param fileName the name of the file containing the execution point
111 * represented by the stack trace element, or {@code null} if
112 * this information is unavailable
113 * @param lineNumber the line number of the source line containing the
114 * execution point represented by this stack trace element, or
115 * a negative number if this information is unavailable. A value
116 * of -2 indicates that the method containing the execution point
117 * is a native method
118 * @throws NullPointerException if {@code declaringClass} or
119 * {@code methodName} is null
120 * @since 1.5
121 */
122 public StackTraceElement(String declaringClass, String methodName,
123 String fileName, int lineNumber) {
124 this(null, null, null, declaringClass, methodName, fileName, lineNumber);
125 }
126
127 /**
128 * Creates a stack trace element representing the specified execution
129 * point.
130 *
131 * @param classLoaderName the class loader name if the class loader of
132 * the class containing the execution point represented by
133 * the stack trace is named; otherwise {@code null}
134 * @param moduleName the module name if the class containing the
135 * execution point represented by the stack trace is in a named
136 * module; otherwise {@code null}
137 * @param moduleVersion the module version if the class containing the
138 * execution point represented by the stack trace is in a named
139 * module that has a version; otherwise {@code null}
140 * @param declaringClass the {@linkplain ClassLoader##binary-name binary name}
141 * of the class containing the execution point represented by
142 * the stack trace element
143 * @param methodName the name of the method containing the execution point
144 * represented by the stack trace element
145 * @param fileName the name of the file containing the execution point
146 * represented by the stack trace element, or {@code null} if
147 * this information is unavailable
148 * @param lineNumber the line number of the source line containing the
149 * execution point represented by this stack trace element, or
150 * a negative number if this information is unavailable. A value
151 * of -2 indicates that the method containing the execution point
152 * is a native method
153 *
154 * @throws NullPointerException if {@code declaringClass} is {@code null}
155 * or {@code methodName} is {@code null}
156 *
157 * @since 9
158 */
159 public StackTraceElement(String classLoaderName,
160 String moduleName, String moduleVersion,
161 String declaringClass, String methodName,
162 String fileName, int lineNumber) {
163 this.classLoaderName = classLoaderName;
164 this.moduleName = moduleName;
165 this.moduleVersion = moduleVersion;
166 this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null");
167 this.methodName = Objects.requireNonNull(methodName, "Method name is null");
168 this.fileName = fileName;
169 this.lineNumber = lineNumber;
170 }
171
172 /*
173 * Private constructor for the factory methods to create StackTraceElement
174 * for Throwable and StackFrameInfo
175 */
176 private StackTraceElement() {}
177
178 /**
179 * Returns the name of the source file containing the execution point
180 * represented by this stack trace element. Generally, this corresponds
181 * to the {@code SourceFile} attribute of the relevant {@code class}
182 * file (as per <cite>The Java Virtual Machine Specification</cite>, Section
183 * {@jvms 4.7.7}). In some systems, the name may refer to some source code unit
184 * other than a file, such as an entry in source repository.
185 *
186 * @return the name of the file containing the execution point
187 * represented by this stack trace element, or {@code null} if
188 * this information is unavailable.
189 */
190 public String getFileName() {
191 return fileName;
192 }
193
194 /**
195 * Returns the line number of the source line containing the execution
196 * point represented by this stack trace element. Generally, this is
197 * derived from the {@code LineNumberTable} attribute of the relevant
198 * {@code class} file (as per <cite>The Java Virtual Machine
199 * Specification</cite>, Section {@jvms 4.7.8}).
200 *
201 * @return the line number of the source line containing the execution
202 * point represented by this stack trace element, or a negative
203 * number if this information is unavailable.
204 */
205 public int getLineNumber() {
206 return lineNumber;
207 }
208
209 /**
210 * Returns the module name of the module containing the execution point
211 * represented by this stack trace element.
212 *
213 * @return the module name of the {@code Module} containing the execution
214 * point represented by this stack trace element; {@code null}
215 * if the module name is not available.
216 * @since 9
217 * @see Module#getName()
218 */
219 public String getModuleName() {
220 return moduleName;
221 }
222
223 /**
224 * Returns the module version of the module containing the execution point
225 * represented by this stack trace element.
226 *
227 * @return the module version of the {@code Module} containing the execution
228 * point represented by this stack trace element; {@code null}
229 * if the module version is not available.
230 * @since 9
231 * @see java.lang.module.ModuleDescriptor.Version
232 */
233 public String getModuleVersion() {
234 return moduleVersion;
235 }
236
237 /**
238 * Returns the name of the class loader of the class containing the
239 * execution point represented by this stack trace element.
240 *
241 * @return the name of the class loader of the class containing the execution
242 * point represented by this stack trace element; {@code null}
243 * if the class loader is not named.
244 *
245 * @since 9
246 * @see java.lang.ClassLoader#getName()
247 */
248 public String getClassLoaderName() {
249 return classLoaderName;
250 }
251
252 /**
253 * {@return the {@linkplain ClassLoader##binary-name binary name}
254 * of the {@code Class} containing the execution point represented
255 * by this stack trace element}
256 */
257 public String getClassName() {
258 return declaringClass;
259 }
260
261 /**
262 * Returns the name of the method containing the execution point
263 * represented by this stack trace element. If the execution point is
264 * contained in an instance or class initializer, this method will return
265 * the appropriate <i>special method name</i>, {@value ConstantDescs#INIT_NAME}
266 * or {@value ConstantDescs#CLASS_INIT_NAME}, as per Section {@jvms 3.9}
267 * of <cite>The Java Virtual Machine Specification</cite>.
268 *
269 * @return the name of the method containing the execution point
270 * represented by this stack trace element.
271 */
272 public String getMethodName() {
273 return methodName;
274 }
275
276 /**
277 * Returns true if the method containing the execution point
278 * represented by this stack trace element is a native method.
279 *
280 * @return {@code true} if the method containing the execution point
281 * represented by this stack trace element is a native method.
282 */
283 public boolean isNativeMethod() {
284 return lineNumber == -2;
285 }
286
287 /**
288 * Returns a string representation of this stack trace element.
289 *
290 * @apiNote The format of this string depends on the implementation, but the
291 * following examples may be regarded as typical:
292 * <ul>
293 * <li>
294 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101)}"
295 * - See the description below.
296 * </li>
297 * <li>
298 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Main.java)}"
299 * - The line number is unavailable.
300 * </li>
301 * <li>
302 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Unknown Source)}"
303 * - Neither the file name nor the line number is available.
304 * </li>
305 * <li>
306 * "{@code com.foo.loader/foo@9.0/com.foo.Main.run(Native Method)}"
307 * - The method containing the execution point is a native method.
308 * </li>
309 * <li>
310 * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}"
311 * - The class of the execution point is defined in the unnamed module of
312 * the class loader named {@code com.foo.loader}.
313 * </li>
314 * <li>
315 * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}"
316 * - The class of the execution point is defined in {@code acme} module
317 * loaded by a built-in class loader such as the application class loader.
318 * </li>
319 * <li>
320 * "{@code MyClass.mash(MyClass.java:9)}"
321 * - {@code MyClass} class is on the application class path.
322 * </li>
323 * </ul>
324 *
325 * <p> The first example shows a stack trace element consisting of
326 * three elements, each separated by {@code "/"}, followed by
327 * the source file name and the line number of the source line
328 * containing the execution point.
329 *
330 * The first element "{@code com.foo.loader}" is
331 * the name of the class loader. The second element "{@code foo@9.0}"
332 * is the module name and version. The third element is the method
333 * containing the execution point; "{@code com.foo.Main"}" is the
334 * binary name and "{@code run}" is the name of the method.
335 * "{@code Main.java}" is the source file name and "{@code 101}" is
336 * the line number.
337 *
338 * <p> If a class is defined in an <em>unnamed module</em>
339 * then the second element is omitted as shown in
340 * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}".
341 *
342 * <p> If the class loader is a <a href="ClassLoader.html#builtinLoaders">
343 * built-in class loader</a> or is not named then the first element
344 * and its following {@code "/"} are omitted as shown in
345 * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}".
346 * If the first element is omitted and the module is an unnamed module,
347 * the second element and its following {@code "/"} are also omitted
348 * as shown in "{@code MyClass.mash(MyClass.java:9)}".
349 *
350 * <p> The {@code toString} method may return two different values on two
351 * {@code StackTraceElement} instances that are
352 * {@linkplain #equals(Object) equal}, for example one created via the
353 * constructor, and one obtained from {@link java.lang.Throwable} or
354 * {@link java.lang.StackWalker.StackFrame}, where an implementation may
355 * choose to omit some element in the returned string.
356 *
357 * @see Throwable#printStackTrace()
358 */
359 @Override
360 public String toString() {
361 int estimatedLength = length(classLoaderName) + 1
362 + length(moduleName) + 1
363 + length(moduleVersion) + 1
364 + declaringClass.length() + 1
365 + methodName.length() + 1
366 + Math.max(UNKNOWN_SOURCE.length(), length(fileName)) + 1
367 + 12;
368
369 StringBuilder sb = new StringBuilder(estimatedLength);
370 if (!dropClassLoaderName() && classLoaderName != null && !classLoaderName.isEmpty()) {
371 sb.append(classLoaderName).append('/');
372 }
373
374 if (moduleName != null && !moduleName.isEmpty()) {
375 sb.append(moduleName);
376 if (!dropModuleVersion() && moduleVersion != null && !moduleVersion.isEmpty()) {
377 sb.append('@').append(moduleVersion);
378 }
379 }
380
381 if (sb.length() > 0) {
382 sb.append('/');
383 }
384
385 sb.append(declaringClass).append('.').append(methodName).append('(');
386 if (isNativeMethod()) {
387 sb.append(NATIVE_METHOD);
388 } else if (fileName == null) {
389 sb.append(UNKNOWN_SOURCE);
390 } else {
391 sb.append(fileName);
392 if (lineNumber >= 0) {
393 sb.append(':').append(lineNumber);
394 }
395 }
396 sb.append(')');
397
398 return sb.toString();
399 }
400
401 private static int length(String s) {
402 return (s == null) ? 0 : s.length();
403 }
404
405 /**
406 * Returns true if the specified object is another
407 * {@code StackTraceElement} instance representing the same execution
408 * point as this instance. Two stack trace elements {@code a} and
409 * {@code b} are equal if and only if:
410 * <pre>{@code
411 * equals(a.getClassLoaderName(), b.getClassLoaderName()) &&
412 * equals(a.getModuleName(), b.getModuleName()) &&
413 * equals(a.getModuleVersion(), b.getModuleVersion()) &&
414 * equals(a.getClassName(), b.getClassName()) &&
415 * equals(a.getMethodName(), b.getMethodName())
416 * equals(a.getFileName(), b.getFileName()) &&
417 * a.getLineNumber() == b.getLineNumber()
418 *
419 * }</pre>
420 * where {@code equals} has the semantics of {@link
421 * java.util.Objects#equals(Object, Object) Objects.equals}.
422 *
423 * @param obj the object to be compared with this stack trace element.
424 * @return true if the specified object is another
425 * {@code StackTraceElement} instance representing the same
426 * execution point as this instance.
427 */
428 public boolean equals(Object obj) {
429 if (obj==this)
430 return true;
431 return (obj instanceof StackTraceElement e)
432 && e.lineNumber == lineNumber
433 && e.declaringClass.equals(declaringClass)
434 && Objects.equals(classLoaderName, e.classLoaderName)
435 && Objects.equals(moduleName, e.moduleName)
436 && Objects.equals(moduleVersion, e.moduleVersion)
437 && Objects.equals(methodName, e.methodName)
438 && Objects.equals(fileName, e.fileName);
439 }
440
441 /**
442 * Returns a hash code value for this stack trace element.
443 */
444 public int hashCode() {
445 int result = 31*declaringClass.hashCode() + methodName.hashCode();
446 result = 31*result + Objects.hashCode(classLoaderName);
447 result = 31*result + Objects.hashCode(moduleName);
448 result = 31*result + Objects.hashCode(moduleVersion);
449 result = 31*result + Objects.hashCode(fileName);
450 result = 31*result + lineNumber;
451 return result;
452 }
453
454
455 /**
456 * Called from of() methods to set the 'format' bitmap using the Class
457 * reference stored in declaringClassObject, and then clear the reference.
458 *
459 * <p>
460 * If the module is a non-upgradeable JDK module, then set
461 * JDK_NON_UPGRADEABLE_MODULE to omit its version string.
462 * <p>
463 * If the loader is one of the built-in loaders (`boot`, `platform`, or `app`)
464 * then set BUILTIN_CLASS_LOADER to omit the first element (`<loader>/`).
465 */
466 private synchronized void computeFormat() {
467 try {
468 Class<?> cls = declaringClassObject;
469 ClassLoader loader = cls.getClassLoader0();
470 Module m = cls.getModule();
471 byte bits = 0;
472
473 // First element - class loader name
474 // Call package-private ClassLoader::name method
475
476 if (loader instanceof BuiltinClassLoader) {
477 bits |= BUILTIN_CLASS_LOADER;
478 }
479
480 // Second element - module name and version
481
482 // Omit if is a JDK non-upgradeable module (recorded in the hashes
483 // in java.base)
484 if (isHashedInJavaBase(m)) {
485 bits |= JDK_NON_UPGRADEABLE_MODULE;
486 }
487 format = bits;
488 } finally {
489 // Class reference no longer needed, clear it
490 declaringClassObject = null;
491 }
492 }
493
494 private static final byte BUILTIN_CLASS_LOADER = 0x1;
495 private static final byte JDK_NON_UPGRADEABLE_MODULE = 0x2;
496
497 private boolean dropClassLoaderName() {
498 return (format & BUILTIN_CLASS_LOADER) == BUILTIN_CLASS_LOADER;
499 }
500
501 private boolean dropModuleVersion() {
502 return (format & JDK_NON_UPGRADEABLE_MODULE) == JDK_NON_UPGRADEABLE_MODULE;
503 }
504
505 /**
506 * Returns true if the module is hashed with java.base.
507 * <p>
508 * This method returns false when running on the exploded image
509 * since JDK modules are not hashed. They have no Version attribute
510 * and so "@<version>" part will be omitted anyway.
511 */
512 private static boolean isHashedInJavaBase(Module m) {
513 // return true if module system is not initialized as the code
514 // must be in java.base
515 if (!VM.isModuleSystemInited())
516 return true;
517
518 return ModuleLayer.boot() == m.getLayer() && HashedModules.contains(m);
519 }
520
521 /*
522 * Finds JDK non-upgradeable modules, i.e. the modules that are
523 * included in the hashes in java.base.
524 */
525 private static class HashedModules {
526 static Set<String> HASHED_MODULES = hashedModules();
527
528 static Set<String> hashedModules() {
529
530 Optional<ResolvedModule> resolvedModule = ModuleLayer.boot()
531 .configuration()
532 .findModule("java.base");
533 assert resolvedModule.isPresent();
534 ModuleReference mref = resolvedModule.get().reference();
535 assert mref instanceof ModuleReferenceImpl;
536 ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
537 if (hashes != null) {
538 Set<String> names = new HashSet<>(hashes.names());
539 names.add("java.base");
540 return names;
541 }
542
543 return Set.of();
544 }
545
546 static boolean contains(Module m) {
547 return HASHED_MODULES.contains(m.getName());
548 }
549 }
550
551
552 /*
553 * Returns an array of StackTraceElements of the given depth
554 * filled from the given backtrace.
555 */
556 static StackTraceElement[] of(Object x, int depth) {
557 StackTraceElement[] stackTrace = new StackTraceElement[depth];
558 for (int i = 0; i < depth; i++) {
559 stackTrace[i] = new StackTraceElement();
560 }
561
562 // VM to fill in StackTraceElement
563 initStackTraceElements(stackTrace, x, depth);
564 return finishInit(stackTrace);
565 }
566
567 /*
568 * Returns a StackTraceElement from a given StackFrameInfo.
569 */
570 static StackTraceElement of(StackFrameInfo sfi) {
571 StackTraceElement ste = new StackTraceElement();
572 initStackTraceElement(ste, sfi);
573
574 ste.computeFormat();
575 return ste;
576 }
577
578 static StackTraceElement[] finishInit(StackTraceElement[] stackTrace) {
579 // ensure the proper StackTraceElement initialization
580 for (StackTraceElement ste : stackTrace) {
581 ste.computeFormat();
582 }
583 return stackTrace;
584 }
585
586 /*
587 * Sets the given stack trace elements with the backtrace
588 * of the given Throwable.
589 */
590 private static native void initStackTraceElements(StackTraceElement[] elements,
591 Object x, int depth);
592 /*
593 * Sets the given stack trace element with the given StackFrameInfo
594 */
595 private static native void initStackTraceElement(StackTraceElement element,
596 StackFrameInfo sfi);
597
598 @java.io.Serial
599 private static final long serialVersionUID = 6992337162326171013L;
600 }