Move stack trace inside Stack class
This commit is contained in:
+10
-24
@@ -36,7 +36,6 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
private val illegalArgumentException = irExceptions.first { it.name.asString() == IllegalArgumentException::class.java.simpleName }
|
||||
|
||||
private val stack = StackImpl()
|
||||
private val stackTrace = mutableListOf<String>()
|
||||
private var commandCount = 0
|
||||
|
||||
private val mapOfEnums = mutableMapOf<Pair<IrClass, String>, Complex>()
|
||||
@@ -129,34 +128,21 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
// catch exception from JVM such as: ArithmeticException, StackOverflowError and others
|
||||
val exceptionName = e::class.java.simpleName
|
||||
val irExceptionClass = irExceptions.firstOrNull { it.name.asString() == exceptionName } ?: irBuiltIns.throwableClass.owner
|
||||
stack.pushReturnValue(ExceptionState(e, irExceptionClass, stackTrace))
|
||||
stack.pushReturnValue(ExceptionState(e, irExceptionClass, stack.getStackTrace()))
|
||||
return Exception
|
||||
}
|
||||
}
|
||||
|
||||
// this method is used to get stack trace after exception
|
||||
private suspend fun interpretFunction(irFunction: IrFunctionImpl): ExecutionResult {
|
||||
return try {
|
||||
yield()
|
||||
yield()
|
||||
|
||||
if (irFunction.fileOrNull != null) {
|
||||
val fileName = irFunction.file.name
|
||||
val lineNum = irFunction.fileEntry.getLineNumber(irFunction.startOffset) + 1
|
||||
stackTrace += "at ${fileName.replace(".kt", "Kt").capitalize()}.${irFunction.fqNameForIrSerialization}($fileName:$lineNum)"
|
||||
}
|
||||
if (irFunction.fileOrNull != null) stack.setCurrentFrameName(irFunction)
|
||||
|
||||
if (stackTrace.size == MAX_STACK_SIZE) {
|
||||
throw StackOverflowError("")
|
||||
}
|
||||
if (stack.getStackTrace().size == MAX_STACK_SIZE) throw StackOverflowError("")
|
||||
|
||||
when (val kind = (irFunction.body as? IrSyntheticBody)?.kind) {
|
||||
IrSyntheticBodyKind.ENUM_VALUES, IrSyntheticBodyKind.ENUM_VALUEOF -> handleIntrinsicMethods(irFunction)
|
||||
null -> irFunction.body?.interpret() ?: throw InterpreterException("Ir function must be with body")
|
||||
else -> throw InterpreterException("Unsupported IrSyntheticBodyKind $kind")
|
||||
}
|
||||
} finally {
|
||||
if (irFunction.fileOrNull != null) stackTrace.removeAt(stackTrace.lastIndex)
|
||||
}
|
||||
if (irFunction.body is IrSyntheticBody) return handleIntrinsicMethods(irFunction)
|
||||
return irFunction.body?.interpret() ?: throw InterpreterException("Ir function must be with body")
|
||||
}
|
||||
|
||||
private suspend fun MethodHandle?.invokeMethod(irFunction: IrFunction): ExecutionResult {
|
||||
@@ -202,7 +188,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
.singleOrNull { it.name.asString() == enumEntryName }
|
||||
if (enumEntry == null) {
|
||||
val message = "No enum constant ${enumClass.fqNameForIrSerialization}.$enumEntryName"
|
||||
stack.pushReturnValue(ExceptionState(IllegalArgumentException(message), illegalArgumentException, stackTrace))
|
||||
stack.pushReturnValue(ExceptionState(IllegalArgumentException(message), illegalArgumentException, stack.getStackTrace()))
|
||||
return Exception
|
||||
} else {
|
||||
enumEntry.interpret().check { return it }
|
||||
@@ -682,7 +668,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
val convertibleClassName = stack.popReturnValue().irClass.fqNameForIrSerialization
|
||||
val castClassName = expression.type.classOrNull?.owner?.fqNameForIrSerialization
|
||||
val message = "$convertibleClassName cannot be cast to $castClassName"
|
||||
stack.pushReturnValue(ExceptionState(ClassCastException(message), classCastException, stackTrace))
|
||||
stack.pushReturnValue(ExceptionState(ClassCastException(message), classCastException, stack.getStackTrace()))
|
||||
return Exception
|
||||
}
|
||||
}
|
||||
@@ -759,8 +745,8 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
private suspend fun interpretThrow(expression: IrThrow): ExecutionResult {
|
||||
expression.value.interpret().check { return it }
|
||||
when (val exception = stack.popReturnValue()) {
|
||||
is Common -> stack.pushReturnValue(ExceptionState(exception, stackTrace))
|
||||
is Wrapper -> stack.pushReturnValue(ExceptionState(exception, stackTrace))
|
||||
is Common -> stack.pushReturnValue(ExceptionState(exception, stack.getStackTrace()))
|
||||
is Wrapper -> stack.pushReturnValue(ExceptionState(exception, stack.getStackTrace()))
|
||||
is ExceptionState -> stack.pushReturnValue(exception)
|
||||
else -> throw InterpreterException("${exception::class} cannot be used as exception state")
|
||||
}
|
||||
|
||||
+22
-1
@@ -9,6 +9,11 @@ import org.jetbrains.kotlin.backend.common.interpreter.ExecutionResult
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterException
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.state.State
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.name
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.fileEntry
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
interface Stack {
|
||||
@@ -16,6 +21,9 @@ interface Stack {
|
||||
asSubFrame: Boolean = false, initPool: List<Variable> = listOf(), block: suspend () -> ExecutionResult
|
||||
): ExecutionResult
|
||||
|
||||
fun setCurrentFrameName(irFunction: IrFunction)
|
||||
fun getStackTrace(): List<String>
|
||||
|
||||
fun clean()
|
||||
fun addVar(variable: Variable)
|
||||
fun addAll(variables: List<Variable>)
|
||||
@@ -49,6 +57,18 @@ class StackImpl : Stack {
|
||||
frameList.removeAt(frameList.lastIndex)
|
||||
}
|
||||
|
||||
override fun setCurrentFrameName(irFunction: IrFunction) {
|
||||
val fileName = irFunction.file.name
|
||||
val fileNameCapitalized = fileName.replace(".kt", "Kt").capitalize()
|
||||
val lineNum = irFunction.fileEntry.getLineNumber(irFunction.startOffset) + 1
|
||||
getCurrentFrame().frameEntryPoint = "at $fileNameCapitalized.${irFunction.fqNameWhenAvailable}($fileName:$lineNum)"
|
||||
}
|
||||
|
||||
override fun getStackTrace(): List<String> {
|
||||
// TODO implement some sort of cache
|
||||
return frameList.mapNotNull { it.frameEntryPoint }
|
||||
}
|
||||
|
||||
override fun clean() {
|
||||
frameList.clear()
|
||||
frameList.add(FrameContainer())
|
||||
@@ -92,7 +112,8 @@ class StackImpl : Stack {
|
||||
}
|
||||
|
||||
private class FrameContainer(current: Frame = InterpreterFrame()) {
|
||||
private var innerStack = mutableListOf(current)
|
||||
var frameEntryPoint: String? = null
|
||||
private val innerStack = mutableListOf(current)
|
||||
private fun getTopFrame() = innerStack.first()
|
||||
|
||||
fun addSubFrame(frame: Frame) {
|
||||
|
||||
Reference in New Issue
Block a user