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