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 3272cbdde4e..8b72a402da2 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 @@ -8,26 +8,75 @@ 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.* +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrConst -import org.jetbrains.kotlin.ir.expressions.IrConstKind -import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrConstructor +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.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.util.isFakeOverride +import org.jetbrains.kotlin.ir.util.statements import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.types.TypeUtils -class IrInterpreter : IrElementVisitor { +class IrInterpreter : IrElementVisitor { + private val unit = Complex(null, emptyList()) + fun interpret(expression: IrExpression): IrExpression { - return visitExpression(expression, null) + return visitExpression(expression, InterpreterFrame()).toIrExpression() } - private fun calculateBuiltIns(descriptor: FunctionDescriptor, args: List): Any { + private fun State.toIrExpression(): IrExpression { + return when (this) { + is Primitive<*> -> this.getIrConst() + else -> TODO("not supported") + } + } + + private fun IrElement?.getState(descriptor: DeclarationDescriptor, data: Frame): State? { + val arg = this?.accept(this@IrInterpreter, data) ?: return null + return arg.setDescriptor(descriptor) + } + + private fun IrMemberAccessExpression.convertValueParameters(data: Frame): MutableList { + val state = mutableListOf() + for (i in 0 until this.valueArgumentsCount) { + this.getValueArgument(i).getState(this.symbol.descriptor.valueParameters[i], data)?.let { state += it } + } + return state + } + + private fun IrFunctionSymbol.caclOverridden(states: List): State { + val owner = this.owner as IrFunctionImpl + val overridden = owner.overriddenSymbols.first() + val newStates = states.first { it.getDescriptor() == this.descriptor.containingDeclaration }.getState().toMutableList() + + return if (overridden.owner.body != null) { + val temp = newStates.first { it.getDescriptor() == overridden.descriptor.containingDeclaration } + overridden.owner.body!!.accept(this@IrInterpreter, InterpreterFrame(mutableListOf(temp))) + } else { + overridden.caclOverridden(newStates) + } + } + + private fun IrFunctionAccessExpression.getBody(): IrBody? { + return this.symbol.owner.body + } + + private fun calculateBuiltIns(descriptor: FunctionDescriptor, frame: Frame): Any { val methodName = descriptor.name.asString() val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) } - val argsValues = args.map { (it as? IrConst<*>)?.value ?: throw IllegalArgumentException("Builtin functions accept only const args") } + val argsValues = frame.getAll() + .map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") } + .map { it.getIrConst().value } val signature = CompileTimeFunction(methodName, argsType.map { it.toString() }) return when (argsType.size) { 1 -> { @@ -59,30 +108,97 @@ class IrInterpreter : IrElementVisitor { } } - override fun visitElement(element: IrElement, data: Nothing?): IrExpression { + private fun IrConst.toPrimitive(): Primitive { + return Primitive(this) + } + + override fun visitElement(element: IrElement, data: Frame): State { return when (element) { is IrCall -> visitCall(element, data) - else -> TODO("not supported") + is IrConstructor -> visitConstructor(element, data) + is IrDelegatingConstructorCall -> visitDelegatingConstructorCall(element, data) + is IrBody -> visitStatements(element.statements, data) + is IrBlock -> visitStatements(element.statements, data) + is IrSetField -> visitSetField(element, data) + is IrGetField -> visitGetField(element, data) + is IrGetValue -> visitGetValue(element, data) + else -> TODO("${element.javaClass} not supported") } } - override fun visitCall(expression: IrCall, data: Nothing?): IrExpression { + override fun visitCall(expression: IrCall, data: Frame): State { val dispatchReceiver = expression.dispatchReceiver?.accept(this, data) val extensionReceiver = expression.extensionReceiver?.accept(this, data) - val receiverValue = dispatchReceiver ?: extensionReceiver - val args = mutableListOf() - for (i in 0 until expression.valueArgumentsCount) { - expression.getValueArgument(i)?.accept(this, data)?.also { args += it } - } + val newFrame = InterpreterFrame(expression.convertValueParameters(data)) + (dispatchReceiver ?: extensionReceiver)?.also { newFrame.addVar(it) } - if (expression.symbol.owner.body == null) { - return calculateBuiltIns(expression.symbol.descriptor, args + listOfNotNull(receiverValue)).toIrConst(expression) + return if (expression.getBody() == null) { + if (expression.symbol.owner.isFakeOverride) { + return expression.symbol.caclOverridden(newFrame.getAll()) + } + calculateBuiltIns(expression.symbol.descriptor, newFrame).toIrConst(expression).toPrimitive() + } else { + expression.getBody()!!.accept(this, newFrame) } - - return super.visitCall(expression, data) } - override fun visitConst(expression: IrConst, data: Nothing?): IrExpression { - return expression + override fun visitConst(expression: IrConst, data: Frame): State { + return Primitive(expression) } -} \ No newline at end of file + + override fun visitConstructorCall(expression: IrConstructorCall, data: Frame): State { + val newFrame = InterpreterFrame(expression.convertValueParameters(data)) + val state = expression.getBody()?.accept(this, newFrame) ?: unit + return Complex(expression.symbol.descriptor.containingDeclaration, state.getState()) + } + + override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Frame): State { + if (expression.symbol.descriptor.containingDeclaration.classId?.asString() == "kotlin/Any") { + return unit + } + + val newFrame = InterpreterFrame(expression.convertValueParameters(data)) + val state = expression.getBody()?.accept(this, newFrame) ?: unit + return Complex(expression.symbol.descriptor.containingDeclaration, state.getState()) + } + + private fun visitStatements(statements: List, data: Frame): State { + val state = mutableListOf() + statements.forEach { + when (it) { + is IrReturn -> return visitReturn(it, data) + else -> state += it.accept(this, data) + } + } + + state.removeIf { it == unit } + return when (state.size) { + 0 -> unit + 1 -> state.first() + else -> Complex(null, state) + } + } + + override fun visitReturn(expression: IrReturn, data: Frame): State { + return expression.value.accept(this, data) + } + + override fun visitSetField(expression: IrSetField, data: Frame): State { + val value = expression.value.accept(this, data) + return value.setDescriptor(expression.symbol.owner.descriptor) + } + + override fun visitGetField(expression: IrGetField, data: Frame): State { + return data.getVar(expression.symbol.descriptor.containingDeclaration) + .getState() + .first { it.getDescriptor() == expression.descriptor } + .copy() + } + + override fun visitGetValue(expression: IrGetValue, data: Frame): State { + if (expression.symbol.descriptor is ReceiverParameterDescriptor) { + return data.getVar(expression.symbol.descriptor.containingDeclaration).copy() + } + return data.getVar(expression.symbol.descriptor).copy() + } +} 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 new file mode 100644 index 00000000000..c73878e0d9c --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Frame.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2019 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.backend.common.interpreter.stack + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import java.util.NoSuchElementException + +interface Frame { + fun addVar(state: State) + fun getVar(descriptor: DeclarationDescriptor): State + fun getAll(): List +} + +class InterpreterFrame(val pool: MutableList = mutableListOf()) : Frame { + override fun addVar(state: State) { + pool.add(state) + } + + override fun getVar(descriptor: DeclarationDescriptor): State { + return pool.firstOrNull { it.getDescriptor() == descriptor } + ?: throw NoSuchElementException("Frame pool doesn't contains variable with descriptor $descriptor") + } + + override fun getAll(): List { + return pool + } +} 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 deleted file mode 100644 index 1ab3c2d2ae7..00000000000 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/Stack.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2010-2019 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.backend.common.interpreter.stack - -interface Stack { - fun pushFrame(frame: Frame) - fun popFrame(): Frame - fun peekFrame(): Frame -} - -interface Frame { - fun addVar(state: State) - fun getVar(name: String): State -} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/StackImpl.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/StackImpl.kt deleted file mode 100644 index cfc468bb5b8..00000000000 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/StackImpl.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2010-2019 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.backend.common.interpreter.stack - -import java.util.NoSuchElementException - -class StackImpl : Stack { - private val stack: MutableList = mutableListOf() - - override fun pushFrame(frame: Frame) { - stack.add(frame) - } - - override fun popFrame(): Frame { - if (stack.isEmpty()) { - throw IndexOutOfBoundsException("Stack is empty") - } - return stack.removeAt(stack.size - 1) - } - - override fun peekFrame(): Frame { - if (stack.isEmpty()) { - throw IndexOutOfBoundsException("Stack is empty") - } - return stack.get(stack.size - 1) - } -} - -class InterpreterFrame : Frame { - val pool: MutableList = mutableListOf() - - override fun addVar(state: State) { - pool.add(state) - } - - override fun getVar(name: String): State { - return pool.firstOrNull { it.getName() == name } - ?: throw NoSuchElementException("Frame pool doesn't contains variable with name $name") - } -} 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 aaa753169ab..49d457b297a 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 @@ -5,28 +5,67 @@ package org.jetbrains.kotlin.backend.common.interpreter.stack +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.ir.expressions.IrConst interface State { fun getState(): List - fun getName(): String + fun getDescriptor(): DeclarationDescriptor? + fun setDescriptor(descriptor: DeclarationDescriptor): State + fun copy(): State } -class Primitive(public val varName: String, public val value: IrConst) : State { +class Primitive(private val value: IrConst) : State { + private lateinit var declarationDescriptor: DeclarationDescriptor + + private constructor(descriptor: DeclarationDescriptor, value: IrConst) : this(value) { + declarationDescriptor = descriptor + } + override fun getState(): List { return listOf(this) } - override fun getName(): String { - return varName + override fun getDescriptor(): DeclarationDescriptor? { + return declarationDescriptor + } + + override fun setDescriptor(descriptor: DeclarationDescriptor): State { + declarationDescriptor = descriptor + return this + } + + override fun copy(): State { + return Primitive(declarationDescriptor, value) + } + + public fun getIrConst(): IrConst { + return value + } + + override fun toString(): String { + return "Primitive(varName='${declarationDescriptor.name}', value=${value.value})" } } -class Complex(public val objName: String, public val values: List) : State { +class Complex(private var declarationDescriptor: DeclarationDescriptor?, private val values: List) : State { override fun getState(): List { return values } - override fun getName(): String { - return objName + override fun getDescriptor(): DeclarationDescriptor? { + return declarationDescriptor + } + + override fun setDescriptor(descriptor: DeclarationDescriptor): State { + declarationDescriptor = descriptor + return this + } + + override fun copy(): State { + return Complex(declarationDescriptor, values) + } + + override fun toString(): String { + return "Complex(objName='${declarationDescriptor?.name}', values=$values)" } } \ No newline at end of file