diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt index 19f1e910e27..4add67c5f30 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt @@ -59,7 +59,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map irBuiltIns.doubleType null -> irBuiltIns.nothingType else -> when (defaultType.classifierOrNull?.owner) { - is IrTypeParameter -> stack.getVariableState(defaultType.classifierOrFail.descriptor).irClass.defaultType + is IrTypeParameter -> stack.getVariable(defaultType.classifierOrFail.descriptor).state.irClass.defaultType else -> defaultType } } @@ -284,7 +284,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map ExecutionResult ): ExecutionResult { - val size = stack.getVariableState(irFunction.valueParameters.first().descriptor).asInt() + val size = stack.getVariable(irFunction.valueParameters.first().descriptor).state.asInt() val array = arrayOfNulls(size) stack.pushReturnValue(array.toState(irFunction.returnType)) return Next @@ -77,7 +77,7 @@ object EnumValues : IntrinsicBase() { irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult ): ExecutionResult { val enumClass = when (irFunction.fqNameWhenAvailable.toString()) { - "kotlin.enumValues" -> stack.getVariableState(irFunction.typeParameters.first().descriptor).irClass + "kotlin.enumValues" -> stack.getVariable(irFunction.typeParameters.first().descriptor).state.irClass else -> irFunction.parent as IrClass } @@ -98,10 +98,10 @@ object EnumValueOf : IntrinsicBase() { irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult ): ExecutionResult { val enumClass = when (irFunction.fqNameWhenAvailable.toString()) { - "kotlin.enumValueOf" -> stack.getVariableState(irFunction.typeParameters.first().descriptor).irClass + "kotlin.enumValueOf" -> stack.getVariable(irFunction.typeParameters.first().descriptor).state.irClass else -> irFunction.parent as IrClass } - val enumEntryName = stack.getVariableState(irFunction.valueParameters.first().descriptor).asString() + val enumEntryName = stack.getVariable(irFunction.valueParameters.first().descriptor).state.asString() val enumEntry = enumClass.declarations.filterIsInstance().singleOrNull { it.name.asString() == enumEntryName } enumEntry?.interpret()?.check { return it } ?: throw IllegalArgumentException("No enum constant ${enumClass.fqNameWhenAvailable}.$enumEntryName") @@ -160,12 +160,12 @@ object JsPrimitives : IntrinsicBase() { ): ExecutionResult { when (irFunction.fqNameWhenAvailable.toString()) { "kotlin.Long." -> { - val low = stack.getVariableState(irFunction.valueParameters[0].descriptor).asInt() - val high = stack.getVariableState(irFunction.valueParameters[1].descriptor).asInt() + val low = stack.getVariable(irFunction.valueParameters[0].descriptor).state.asInt() + val high = stack.getVariable(irFunction.valueParameters[1].descriptor).state.asInt() stack.pushReturnValue((high.toLong().shl(32) + low).toState(irFunction.returnType)) } "kotlin.Char." -> { - val value = stack.getVariableState(irFunction.valueParameters[0].descriptor).asInt() + val value = stack.getVariable(irFunction.valueParameters[0].descriptor).state.asInt() stack.pushReturnValue(value.toChar().toState(irFunction.returnType)) } } @@ -183,12 +183,12 @@ object ArrayConstructor : IntrinsicBase() { irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult ): ExecutionResult { val sizeDescriptor = irFunction.valueParameters[0].descriptor - val size = stack.getVariableState(sizeDescriptor).asInt() + val size = stack.getVariable(sizeDescriptor).state.asInt() val arrayValue = MutableList(size) { 0 } if (irFunction.valueParameters.size == 2) { val initDescriptor = irFunction.valueParameters[1].descriptor - val initLambda = stack.getVariableState(initDescriptor) as Lambda + val initLambda = stack.getVariable(initDescriptor).state as Lambda val index = initLambda.irFunction.valueParameters.single() for (i in 0 until size) { val indexVar = listOf(Variable(index.descriptor, i.toState(index.type))) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Frame.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Frame.kt index 787d0bce72d..5e21096e8e8 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Frame.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Frame.kt @@ -14,8 +14,7 @@ import kotlin.NoSuchElementException interface Frame { fun addVar(variable: Variable) fun addAll(variables: List) - fun getVariableState(variableDescriptor: DeclarationDescriptor): State - fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State? + fun getVariable(variableDescriptor: DeclarationDescriptor): Variable? fun getAll(): List fun contains(descriptor: DeclarationDescriptor): Boolean fun pushReturnValue(state: State) @@ -40,14 +39,9 @@ class InterpreterFrame( pool.addAll(variables) } - override fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State? { + override fun getVariable(variableDescriptor: DeclarationDescriptor): Variable? { return (if (variableDescriptor is TypeParameterDescriptor) typeArguments else pool) - .firstOrNull { it.descriptor.equalTo(variableDescriptor) }?.state - } - - override fun getVariableState(variableDescriptor: DeclarationDescriptor): State { - return tryGetVariableState(variableDescriptor) - ?: throw NoSuchElementException("Frame pool doesn't contains variable with descriptor $variableDescriptor") + .firstOrNull { it.descriptor.equalTo(variableDescriptor) } } override fun getAll(): List { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt index fbd737d629e..04e657c97b0 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt @@ -28,7 +28,7 @@ interface Stack { fun clean() fun addVar(variable: Variable) fun addAll(variables: List) - fun getVariableState(variableDescriptor: DeclarationDescriptor): State + fun getVariable(variableDescriptor: DeclarationDescriptor): Variable fun getAll(): List fun contains(descriptor: DeclarationDescriptor): Boolean @@ -86,8 +86,8 @@ class StackImpl : Stack { getCurrentFrame().addAll(variables) } - override fun getVariableState(variableDescriptor: DeclarationDescriptor): State { - return getCurrentFrame().getVariableState(variableDescriptor) + override fun getVariable(variableDescriptor: DeclarationDescriptor): Variable { + return getCurrentFrame().getVariable(variableDescriptor) } override fun getAll(): List { @@ -132,8 +132,8 @@ private class FrameContainer(current: Frame = InterpreterFrame()) { fun addVar(variable: Variable) = getTopFrame().addVar(variable) fun addAll(variables: List) = getTopFrame().addAll(variables) fun getAll() = innerStack.flatMap { it.getAll() } - fun getVariableState(variableDescriptor: DeclarationDescriptor): State { - return innerStack.firstNotNullResult { it.tryGetVariableState(variableDescriptor) } + fun getVariable(variableDescriptor: DeclarationDescriptor): Variable { + return innerStack.firstNotNullResult { it.getVariable(variableDescriptor) } ?: throw InterpreterException("$variableDescriptor not found") // TODO better message } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Variable.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Variable.kt index 50d7ea7a9b4..28514d0ca0a 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Variable.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Variable.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.backend.common.interpreter.state.State import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor -data class Variable(val descriptor: DeclarationDescriptor, val state: State) { +data class Variable(val descriptor: DeclarationDescriptor, var state: State) { override fun toString(): String { val descriptorName = when (descriptor) { is ReceiverParameterDescriptor -> descriptor.containingDeclaration.name.toString() + "::this" diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt index 3fa4490e590..16c575291cc 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Common.kt @@ -48,8 +48,6 @@ class Common private constructor( .let { getOverridden(it as IrSimpleFunction, this) } } - override fun copy() = Common(irClass, fields).copyFrom(this) - override fun toString(): String { return "Common(obj='${irClass.fqNameForIrSerialization}', super=$superClass, values=$fields)" } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt index a81d7ecacee..3abe4bd9736 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Complex.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.util.isInterface abstract class Complex(override val irClass: IrClass, override val fields: MutableList) : State { var superClass: Complex? = null var subClass: Complex? = null + val interfaces: MutableList = mutableListOf() // filled lazily, as needed val typeArguments: MutableList = mutableListOf() var outerClass: Variable? = null @@ -46,21 +47,6 @@ abstract class Complex(override val irClass: IrClass, override val fields: Mutab private fun contains(variable: Variable) = fields.any { it.descriptor == variable.descriptor } - override fun setState(newVar: Variable) { - when (val oldState = fields.firstOrNull { it.descriptor == newVar.descriptor }) { - null -> fields.add(newVar) // newVar isn't present in value list - else -> fields[fields.indexOf(oldState)] = newVar // newVar already present - } - } - - protected fun copyFrom(other: Complex): State { - this.superClass = other.superClass - this.subClass = other.subClass ?: other - this.typeArguments.addAll(other.typeArguments) - this.outerClass = other.outerClass - return this - } - private fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { val propertyGetters = irClass.declarations.filterIsInstance().mapNotNull { it.getter } val functions = irClass.declarations.filterIsInstance() @@ -70,10 +56,9 @@ abstract class Complex(override val irClass: IrClass, override val fields: Mutab private fun getThisOrSuperReceiver(superIrClass: IrClass?): Complex? { return when { superIrClass == null -> this.getOriginal() - superIrClass.isInterface -> { - val interfaceState = Common(superIrClass) - (this.copy() as Complex).setSuperClassInstance(interfaceState) - interfaceState + superIrClass.isInterface -> Common(superIrClass).apply { + interfaces.add(this) + this.subClass = this@Complex } else -> this.superClass } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/ExceptionState.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/ExceptionState.kt index 63b30b3e8bb..5dbbcefc4d5 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/ExceptionState.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/ExceptionState.kt @@ -80,11 +80,11 @@ class ExceptionState private constructor( } private fun setMessage(messageValue: String? = null) { - setState(Variable(messageProperty.descriptor, Primitive(messageValue, messageProperty.getter!!.returnType))) + setField(Variable(messageProperty.descriptor, Primitive(messageValue, messageProperty.getter!!.returnType))) } private fun setCause(causeValue: State?) { - setState(Variable(causeProperty.descriptor, causeValue ?: Primitive(null, causeProperty.getter!!.returnType))) + setField(Variable(causeProperty.descriptor, causeValue ?: Primitive(null, causeProperty.getter!!.returnType))) } fun getMessage(): Primitive = getState(messageProperty.descriptor) as Primitive @@ -105,8 +105,6 @@ class ExceptionState private constructor( fun getThisAsCauseForException() = ExceptionData(this) - override fun copy() = ExceptionState(irClass, fields, stackTrace).copyFrom(this) - companion object { private fun IrClass.getPropertyByName(name: String): IrProperty { val getPropertyFun = this.declarations.firstOrNull { it.nameForIrSerialization.asString().contains("get-$name") } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt index cc1d42259ce..0cfcd7c07fb 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt @@ -19,18 +19,10 @@ class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State // irFunction is anonymous declaration, but irCall will contain descriptor of invoke method from Function interface private val invokeDescriptor = irClass.declarations.single { it.nameForIrSerialization.asString() == "invoke" }.descriptor - override fun setState(newVar: Variable) { - throw UnsupportedOperationException("Method setState is not supported in Lambda class") - } - override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { return if (invokeDescriptor.equalTo(expression.symbol.descriptor)) irFunction else null } - override fun copy(): State { - return Lambda(irFunction, irClass).apply { this.fields.addAll(this@Lambda.fields) } - } - override fun toString(): String { val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.getFqName(true) val arguments = irFunction.valueParameters.map { it.type.getFqName(true) }.joinToString(prefix = "(", postfix = ")") diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Primitive.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Primitive.kt index 66465e7e472..52fd5484701 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Primitive.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Primitive.kt @@ -24,15 +24,6 @@ class Primitive(var value: T, val type: IrType) : State { return super.getState(descriptor) ?: this } - override fun setState(newVar: Variable) { - newVar.state as? Primitive ?: throw IllegalArgumentException("Cannot set $newVar in current $this") - value = newVar.state.value - } - - override fun copy(): State { - return Primitive(value, type) - } - override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { val descriptor = expression.symbol.descriptor // must add property's getter to declaration's list because they are not present in ir class for primitives diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/State.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/State.kt index 0e8b44f3e35..71aa8924d07 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/State.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/State.kt @@ -20,16 +20,12 @@ interface State { return fields.firstOrNull { it.descriptor.equalTo(descriptor) }?.state } - fun setState(newVar: Variable) - - /** - * This method is used for passing a copy of a state. - * It is necessary then copy change its state's value, but the original one must remain the same. - * - * @see copyReceivedValue.kt - * @see tryFinally.kt - */ - fun copy(): State + fun setField(newVar: Variable) { + when (val oldState = fields.firstOrNull { it.descriptor == newVar.descriptor }) { + null -> fields.add(newVar) // newVar isn't present in value list + else -> fields[fields.indexOf(oldState)].state = newVar.state // newVar already present + } + } fun getIrFunctionByIrCall(expression: IrCall): IrFunction? } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt index 8ed4d3b168d..e77958c5ae6 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt @@ -52,10 +52,6 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, return MethodHandles.lookup().findVirtual(receiverClass, methodName, methodType) } - override fun setState(newVar: Variable) { - throw UnsupportedOperationException("Method setState is not supported in Wrapper class") - } - // this method is used to get correct java method name // for example: - method 'get' in kotlin StringBuilder is actually 'charAt' in java StringBuilder // - method 'keys' in kotlin Map is actually 'keySet' in java @@ -194,8 +190,6 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, } } - override fun copy() = Wrapper(value, irClass).copyFrom(this) - override fun toString(): String { return "Wrapper(obj='$typeFqName', value=$value)" }