We have to be very careful not to break anything here.
Some desirable features of what we have at the moment:
1. Creating an instance of Throwable is fast. It's good that we
don't do any expensive searches when fillInStackTrace() is called.
Right - fillInStackTrace() walks the stack and collects the PC/IP for
each frame, exactly what it does already. This is called from the
Throwable constructor. getStackTrace() takes that info and converts it
to the StackFrameInfo array which contains the method names, line number
info, etc - as much as is available. Finally printStackTrace() takes the
StackTraceData array and prints the trace.