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