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