I am trying to understand the implementation of Throwable.fillInStackTrace():
private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0];
[...]
private StackTraceElement[] stackTrace = UNASSIGNED_STACK;
[...]
/**
* Fills in the execution stack trace. This method records within this
* {@code Throwable} object information about the current state of
* the stack frames for the current thread.
*
* <p>If the stack trace of this {@code Throwable} {@linkplain
* Throwable#Throwable(String, Throwable, boolean, boolean) is not
* writable}, calling this method has no effect.
*
* @return a reference to this {@code Throwable} instance.
* @see java.lang.Throwable#printStackTrace()
*/
public synchronized Throwable fillInStackTrace() {
if (stackTrace != null ||
backtrace != null /* Out of protocol state */ ) {
fillInStackTrace(0);
stackTrace = UNASSIGNED_STACK;
}
return this;
}
private native Throwable fillInStackTrace(int dummy);
(source OpenJDK)
I would have guess that fillInStackTrace(int) collects the stack trace from VM internals, and then creates an array of java/lang/StackTraceElement and assigns it to the Throwable.stackTrace property.
However, the standard implementation seems to clear the value of Throwable.stackTrace directly after. When running a simple sample, the information is clearly stored in the Throwable. Sample:
Throwable th = new Throwable();
th.printStackTrace(); // prints the stack up to this point
So, where is the magic / what am I misunderstanding?
PS: what does "out of protocol state" mean in the source code?