kyo.kernel.Trace.scala Maven / Gradle / Ivy
The newest version!
package kyo.kernel
import internal.*
import kyo.Frame
import scala.annotation.tailrec
import scala.util.control.NonFatal
import scala.util.control.NoStackTrace
final private[kyo] class Trace(
private[kernel] var frames: Array[Frame],
private[kernel] var index: Int
)
private[kyo] object Trace:
private[kernel] def init: Trace = Trace(new Array[Frame](maxTraceFrames), 0)
abstract private[kernel] class Owner extends TracePool.Local:
final private var frames = new Array[Frame](maxTraceFrames)
final private var index = 0
private[kernel] inline def pushFrame(frame: Frame): Unit =
val idx = this.index
frames(idx & (maxTraceFrames - 1)) = frame
this.index = idx + 1
end pushFrame
final private[kernel] def saveTrace(): Trace =
val newTrace = borrow()
val newFrames = newTrace.frames
val newIndex = math.min(index, maxTraceFrames)
if index <= maxTraceFrames then
System.arraycopy(frames, 0, newFrames, 0, newIndex)
else
val splitIndex = index & (maxTraceFrames - 1)
val firstPartLength = maxTraceFrames - splitIndex
System.arraycopy(frames, splitIndex, newFrames, 0, firstPartLength)
System.arraycopy(frames, 0, newFrames, firstPartLength, splitIndex)
end if
newTrace.index = newIndex
newTrace
end saveTrace
final private[kyo] def copyTrace(trace: Trace): Trace =
val newTrace = borrow()
System.arraycopy(trace.frames, 0, newTrace.frames, 0, Math.min(trace.index, maxTraceFrames - 1))
newTrace.index = trace.index
newTrace
end copyTrace
final private[kyo] def releaseTrace(trace: Trace): Unit =
release(trace)
private[kernel] inline def withTrace[A](trace: Trace)(inline f: => A)(using frame: Frame): A =
val prevFrames = frames
val prevIdx = index
frames = trace.frames
index = trace.index
pushFrame(frame)
try f
catch
case ex: Throwable if NonFatal(ex) =>
enrich(ex)
throw ex
finally
frames = prevFrames
index = prevIdx
end try
end withTrace
private[kernel] inline def withNewTrace[A](inline f: => A)(using Frame): A =
val trace: Trace = borrow()
try
withTrace(trace)(f)
finally
release(trace)
end try
end withNewTrace
final private[kernel] def enrich(ex: Throwable): Unit =
val size = if index < maxTraceFrames then index else maxTraceFrames
if size > 0 && !ex.isInstanceOf[NoStackTrace] then
val start =
if index < maxTraceFrames then 0
else index & (maxTraceFrames - 1)
val ordered = new Array[Frame](size)
@tailrec def parse(idx: Int, maxSnippetSize: Int): Int =
if idx < size then
val curr = frames((start + idx) & (maxTraceFrames - 1))
ordered(idx) = curr
val snippetSize = curr.snippetShort.size
parse(idx + 1, if snippetSize > maxSnippetSize then snippetSize else maxSnippetSize)
else
maxSnippetSize + 1
val toPad = parse(0, 0)
val elements =
ordered.foldLeft(List.empty[Frame]) {
case (acc, curr) =>
acc match
case `curr` :: tail => acc
case _ => curr :: acc
}.map { frame =>
StackTraceElement(
frame.snippetShort.reverse.padTo(toPad, ' ').reverse + " @ " + frame.className,
frame.methodName,
frame.position.fileName,
frame.position.lineNumber
)
}
val prefix = ex.getStackTrace.takeWhile(e =>
e.getFileName() != elements(0).getFileName() || e.getLineNumber != elements(0).getLineNumber()
)
val suffix = (new Exception).getStackTrace().drop(2)
ex.setStackTrace(prefix ++ elements ++ suffix)
end if
end enrich
end Owner
end Trace
© 2015 - 2025 Weber Informatics LLC | Privacy Policy