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 b4af541ccd9..3fdeab26dac 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 @@ -7,20 +7,18 @@ package org.jetbrains.kotlin.backend.common.interpreter import org.jetbrains.kotlin.backend.common.interpreter.stack.* import org.jetbrains.kotlin.builtins.DefaultBuiltIns -import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.util.isFakeOverride import org.jetbrains.kotlin.ir.util.statements import org.jetbrains.kotlin.ir.visitors.IrElementVisitor class IrInterpreter : IrElementVisitor { private val builtIns = DefaultBuiltIns.Instance - private val unit = Complex(builtIns.unit, mutableListOf()) - private val any = Complex(builtIns.any, mutableListOf()) + private val empty = EmptyState() fun interpret(expression: IrExpression): IrExpression { return visitExpression(expression, InterpreterFrame()).convertToIrExpression(expression) @@ -50,26 +48,28 @@ class IrInterpreter : IrElementVisitor { } override fun visitCall(expression: IrCall, data: Frame): State { - val newFrame = InterpreterFrame() // it is important firstly to add receiver, then arguments + val newFrame = InterpreterFrame() val valueParameters = convertValueParameters(expression, data) - if (expression.symbol.owner.isFakeOverride) { - expression.dispatchReceiver?.accept(this, data)?.let { newFrame.addVar(it) } - newFrame.addAll(valueParameters) - return calculateOverridden(expression.symbol, newFrame) - } + val dispatchReceiver = expression.dispatchReceiver?.accept(this, data) // can be either Primitive or Complex + val extensionReceiver = expression.extensionReceiver?.accept(this, data) // similarly - val dispatchReceiver = expression.dispatchReceiver?.accept(this, data) - ?.setDescriptor(expression.symbol.descriptor.dispatchReceiverParameter!!) - val extensionReceiver = expression.extensionReceiver?.accept(this, data) - ?.setDescriptor(expression.symbol.descriptor.extensionReceiverParameter!!) - (dispatchReceiver ?: extensionReceiver)?.also { newFrame.addVar(it) } + // it is important firstly to add receiver, then arguments + val receiverParameter = (expression.symbol.descriptor.dispatchReceiverParameter ?: expression.symbol.descriptor.extensionReceiverParameter) + when (val receiver = (dispatchReceiver ?: extensionReceiver)) { + // if receiver is complex then frame will contain receiver and its supers as raw list (not tree) + // this is necessary because it is hard to instantly say that receiver will be used; for example, in abstract methods + is Complex -> newFrame.addAll(receiver.getAllStates()) + else -> receiver?.let { newFrame.addVar(Variable(receiverParameter!!, it)) } + } newFrame.addAll(valueParameters) - return if (expression.getBody() == null) { - calculateBuiltIns(expression.symbol.descriptor, newFrame).toIrConst(expression).toPrimitive() - } else { - expression.getBody()!!.accept(this, newFrame) + val irFunction = (dispatchReceiver as? Complex)?.getIrFunctionByName(expression.symbol.descriptor.name) + return when { + expression.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be first + expression.isFakeOverridden() -> calculateOverridden(irFunction!!.symbol, newFrame) + expression.getBody() == null -> calculateBuiltIns(expression.symbol.descriptor, newFrame).toIrConst(expression).toPrimitive() + else -> expression.getBody()!!.accept(this, newFrame) } } @@ -79,12 +79,16 @@ class IrInterpreter : IrElementVisitor { private fun visitConstructor(constructor: IrFunctionAccessExpression, data: Frame): State { val newFrame = InterpreterFrame(convertValueParameters(constructor, data)) - val obj = Complex((constructor.symbol.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter, mutableListOf()) + val obj = Complex(constructor.symbol.owner.parent as IrClass, mutableListOf()) constructor.getBody()?.statements?.forEach { when (it) { is IrDelegatingConstructorCall -> { - obj.addSuperQualifier(visitDelegatingConstructorCall(it, newFrame) as Complex) - newFrame.addVar(obj) + val delegatingConstructorCall = visitDelegatingConstructorCall(it, newFrame) + if (delegatingConstructorCall != empty) { + val superObj = Variable(it.symbol.descriptor.containingDeclaration.thisAsReceiverParameter, delegatingConstructorCall) + obj.addSuperQualifier(superObj) + } + newFrame.addVar(Variable(constructor.getThisAsReceiver(), obj)) } else -> it.accept(this, newFrame) } @@ -98,7 +102,7 @@ class IrInterpreter : IrElementVisitor { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Frame): State { if (expression.symbol.descriptor.containingDeclaration.defaultType == builtIns.anyType) { - return any + return empty } return visitConstructor(expression, data) @@ -113,7 +117,7 @@ class IrInterpreter : IrElementVisitor { } // unreachable state; method must return inside forEach - return unit + return empty } override fun visitReturn(expression: IrReturn, data: Frame): State { @@ -121,37 +125,37 @@ class IrInterpreter : IrElementVisitor { } override fun visitSetField(expression: IrSetField, data: Frame): State { - val value = expression.value.accept(this, data).setDescriptor(expression.symbol.owner.descriptor) + val value = expression.value.accept(this, data) val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor - data.getVar(receiver).setState(value) - return unit + data.getVariableState(receiver).setState(Variable(expression.symbol.owner.descriptor, value)) + return empty } override fun visitGetField(expression: IrGetField, data: Frame): State { val receiver = (expression.receiver as? IrDeclarationReference)?.symbol?.descriptor // receiver is null, for example, for top level fields ?: return expression.symbol.owner.initializer!!.expression.accept(this, data) - return data.getVar(receiver).getState(expression.symbol.descriptor).copy() + return data.getVariableState(receiver).getState(expression.symbol.descriptor).copy() } override fun visitGetValue(expression: IrGetValue, data: Frame): State { - return data.getVar(expression.symbol.descriptor).copy() + return data.getVariableState(expression.symbol.descriptor).copy() } override fun visitVariable(declaration: IrVariable, data: Frame): State { - val variable = declaration.initializer?.accept(this, data)?.setDescriptor(declaration.descriptor) - variable?.let { data.addVar(it) } - return unit + val variable = declaration.initializer?.accept(this, data) + variable?.let { data.addVar(Variable(declaration.descriptor, it)) } + return empty } override fun visitSetVariable(expression: IrSetVariable, data: Frame): State { if (data.contains(expression.symbol.descriptor)) { - val variable = data.getVar(expression.symbol.descriptor) - variable.setState(expression.value.accept(this, data)) + val variable = data.getVariableState(expression.symbol.descriptor) + variable.setState(Variable(expression.symbol.descriptor, expression.value.accept(this, data))) } else { - val variable = expression.value.accept(this, data).setDescriptor(expression.symbol.descriptor) - data.addVar(variable) + val variable = expression.value.accept(this, data) + data.addVar(Variable(expression.symbol.descriptor, variable)) } - return unit + return empty } override fun visitWhen(expression: IrWhen, data: Frame): State { @@ -160,6 +164,6 @@ class IrInterpreter : IrElementVisitor { return it.result.accept(this, data) } } - return unit + return empty } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt index 13f2bedaee2..374a25ead53 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt @@ -8,26 +8,27 @@ package org.jetbrains.kotlin.backend.common.interpreter import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction import org.jetbrains.kotlin.backend.common.interpreter.builtins.binaryFunctions import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions -import org.jetbrains.kotlin.backend.common.interpreter.stack.Frame -import org.jetbrains.kotlin.backend.common.interpreter.stack.InterpreterFrame -import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive -import org.jetbrains.kotlin.backend.common.interpreter.stack.State +import org.jetbrains.kotlin.backend.common.interpreter.stack.* import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.util.isFakeOverride import org.jetbrains.kotlin.types.TypeUtils fun IrInterpreter.calculateOverridden(symbol: IrFunctionSymbol, data: Frame): State { val owner = symbol.owner as IrFunctionImpl val overridden = owner.overriddenSymbols.first() - val overriddenReceiver = data.getVar(symbol.getThisAsReceiver()).getState(overridden.getThisAsReceiver()) + val overriddenReceiver = data.getVariableState(symbol.getThisAsReceiver()).getState(overridden.getThisAsReceiver()) val valueParameters = symbol.owner.valueParameters.zip(overridden.owner.valueParameters) - .map { data.getVar(it.first.descriptor).setDescriptor(it.second.descriptor) } - val newStates = InterpreterFrame((valueParameters + overriddenReceiver).toMutableList()) + .map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) } + val newStates = InterpreterFrame((valueParameters + Variable(overridden.getThisAsReceiver(), overriddenReceiver)).toMutableList()) return if (overridden.owner.body != null) { overridden.owner.body!!.accept(this, newStates) @@ -41,6 +42,7 @@ fun calculateBuiltIns(descriptor: FunctionDescriptor, frame: Frame): Any { val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) } val argsValues = frame.getAll() + .map { it.state } .map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") } .map { it.getIrConst().value } val signature = CompileTimeFunction(methodName, argsType.map { it.toString() }) @@ -59,11 +61,15 @@ fun calculateBuiltIns(descriptor: FunctionDescriptor, frame: Frame): Any { } } -fun IrInterpreter.convertValueParameters(memberAccess: IrMemberAccessExpression, data: Frame): MutableList { - return mutableListOf().apply { +fun IrInterpreter.calculateAbstract(irFunction: IrFunction?, data: Frame): State { + return irFunction?.body?.accept(this, data)!! +} + +fun IrInterpreter.convertValueParameters(memberAccess: IrMemberAccessExpression, data: Frame): MutableList { + return mutableListOf().apply { for (i in 0 until memberAccess.valueArgumentsCount) { val arg = memberAccess.getValueArgument(i)?.accept(this@convertValueParameters, data) - arg?.setDescriptor((memberAccess.symbol.descriptor as FunctionDescriptor).valueParameters[i])?.let { this += it } + arg?.let { add(Variable((memberAccess.symbol.descriptor as FunctionDescriptor).valueParameters[i], it)) } } } } @@ -72,10 +78,22 @@ fun IrFunctionSymbol.getThisAsReceiver(): ReceiverParameterDescriptor { return (this.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter } +fun IrFunctionAccessExpression.getThisAsReceiver(): ReceiverParameterDescriptor { + return (this.symbol.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter +} + fun IrFunctionAccessExpression.getBody(): IrBody? { return this.symbol.owner.body } +fun IrCall.isAbstract(): Boolean { + return (this.symbol.owner as? IrSimpleFunction)?.modality == Modality.ABSTRACT +} + +fun IrCall.isFakeOverridden(): Boolean { + return this.symbol.owner.isFakeOverride +} + fun Any?.toIrConst(expression: IrExpression): IrConst<*> { return when (this) { is Boolean -> expression.copyParametersTo(IrConstKind.Boolean, this) 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 ec1b3966c4a..47d35c5dda5 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 @@ -6,35 +6,46 @@ package org.jetbrains.kotlin.backend.common.interpreter.stack import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import java.util.NoSuchElementException +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import java.util.* + +data class Variable(val descriptor: DeclarationDescriptor, val state: State) { + override fun toString(): String { + val descriptorName = when (descriptor) { + is ReceiverParameterDescriptor -> descriptor.containingDeclaration.name.toString() + "::this" + else -> descriptor.name + } + return "Variable(descriptor=$descriptorName, state=$state)" + } +} interface Frame { - fun addVar(state: State) - fun addAll(states: List) - fun getVar(descriptor: DeclarationDescriptor): State - fun getAll(): List + fun addVar(variable: Variable) + fun addAll(variables: List) + fun getVariableState(variableDescriptor: DeclarationDescriptor): State + fun getAll(): List fun contains(descriptor: DeclarationDescriptor): Boolean } -class InterpreterFrame(val pool: MutableList = mutableListOf()) : Frame { - override fun addVar(state: State) { - pool.add(state) +class InterpreterFrame(val pool: MutableList = mutableListOf()) : Frame { + override fun addVar(variable: Variable) { + pool.add(variable) } - override fun addAll(states: List) { - pool.addAll(states) + override fun addAll(variables: List) { + pool.addAll(variables) } - override fun getVar(descriptor: DeclarationDescriptor): State { - return pool.firstOrNull { it.isTypeOf(descriptor) } - ?: throw NoSuchElementException("Frame pool doesn't contains variable with descriptor $descriptor") + override fun getVariableState(variableDescriptor: DeclarationDescriptor): State { + return pool.firstOrNull { it.descriptor == variableDescriptor }?.state + ?: throw NoSuchElementException("Frame pool doesn't contains variable with descriptor $variableDescriptor") } - override fun getAll(): List { + override fun getAll(): List { return pool } override fun contains(descriptor: DeclarationDescriptor): Boolean { - return pool.any { it.isTypeOf(descriptor) } + return pool.any { it.descriptor == descriptor } } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt index 4cc13ed4e49..31fa5d1283e 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt @@ -6,100 +6,100 @@ package org.jetbrains.kotlin.backend.common.interpreter.stack import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization +import org.jetbrains.kotlin.name.Name +import java.util.* interface State { fun getState(descriptor: DeclarationDescriptor): State - fun setState(newState: State) - fun getDescriptor(): DeclarationDescriptor - fun setDescriptor(descriptor: DeclarationDescriptor): State - fun isTypeOf(descriptor: DeclarationDescriptor): Boolean + fun setState(newVar: Variable) fun copy(): State } class Primitive(private var value: IrConst) : State { - private lateinit var declarationDescriptor: DeclarationDescriptor - - constructor(descriptor: DeclarationDescriptor, value: IrConst) : this(value) { - declarationDescriptor = descriptor - } - fun getIrConst(): IrConst { return value } override fun getState(descriptor: DeclarationDescriptor): State { - return when (descriptor) { - this.declarationDescriptor -> this - else -> throw IllegalAccessException("Can't get descriptor $descriptor from $this") - } + throw UnsupportedOperationException("Only complex are allowed") } - override fun setState(newState: State) { - newState as? Primitive ?: throw IllegalArgumentException("Cannot set $newState in current $this") - value = newState.value - } - - override fun getDescriptor(): DeclarationDescriptor { - return declarationDescriptor - } - - override fun setDescriptor(descriptor: DeclarationDescriptor): State { - declarationDescriptor = descriptor - return this - } - - override fun isTypeOf(descriptor: DeclarationDescriptor): Boolean { - return declarationDescriptor == descriptor + 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(declarationDescriptor, value) + return Primitive(value) } override fun toString(): String { - return "Primitive(varName='${declarationDescriptor.name}', value=${value.value})" + return "Primitive(value=${value.value})" } } -class Complex(private var declarationDescriptor: DeclarationDescriptor, private val values: MutableList) : State { - private val superQualifiers = mutableListOf() +class Complex(private var classOfObject: IrClass, private val values: MutableList) : State { + fun addSuperQualifier(superObj: Variable) { + val superTypesList = getSuperTypes(classOfObject).map { it.descriptor.thisAsReceiverParameter } + (superObj.state as? Complex)?.values?.filter { superTypesList.contains(it.descriptor) }?.let { values += it } + values += superObj + } - public fun addSuperQualifier(superObj: Complex) { - superQualifiers += superObj.superQualifiers - superQualifiers += superObj + private fun getSuperTypes(descriptor: IrClass): List { + val superTypesList = descriptor.superTypes.mapNotNull { it.classOrNull }.toMutableList() + return superTypesList + superTypesList.flatMap { getSuperTypes(it.owner) } + } + + fun getIrFunctionByName(name: Name): IrFunction { + return classOfObject.declarations.firstOrNull { it.descriptor.name == name } as? IrFunction + ?: throw NoSuchMethodException("Abstract method $name has not been implemented") + } + + fun getAllStates(): List { + val superTypesList = getSuperTypes(classOfObject).map { it.descriptor.thisAsReceiverParameter } + return values.filter { superTypesList.contains(it.descriptor) } + Variable(classOfObject.descriptor.thisAsReceiverParameter, this) } override fun getState(descriptor: DeclarationDescriptor): State { - return (values + superQualifiers).first { it.getDescriptor() == descriptor } + return values.firstOrNull { it.descriptor == descriptor }?.state + ?: throw NoSuchElementException("Complex object doesn't contains state with descriptor $descriptor") } - override fun setState(newState: State) { - val oldState = values.firstOrNull { it.getDescriptor() == newState.getDescriptor() } - if (oldState == null) { - values.add(newState) - } else { - values[values.indexOf(oldState)] = newState + override fun setState(newVar: Variable) { + when (val oldState = values.firstOrNull { it.descriptor == newVar.descriptor }) { + null -> values.add(newVar) // newVar isn't present in value list + else -> values[values.indexOf(oldState)] = newVar // newVar already present } } - override fun getDescriptor(): DeclarationDescriptor { - return declarationDescriptor - } - - override fun setDescriptor(descriptor: DeclarationDescriptor): State { - declarationDescriptor = descriptor - return this - } - - override fun isTypeOf(descriptor: DeclarationDescriptor): Boolean { - return (superQualifiers + this).any { it.declarationDescriptor == descriptor } - } - override fun copy(): State { - return Complex(declarationDescriptor, values).apply { this.superQualifiers += this@Complex.superQualifiers } + return Complex(classOfObject, values) } override fun toString(): String { - return "Complex(obj='$declarationDescriptor', super=$superQualifiers, values=$values)" + return "Complex(obj='${classOfObject.fqNameForIrSerialization}', values=$values)" + } +} + +class EmptyState : State { + override fun getState(descriptor: DeclarationDescriptor): State { + throw UnsupportedOperationException("Get state is not supported in empty state object") + } + + override fun setState(newVar: Variable) { + throw UnsupportedOperationException("Set state is not supported in empty state object") + } + + override fun copy(): State { + throw UnsupportedOperationException("Copy method is not supported in empty state object") + } + + override fun toString(): String { + return "EmptyState" } } \ No newline at end of file