Add simple handler for StackOverflowError in ir interpreter

This commit is contained in:
Ivan Kylchik
2020-08-07 21:27:00 +03:00
committed by TeamCityServer
parent f3d7dc5f22
commit 6a483a8464
2 changed files with 10 additions and 1 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.name.Name
import java.lang.invoke.MethodHandle import java.lang.invoke.MethodHandle
private const val MAX_COMMANDS = 500_000 private const val MAX_COMMANDS = 500_000
private const val MAX_STACK = 500
class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSignature, IrBody> = emptyMap()) { class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map<IdSignature, IrBody> = emptyMap()) {
private val irExceptions = mutableListOf<IrClass>() private val irExceptions = mutableListOf<IrClass>()
@@ -82,7 +83,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map
} }
else -> TODO("$returnLabel not supported as result of interpretation") else -> TODO("$returnLabel not supported as result of interpretation")
} }
} catch (e: InterpreterException) { } catch (e: Throwable) {
// TODO don't handle, throw to lowering // TODO don't handle, throw to lowering
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + e.message) IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + e.message)
} }
@@ -142,6 +143,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map
// 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 (irFunction.fileOrNull != null) stack.setCurrentFrameName(irFunction) if (irFunction.fileOrNull != null) stack.setCurrentFrameName(irFunction)
if (irFunction.body is IrSyntheticBody) return handleIntrinsicMethods(irFunction) if (irFunction.body is IrSyntheticBody) return handleIntrinsicMethods(irFunction)
@@ -22,6 +22,7 @@ internal interface Stack {
fun setCurrentFrameName(irFunction: IrFunction) fun setCurrentFrameName(irFunction: IrFunction)
fun getStackTrace(): List<String> fun getStackTrace(): List<String>
fun getStackCount(): Int
fun clean() fun clean()
fun addVar(variable: Variable) fun addVar(variable: Variable)
@@ -39,6 +40,7 @@ internal interface Stack {
internal class StackImpl : Stack { internal class StackImpl : Stack {
private val frameList = mutableListOf(FrameContainer()) // first frame is default, it is easier to work when last() is not null private val frameList = mutableListOf(FrameContainer()) // first frame is default, it is easier to work when last() is not null
private fun getCurrentFrame() = frameList.last() private fun getCurrentFrame() = frameList.last()
private var stackCount = 0
override fun newFrame(asSubFrame: Boolean, initPool: List<Variable>, block: () -> ExecutionResult): ExecutionResult { override fun newFrame(asSubFrame: Boolean, initPool: List<Variable>, block: () -> ExecutionResult): ExecutionResult {
val typeArgumentsPool = initPool.filter { it.symbol is IrTypeParameterSymbol } val typeArgumentsPool = initPool.filter { it.symbol is IrTypeParameterSymbol }
@@ -47,8 +49,10 @@ internal class StackImpl : Stack {
if (asSubFrame) getCurrentFrame().addSubFrame(newFrame) else frameList.add(FrameContainer(newFrame)) if (asSubFrame) getCurrentFrame().addSubFrame(newFrame) else frameList.add(FrameContainer(newFrame))
return try { return try {
stackCount++
block() block()
} finally { } finally {
stackCount--
if (asSubFrame) getCurrentFrame().removeSubFrame() else removeLastFrame() if (asSubFrame) getCurrentFrame().removeSubFrame() else removeLastFrame()
} }
} }
@@ -71,7 +75,10 @@ internal class StackImpl : Stack {
return frameList.mapNotNull { it.frameEntryPoint } return frameList.mapNotNull { it.frameEntryPoint }
} }
override fun getStackCount(): Int = stackCount
override fun clean() { override fun clean() {
stackCount = 0
frameList.clear() frameList.clear()
frameList.add(FrameContainer()) frameList.add(FrameContainer())
} }