< prev index next >

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

Print this page
@@ -25,10 +25,12 @@
  
  package java.lang;
  
  import java.io.*;
  import java.util.*;
+ import jdk.internal.access.SharedSecrets;
+ import jdk.internal.misc.InternalLock;
  
  /**
   * The {@code Throwable} class is the superclass of all errors and
   * exceptions in the Java language. Only objects that are instances of this
   * class (or one of its subclasses) are thrown by the Java Virtual Machine or

@@ -657,31 +659,43 @@
      public void printStackTrace(PrintStream s) {
          printStackTrace(new WrappedPrintStream(s));
      }
  
      private void printStackTrace(PrintStreamOrWriter s) {
+         Object lock = s.lock();
+         if (lock instanceof InternalLock locker) {
+             locker.lock();
+             try {
+                 lockedPrintStackTrace(s);
+             } finally {
+                 locker.unlock();
+             }
+         } else synchronized (lock) {
+             lockedPrintStackTrace(s);
+         }
+     }
+ 
+     private void lockedPrintStackTrace(PrintStreamOrWriter s) {
          // Guard against malicious overrides of Throwable.equals by
          // using a Set with identity equality semantics.
          Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>());
          dejaVu.add(this);
  
-         synchronized (s.lock()) {
-             // Print our stack trace
-             s.println(this);
-             StackTraceElement[] trace = getOurStackTrace();
-             for (StackTraceElement traceElement : trace)
-                 s.println("\tat " + traceElement);
+         // Print our stack trace
+         s.println(this);
+         StackTraceElement[] trace = getOurStackTrace();
+         for (StackTraceElement traceElement : trace)
+             s.println("\tat " + traceElement);
  
-             // Print suppressed exceptions, if any
-             for (Throwable se : getSuppressed())
-                 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
+         // Print suppressed exceptions, if any
+         for (Throwable se : getSuppressed())
+             se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
  
-             // Print cause, if any
-             Throwable ourCause = getCause();
-             if (ourCause != null)
-                 ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
-         }
+         // Print cause, if any
+         Throwable ourCause = getCause();
+         if (ourCause != null)
+             ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
      }
  
      /**
       * Print our stack trace as an enclosed exception for the specified
       * stack trace.

@@ -689,11 +703,11 @@
      private void printEnclosedStackTrace(PrintStreamOrWriter s,
                                           StackTraceElement[] enclosingTrace,
                                           String caption,
                                           String prefix,
                                           Set<Throwable> dejaVu) {
-         assert Thread.holdsLock(s.lock());
+         assert s.isLockedByCurrentThread();
          if (dejaVu.contains(this)) {
              s.println(prefix + caption + "[CIRCULAR REFERENCE: " + this + "]");
          } else {
              dejaVu.add(this);
              // Compute number of frames in common between this and enclosing trace

@@ -741,10 +755,19 @@
       */
      private abstract static class PrintStreamOrWriter {
          /** Returns the object to be locked when using this StreamOrWriter */
          abstract Object lock();
  
+         boolean isLockedByCurrentThread() {
+             Object lock = lock();
+             if (lock instanceof InternalLock locker) {
+                 return locker.isHeldByCurrentThread();
+             } else {
+                 return Thread.holdsLock(lock);
+             }
+         }
+ 
          /** Prints the specified string as a line on this StreamOrWriter */
          abstract void println(Object o);
      }
  
      private static class WrappedPrintStream extends PrintStreamOrWriter {

@@ -753,11 +776,11 @@
          WrappedPrintStream(PrintStream printStream) {
              this.printStream = printStream;
          }
  
          Object lock() {
-             return printStream;
+             return SharedSecrets.getJavaIOPrintStreamAccess().lock(printStream);
          }
  
          void println(Object o) {
              printStream.println(o);
          }

@@ -769,11 +792,11 @@
          WrappedPrintWriter(PrintWriter printWriter) {
              this.printWriter = printWriter;
          }
  
          Object lock() {
-             return printWriter;
+             return SharedSecrets.getJavaIOPrintWriterAccess().lock(printWriter);
          }
  
          void println(Object o) {
              printWriter.println(o);
          }

@@ -831,15 +854,17 @@
      }
  
      private synchronized StackTraceElement[] getOurStackTrace() {
          // Initialize stack trace field with information from
          // backtrace if this is the first call to this method
-         if (stackTrace == UNASSIGNED_STACK ||
-             (stackTrace == null && backtrace != null) /* Out of protocol state */) {
-             stackTrace = StackTraceElement.of(this, depth);
-         } else if (stackTrace == null) {
-             return UNASSIGNED_STACK;
+         if (stackTrace == UNASSIGNED_STACK || stackTrace == null) {
+             if (backtrace != null) { /* Out of protocol state */
+                 stackTrace = StackTraceElement.of(backtrace, depth);
+             } else {
+                 // no backtrace, fillInStackTrace overridden or not called
+                 return UNASSIGNED_STACK;
+             }
          }
          return stackTrace;
      }
  
      /**
< prev index next >