Save right entry point for expression
This commit is contained in:
committed by
TeamCityServer
parent
9d9ab498aa
commit
ec16c40bf4
+13
-17
@@ -43,7 +43,7 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
|||||||
private val mapOfEnums = mutableMapOf<IrSymbol, Complex>()
|
private val mapOfEnums = mutableMapOf<IrSymbol, Complex>()
|
||||||
private val mapOfObjects = mutableMapOf<IrSymbol, Complex>()
|
private val mapOfObjects = mutableMapOf<IrSymbol, Complex>()
|
||||||
|
|
||||||
constructor(irModule: IrModuleFragment): this(irModule.irBuiltins) {
|
constructor(irModule: IrModuleFragment) : this(irModule.irBuiltins) {
|
||||||
irExceptions.addAll(
|
irExceptions.addAll(
|
||||||
irModule.files
|
irModule.files
|
||||||
.flatMap { it.declarations }
|
.flatMap { it.declarations }
|
||||||
@@ -73,25 +73,21 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
|||||||
if (commandCount >= MAX_COMMANDS) InterpreterTimeOutError().throwAsUserException()
|
if (commandCount >= MAX_COMMANDS) InterpreterTimeOutError().throwAsUserException()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun interpret(expression: IrExpression): IrExpression {
|
fun interpret(expression: IrExpression, parentFile: IrFile? = null): IrExpression {
|
||||||
stack.clean()
|
stack.clean()
|
||||||
return try {
|
val result = stack.withEntryPoint(irFile = parentFile) { expression.interpret() }
|
||||||
when (val returnLabel = expression.interpret().returnLabel) {
|
return when (val returnLabel = result.returnLabel) {
|
||||||
ReturnLabel.REGULAR -> stack.popReturnValue().toIrExpression(expression)
|
ReturnLabel.REGULAR -> stack.popReturnValue().toIrExpression(expression)
|
||||||
ReturnLabel.EXCEPTION -> {
|
ReturnLabel.EXCEPTION -> {
|
||||||
val message = (stack.popReturnValue() as ExceptionState).getFullDescription()
|
val message = (stack.popReturnValue() as ExceptionState).getFullDescription()
|
||||||
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + message)
|
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + message)
|
||||||
}
|
|
||||||
else -> TODO("$returnLabel not supported as result of interpretation")
|
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
else -> TODO("$returnLabel not supported as result of interpretation")
|
||||||
// TODO don't handle, throw to lowering
|
|
||||||
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + e.message)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun IrFunction.interpret(valueArguments: List<Variable>, expectedResultClass: Class<*> = Any::class.java): Any? {
|
internal fun IrFunction.interpret(valueArguments: List<Variable>, expectedResultClass: Class<*> = Any::class.java): Any? {
|
||||||
val returnLabel = stack.newFrame(asSubFrame = this.isLocal, initPool = valueArguments) {
|
val returnLabel = stack.newFrame(this, initPool = valueArguments) {
|
||||||
this@interpret.interpret()
|
this@interpret.interpret()
|
||||||
}
|
}
|
||||||
return when (returnLabel.returnLabel) {
|
return when (returnLabel.returnLabel) {
|
||||||
@@ -158,8 +154,6 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
|||||||
// this method is used to get stack trace after exception
|
// this method is used to get stack trace after exception
|
||||||
private fun interpretFunction(irFunction: IrSimpleFunction): ExecutionResult {
|
private fun interpretFunction(irFunction: IrSimpleFunction): ExecutionResult {
|
||||||
if (stack.getStackCount() >= MAX_STACK) StackOverflowError().throwAsUserException()
|
if (stack.getStackCount() >= MAX_STACK) StackOverflowError().throwAsUserException()
|
||||||
if (irFunction.fileOrNull != null) stack.setCurrentFrameName(irFunction)
|
|
||||||
|
|
||||||
if (irFunction.body is IrSyntheticBody) return handleIntrinsicMethods(irFunction)
|
if (irFunction.body is IrSyntheticBody) return handleIntrinsicMethods(irFunction)
|
||||||
return irFunction.body?.interpret() ?: throw InterpreterError("Ir function must be with body")
|
return irFunction.body?.interpret() ?: throw InterpreterError("Ir function must be with body")
|
||||||
}
|
}
|
||||||
@@ -316,7 +310,8 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
|||||||
generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { valueArguments.add(it) }
|
generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { valueArguments.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
return stack.newFrame(asSubFrame = irFunction.isInline || irFunction.isLocal, initPool = valueArguments) {
|
stack.fixCallEntryPoint(expression)
|
||||||
|
return stack.newFrame(irFunction, initPool = valueArguments) {
|
||||||
// inline only methods are not presented in lookup table, so must be interpreted instead of execution
|
// inline only methods are not presented in lookup table, so must be interpreted instead of execution
|
||||||
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
|
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
|
||||||
return@newFrame when {
|
return@newFrame when {
|
||||||
@@ -821,6 +816,7 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSigna
|
|||||||
|
|
||||||
private fun interpretThrow(expression: IrThrow): ExecutionResult {
|
private fun interpretThrow(expression: IrThrow): ExecutionResult {
|
||||||
expression.value.interpret().check { return it }
|
expression.value.interpret().check { return it }
|
||||||
|
stack.fixCallEntryPoint(expression)
|
||||||
when (val exception = stack.popReturnValue()) {
|
when (val exception = stack.popReturnValue()) {
|
||||||
is Common -> stack.pushReturnValue(ExceptionState(exception, stack.getStackTrace()))
|
is Common -> stack.pushReturnValue(ExceptionState(exception, stack.getStackTrace()))
|
||||||
is Wrapper -> stack.pushReturnValue(ExceptionState(exception, stack.getStackTrace()))
|
is Wrapper -> stack.pushReturnValue(ExceptionState(exception, stack.getStackTrace()))
|
||||||
|
|||||||
@@ -5,22 +5,25 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.interpreter.stack
|
package org.jetbrains.kotlin.ir.interpreter.stack
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.ExecutionResult
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.interpreter.getCapitalizedFileName
|
|
||||||
import org.jetbrains.kotlin.ir.interpreter.state.State
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.name
|
import org.jetbrains.kotlin.ir.declarations.name
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.ExecutionResult
|
||||||
|
import org.jetbrains.kotlin.ir.interpreter.state.State
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.util.file
|
import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.fileEntry
|
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
|
import org.jetbrains.kotlin.ir.util.isLocal
|
||||||
|
|
||||||
internal interface Stack {
|
internal interface Stack {
|
||||||
fun newFrame(asSubFrame: Boolean = false, initPool: List<Variable> = listOf(), block: () -> ExecutionResult): ExecutionResult
|
fun newFrame(asSubFrame: Boolean = false, initPool: List<Variable> = listOf(), block: () -> ExecutionResult): ExecutionResult
|
||||||
|
fun newFrame(irFunction: IrFunction, initPool: List<Variable> = listOf(), block: () -> ExecutionResult): ExecutionResult
|
||||||
|
|
||||||
fun setCurrentFrameName(irFunction: IrFunction)
|
fun fixCallEntryPoint(irExpression: IrExpression)
|
||||||
|
fun withEntryPoint(irFunction: IrFunction? = null, irFile: IrFile? = null, block: () -> ExecutionResult): ExecutionResult
|
||||||
fun getStackTrace(): List<String>
|
fun getStackTrace(): List<String>
|
||||||
fun getStackCount(): Int
|
fun getStackCount(): Int
|
||||||
|
|
||||||
@@ -57,22 +60,36 @@ internal class StackImpl : Stack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun newFrame(irFunction: IrFunction, initPool: List<Variable>, block: () -> ExecutionResult): ExecutionResult {
|
||||||
|
val asSubFrame = irFunction.isInline || irFunction.isLocal
|
||||||
|
return newFrame(asSubFrame, initPool) {
|
||||||
|
withEntryPoint(irFunction, irFunction.fileOrNull) {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun removeLastFrame() {
|
private fun removeLastFrame() {
|
||||||
if (frameList.size > 1 && getCurrentFrame().hasReturnValue()) frameList[frameList.lastIndex - 1].pushReturnValue(getCurrentFrame())
|
if (frameList.size > 1 && getCurrentFrame().hasReturnValue()) frameList[frameList.lastIndex - 1].pushReturnValue(getCurrentFrame())
|
||||||
frameList.removeAt(frameList.lastIndex)
|
frameList.removeAt(frameList.lastIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setCurrentFrameName(irFunction: IrFunction) {
|
override fun fixCallEntryPoint(irExpression: IrExpression) {
|
||||||
val fileName = irFunction.file.name
|
val fileEntry = getCurrentFrame().entryPoint?.irFile?.fileEntry ?: return
|
||||||
val fileNameCapitalized = irFunction.getCapitalizedFileName()
|
val lineNum = fileEntry.getLineNumber(irExpression.startOffset) + 1
|
||||||
val lineNum = irFunction.fileEntry.getLineNumber(irFunction.startOffset) + 1
|
getCurrentFrame().entryPoint?.lineNumber = lineNum
|
||||||
if (getCurrentFrame().frameEntryPoint == null)
|
}
|
||||||
getCurrentFrame().frameEntryPoint = "at $fileNameCapitalized.${irFunction.fqNameWhenAvailable}($fileName:$lineNum)"
|
|
||||||
|
// TODO remove method and create EntryPoint in frame constructor
|
||||||
|
override fun withEntryPoint(irFunction: IrFunction?, irFile: IrFile?, block: () -> ExecutionResult): ExecutionResult {
|
||||||
|
val frame = getCurrentFrame()
|
||||||
|
if (frame.entryPoint == null && irFile != null) frame.entryPoint = FrameContainer.Companion.EntryPoint(irFunction, irFile)
|
||||||
|
return block()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStackTrace(): List<String> {
|
override fun getStackTrace(): List<String> {
|
||||||
// TODO implement some sort of cache
|
// TODO implement some sort of cache
|
||||||
return frameList.mapNotNull { it.frameEntryPoint }
|
return frameList.map { it.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStackCount(): Int = stackCount
|
override fun getStackCount(): Int = stackCount
|
||||||
@@ -121,10 +138,16 @@ internal class StackImpl : Stack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class FrameContainer(current: Frame = InterpreterFrame()) {
|
private class FrameContainer(current: Frame = InterpreterFrame()) {
|
||||||
var frameEntryPoint: String? = null
|
var entryPoint: EntryPoint? = null
|
||||||
private val innerStack = mutableListOf(current)
|
private val innerStack = mutableListOf(current)
|
||||||
private fun getTopFrame() = innerStack.first()
|
private fun getTopFrame() = innerStack.first()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
class EntryPoint(val irFunction: IrFunction?, val irFile: IrFile) {
|
||||||
|
var lineNumber: Int = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun addSubFrame(frame: Frame) {
|
fun addSubFrame(frame: Frame) {
|
||||||
innerStack.add(0, frame)
|
innerStack.add(0, frame)
|
||||||
}
|
}
|
||||||
@@ -149,5 +172,10 @@ private class FrameContainer(current: Frame = InterpreterFrame()) {
|
|||||||
fun popReturnValue() = getTopFrame().popReturnValue()
|
fun popReturnValue() = getTopFrame().popReturnValue()
|
||||||
fun peekReturnValue() = getTopFrame().peekReturnValue()
|
fun peekReturnValue() = getTopFrame().peekReturnValue()
|
||||||
|
|
||||||
override fun toString() = frameEntryPoint ?: "Not defined"
|
override fun toString(): String {
|
||||||
|
entryPoint?.irFile ?: return "Not defined"
|
||||||
|
val fileNameCapitalized = entryPoint!!.irFile.name.replace(".kt", "Kt").capitalize()
|
||||||
|
val lineNum = if (entryPoint?.lineNumber != -1) ":${entryPoint?.lineNumber}" else ""
|
||||||
|
return "at $fileNameCapitalized.${entryPoint?.irFunction?.fqNameWhenAvailable ?: "<clinit>"}(${entryPoint!!.irFile.name}$lineNum)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user