Add configuration into IrInterpreterEnvironment

This configuration will contains all necessary setting for interpreter
and will be replenished over time
This commit is contained in:
Ivan Kylchik
2021-06-10 16:31:47 +03:00
committed by TeamCityServer
parent b150cc9537
commit cc56acc2c2
4 changed files with 38 additions and 23 deletions
@@ -80,7 +80,7 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn
}
private fun unfoldFunction(function: IrSimpleFunction, environment: IrInterpreterEnvironment) {
if (environment.callStack.getStackCount() >= IrInterpreterEnvironment.MAX_STACK)
if (environment.callStack.getStackCount() >= environment.configuration.maxStack)
return StackOverflowError().handleUserException(environment)
// SimpleInstruction with function is added in IrCall
// It will serve as endpoint for all possible calls, there we drop frame and copy result to new one
@@ -39,9 +39,7 @@ internal class CustomInstruction(val evaluate: () -> Unit) : Instruction {
get() = null
}
class IrInterpreter private constructor(
internal val bodyMap: Map<IdSignature, IrBody>, internal val environment: IrInterpreterEnvironment
) {
class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal val bodyMap: Map<IdSignature, IrBody>) {
val irBuiltIns: IrBuiltIns
get() = environment.irBuiltIns
private val callStack: CallStack
@@ -50,16 +48,13 @@ class IrInterpreter private constructor(
private var commandCount = 0
constructor(irBuiltIns: IrBuiltIns, bodyMap: Map<IdSignature, IrBody> = emptyMap()) :
this(bodyMap, IrInterpreterEnvironment(irBuiltIns, CallStack()))
this(IrInterpreterEnvironment(irBuiltIns), bodyMap)
private constructor(environment: IrInterpreterEnvironment, bodyMap: Map<IdSignature, IrBody> = emptyMap()) :
this(bodyMap, environment)
constructor(irModule: IrModuleFragment) : this(emptyMap(), IrInterpreterEnvironment(irModule))
constructor(irModule: IrModuleFragment) : this(IrInterpreterEnvironment(irModule), emptyMap())
private fun incrementAndCheckCommands() {
commandCount++
if (commandCount >= IrInterpreterEnvironment.MAX_COMMANDS) InterpreterTimeOutError().handleUserException(environment)
if (commandCount >= environment.configuration.maxCommands) InterpreterTimeOutError().handleUserException(environment)
}
private fun getUnitState(): State = environment.mapOfObjects[irBuiltIns.unitClass]!!
@@ -395,8 +390,9 @@ class IrInterpreter private constructor(
environment.mapOfObjects[objectClass.symbol] = state // must set object's state here to avoid cyclic evaluation
callStack.addVariable(Variable(objectClass.thisReceiver!!.symbol, state))
// non compile time objects can be used in interpreter, for example, to evaluate const properties
if (!objectClass.hasAnnotation(compileTimeAnnotation)) return@interceptGetObjectValue callStack.pushState(state)
// non compile time objects can be used in interpreter, for example, to evaluate const properties or in tests
if (!objectClass.hasAnnotation(compileTimeAnnotation) && !environment.configuration.createNonCompileTimeObjects)
return@interceptGetObjectValue callStack.pushState(state)
val constructor = objectClass.constructors.firstOrNull() ?: return@interceptGetObjectValue callStack.pushState(state)
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.interpreter
/**
* @param maxStack describes the maximum allowed call stack size
* @param maxCommands describes the maximum allowed number of simple instructions performed
* @param createNonCompileTimeObjects
* 'true' - interpreter will construct object and initialize its properties despite the fact it is not marked as compile time;
* 'false' - interpreter will create a representation of empty object, that can be used to get const properties
*/
// TODO maybe create some sort of builder
class IrInterpreterConfiguration(
val maxStack: Int = 10_000,
val maxCommands: Int = 1_000_000,
val createNonCompileTimeObjects: Boolean = false,
)
@@ -14,22 +14,26 @@ import org.jetbrains.kotlin.ir.interpreter.state.Complex
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.isSubclassOf
internal class IrInterpreterEnvironment(val irBuiltIns: IrBuiltIns, val callStack: CallStack) {
val irExceptions = mutableListOf<IrClass>()
var mapOfEnums = mutableMapOf<IrSymbol, Complex>()
var mapOfObjects = mutableMapOf<IrSymbol, Complex>()
class IrInterpreterEnvironment(
val irBuiltIns: IrBuiltIns,
val configuration: IrInterpreterConfiguration = IrInterpreterConfiguration(),
) {
internal val callStack: CallStack = CallStack()
internal val irExceptions = mutableListOf<IrClass>()
internal var mapOfEnums = mutableMapOf<IrSymbol, Complex>()
internal var mapOfObjects = mutableMapOf<IrSymbol, Complex>()
init {
mapOfObjects[irBuiltIns.unitClass] = Common(irBuiltIns.unitClass.owner)
}
private constructor(environment: IrInterpreterEnvironment) : this(environment.irBuiltIns, CallStack()) {
private constructor(environment: IrInterpreterEnvironment) : this(environment.irBuiltIns, configuration = environment.configuration) {
irExceptions.addAll(environment.irExceptions)
mapOfEnums = environment.mapOfEnums
mapOfObjects = environment.mapOfObjects
}
constructor(irModule: IrModuleFragment) : this(irModule.irBuiltins, CallStack()) {
constructor(irModule: IrModuleFragment) : this(irModule.irBuiltins) {
irExceptions.addAll(
irModule.files
.flatMap { it.declarations }
@@ -41,9 +45,4 @@ internal class IrInterpreterEnvironment(val irBuiltIns: IrBuiltIns, val callStac
fun copyWithNewCallStack(): IrInterpreterEnvironment {
return IrInterpreterEnvironment(this)
}
companion object {
const val MAX_STACK = 10_000
const val MAX_COMMANDS = 1_000_000
}
}