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 36da3be3479..800f2eccde0 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 @@ -5,172 +5,343 @@ 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.builtins.DefaultBuiltIns 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.IrVariable +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl +import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.statements -import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.types.TypeUtils -class IrInterpreter : IrElementVisitor { - private val builtIns = DefaultBuiltIns.Instance - private val empty = EmptyState() +enum class Code(var info: String = "") { + NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION +} - fun interpret(expression: IrExpression): IrExpression { - return visitExpression(expression, InterpreterFrame()).toIrExpression(expression) - } +fun interpret(expression: IrExpression): IrExpression { + return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(expression) +} - override fun visitElement(element: IrElement, data: Frame): State { - return when (element) { - is IrCall -> visitCall(element, data) - is IrConstructorCall -> 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) - is IrGetObjectValue -> visitGetObjectValue(element, data) - is IrConst<*> -> visitConst(element, data) - is IrWhen -> visitWhen(element, data) - else -> TODO("${element.javaClass} not supported") +fun IrElement.interpret(data: Frame): Code { + try { + val code = when (this) { + is IrCall -> this.interpretCall(data) + is IrConstructorCall -> this.interpretConstructorCall(data) + is IrDelegatingConstructorCall -> this.interpretDelegatedConstructorCall(data) + is IrBody -> this.interpretBody(data) + is IrBlock -> this.interpretBlock(data) + is IrReturn -> this.interpretReturn(data) + is IrSetField -> this.interpretSetField(data) + is IrGetField -> this.interpretGetField(data) + is IrGetValue -> this.interpretGetValue(data) + is IrGetObjectValue -> this.interpretGetObjectValue(data) + is IrConst<*> -> this.interpretConst(data) + is IrVariable -> this.interpretVariable(data) + is IrSetVariable -> this.interpretSetVariable(data) + is IrTypeOperatorCall -> this.interpretTypeOperatorCall(data) + is IrBranch -> this.interpretBranch(data) + is IrWhileLoop -> this.interpretWhile(data) + is IrWhen -> this.interpretWhen(data) + is IrBreak -> this.interpretBreak(data) + + else -> TODO("${this.javaClass} not supported") } - } - override fun visitCall(expression: IrCall, data: Frame): State { - val newFrame = InterpreterFrame() - val valueParameters = convertValueParameters(expression, data) - - val dispatchReceiver = expression.dispatchReceiver?.accept(this, data) // can be either Primitive or Complex - val extensionReceiver = expression.extensionReceiver?.accept(this, data) // similarly - - val irFunction = dispatchReceiver.getIrFunction(expression) - // it is important firstly to add receiver, then arguments - val receiverParameter = irFunction.symbol.getReceiverDescriptor() - val receiver = (dispatchReceiver ?: extensionReceiver) - receiver?.let { newFrame.addVar(Variable(receiverParameter!!, it)) } - newFrame.addAll(valueParameters) - - return when { - expression.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be first - expression.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame) - expression.getBody() == null -> calculateBuiltIns(expression, newFrame).toState(expression) - else -> (irFunction.body ?: expression.getBody())!!.accept(this, newFrame) - } - } - - override fun visitConst(expression: IrConst, data: Frame): State { - return expression.toPrimitive() - } - - private fun visitConstructor(constructor: IrFunctionAccessExpression, data: Frame): State { - val newFrame = InterpreterFrame(convertValueParameters(constructor, data)) - val obj = Complex(constructor.symbol.owner.parent as IrClass, mutableListOf()) - constructor.getBody()?.statements?.forEach { - when (it) { - is IrDelegatingConstructorCall -> { - val delegatingConstructorCall = visitDelegatingConstructorCall(it, newFrame) - if (delegatingConstructorCall != empty) { - val superObj = Variable(it.getThisAsReceiver(), delegatingConstructorCall) - obj.addSuperQualifier(superObj) - } - newFrame.addVar(Variable(constructor.getThisAsReceiver(), obj)) - } - else -> it.accept(this, newFrame) + return when (code) { + Code.RETURN -> when (this) { + is IrCall -> Code.NEXT + else -> Code.RETURN } - } - return obj - } - - override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Frame): State { - if (expression.symbol.descriptor.containingDeclaration.defaultType == builtIns.anyType) { - return empty - } - - return visitConstructor(expression, data) - } - - private fun visitStatements(statements: List, data: Frame): State { - statements.forEachIndexed { index, statement -> - when { - statement is IrReturn || index == statements.lastIndex -> return statement.accept(this, data) - else -> statement.accept(this, data) + Code.BREAK_WHEN -> when (this) { + is IrWhen -> Code.NEXT + else -> code } - } - - // unreachable state; method must return inside forEach - return empty - } - - 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) - val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor - 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 receiver?.let { data.getVariableState(receiver).getState(expression.symbol.descriptor)?.copy() } - ?: expression.symbol.owner.initializer!!.expression.accept(this, data) - } - - override fun visitGetValue(expression: IrGetValue, data: Frame): State { - return data.getVariableState(expression.symbol.descriptor).copy() - } - - override fun visitVariable(declaration: IrVariable, data: Frame): State { - 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.getVariableState(expression.symbol.descriptor) - variable.setState(Variable(expression.symbol.descriptor, expression.value.accept(this, data))) - } else { - val variable = expression.value.accept(this, data) - data.addVar(Variable(expression.symbol.descriptor, variable)) - } - return empty - } - - override fun visitWhen(expression: IrWhen, data: Frame): State { - expression.branches.forEach { - if ((it.condition.accept(this, data) as? Primitive<*>)?.getIrConst()?.value == true) { - return it.result.accept(this, data) + Code.BREAK_LOOP -> when (this) { + is IrWhileLoop -> if ((this.label ?: "") == code.info) Code.NEXT else code + else -> code } + Code.CONTINUE -> TODO("Code.CONTINUE not implemented") + Code.EXCEPTION -> TODO("Code.EXCEPTION not implemented") + Code.NEXT -> Code.NEXT } - return empty - } - - override fun visitGetObjectValue(expression: IrGetObjectValue, data: Frame): State { - return Complex(expression.symbol.owner, mutableListOf()) - } - - override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Frame): State { - when (expression.operator) { - IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { - expression.argument.accept(this, data) - return empty - } - else -> TODO("${expression.operator} not implemented") - } - } - - override fun visitWhileLoop(loop: IrWhileLoop, data: Frame): State { - while ((loop.condition.accept(this, data) as? Primitive<*>)?.getIrConst()?.value == true) { - loop.body?.accept(this, InterpreterFrame(data.getAll().toMutableList())) - } - return empty + } catch (e: Exception) { + e.printStackTrace() + assert(false) + return Code.EXCEPTION } } + +private fun calculateAbstract(irFunction: IrFunction, data: Frame): Code { + return irFunction.body?.interpret(data) + ?: throw NoSuchMethodException("Method \"${irFunction.name}\" wasn't implemented") +} + +private fun calculateOverridden(owner: IrFunctionImpl, data: Frame): Code { + val variableDescriptor = owner.symbol.getThisAsReceiver()!! + val superQualifier = (data.getVariableState(variableDescriptor) as Complex).getSuperQualifier()!! + val overridden = owner.overriddenSymbols.first { it.getThisAsReceiver()?.equalTo(superQualifier.getThisReceiver()) == true } + + val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters) + .map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) } + val newStates = InterpreterFrame((valueParameters + Variable(superQualifier.getThisReceiver(), superQualifier)).toMutableList()) + + val overriddenOwner = overridden.owner as IrFunctionImpl + val body = overriddenOwner.body + return when { + body != null -> body.interpret(newStates) + else -> calculateOverridden(overriddenOwner, newStates) + }.apply { data.pushReturnValue(newStates) } +} + +private fun isBuiltIn(irFunction: IrFunction): Boolean { + val descriptor = irFunction.descriptor + 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 signature = CompileTimeFunction( + methodName, + argsType.map { it.toString() }) + return (unaryFunctions[signature] ?: binaryFunctions[signature]) != null +} + +private fun calculateBuiltIns(expression: IrCall, data: Frame): Code { + val descriptor = expression.symbol.descriptor + 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 = data.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() }) + //todo try catch + val result = when (argsType.size) { + 1 -> { + val function = unaryFunctions[signature] + ?: throw NoSuchMethodException("For given function $signature there is no entry in unary map") + function.invoke(argsValues.first()) + } + 2 -> { + val function = binaryFunctions[signature] + ?: throw NoSuchMethodException("For given function $signature there is no entry in binary map") + when (methodName) { + "rangeTo" -> return calculateRangeTo(expression, data) + else -> function.invoke(argsValues[0], argsValues[1]) + } + } + else -> throw UnsupportedOperationException("Unsupported number of arguments") + } + data.pushReturnValue(result.toState(expression)) + return Code.NEXT +} + +private fun calculateRangeTo(expression: IrExpression, data: Frame): Code { + val constructor = expression.type.classOrNull!!.owner.constructors.first() + val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) + + val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> } + primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getIrConst()) } + + val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters) + val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList()) + + val code = constructorCall.interpret(newFrame) + data.pushReturnValue(newFrame) + return code +} + +fun IrMemberAccessExpression.interpretValueParameters(data: Frame): Code { + for (i in (this.valueArgumentsCount - 1) downTo 0) { + val code = this.getValueArgument(i)?.interpret(data) ?: Code.NEXT + if (code != Code.NEXT) return code + } + return Code.NEXT +} + +fun IrCall.interpretCall(data: Frame): Code { + val newFrame = InterpreterFrame() + + this.interpretValueParameters(data).also { if (it != Code.NEXT) return it } + val valueParameters = this.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) } + + val rawReceiver = this.dispatchReceiver ?: this.extensionReceiver + rawReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it } + + val receiver = rawReceiver?.let { data.popReturnValue() } + val irFunction = receiver.getIrFunction(this) + val receiverParameter = irFunction.symbol.getThisAsReceiver() + // it is important firstly to add receiver, then arguments + receiver?.let { newFrame.addVar(Variable(receiverParameter!!, it)) } + newFrame.addAll(valueParameters) + + val code = when { + //irFunction.annotations.any { it.descriptor.containingDeclaration.fqNameSafe == evaluateIntrinsicAnnotation } -> empty + isBuiltIn(irFunction) -> calculateBuiltIns(this, newFrame) + this.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check + this.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame) + else -> (irFunction.body ?: this.getBody())!!.interpret(newFrame) + } + data.pushReturnValue(newFrame) + return code +} + +fun IrFunctionAccessExpression.interpretConstructor(data: Frame): Code { + this.interpretValueParameters(data).also { if (it != Code.NEXT) return it } + val valueParameters = this.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList() + + val newFrame = InterpreterFrame(valueParameters) + val state = Complex(this.symbol.owner.parent as IrClass, mutableListOf()) + newFrame.addVar(Variable(this.getThisAsReceiver(), state)) //used to set up fields in body + val code = this.getBody()?.interpret(newFrame) ?: Code.NEXT + if (newFrame.hasReturnValue()) { + state.setSuperQualifier(newFrame.popReturnValue() as Complex) + } + data.pushReturnValue(state) + return code +} + +fun IrConstructorCall.interpretConstructorCall(data: Frame): Code { + return this.interpretConstructor(data) +} + +fun IrDelegatingConstructorCall.interpretDelegatedConstructorCall(data: Frame): Code { + if (this.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) { + return Code.NEXT + } + + return this.interpretConstructor(data) +} + +fun IrConst<*>.interpretConst(data: Frame): Code { + data.pushReturnValue(this.toPrimitive()) + return Code.NEXT +} + +fun List.interpretStatements(data: Frame): Code { + //create newFrame + val newFrame = data.copy() + + var code = Code.NEXT + val iterator = this.asSequence().iterator() + while (code == Code.NEXT && iterator.hasNext()) { + code = iterator.next().interpret(newFrame) + } + data.pushReturnValue(newFrame) + return code +} + +fun IrBlock.interpretBlock(data: Frame): Code { + return this.statements.interpretStatements(data) +} + +fun IrBody.interpretBody(data: Frame): Code { + return this.statements.interpretStatements(data) +} + +fun IrReturn.interpretReturn(data: Frame): Code { + val code = this.value.interpret(data) + return if (code == Code.NEXT) Code.RETURN else code +} + +fun IrWhileLoop.interpretWhile(data: Frame): Code { + var code = Code.NEXT + while (code == Code.NEXT) { + code = this.condition.interpret(data) + if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) { + code = this.body?.interpret(data) ?: Code.NEXT + } else { + break + } + } + return code +} + +fun IrWhen.interpretWhen(data: Frame): Code { + var code = Code.NEXT + val iterator = this.branches.asSequence().iterator() + while (code == Code.NEXT && iterator.hasNext()) { + code = iterator.next().interpret(data) + } + return code +} + +fun IrBranch.interpretBranch(data: Frame): Code { + var code = this.condition.interpret(data) + if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) { + code = this.result.interpret(data) + if (code == Code.NEXT) return Code.BREAK_WHEN + } + return code +} + +fun IrBreak.interpretBreak(data: Frame): Code { + return Code.BREAK_LOOP.apply { info = this@interpretBreak.label ?: "" } +} + +fun IrSetField.interpretSetField(data: Frame): Code { + val code = this.value.interpret(data) + if (code != Code.NEXT) return code + + val receiver = (this.receiver as IrDeclarationReference).symbol.descriptor + data.getVariableState(receiver).setState(Variable(this.symbol.owner.descriptor, data.popReturnValue())) + return Code.NEXT +} + +fun IrGetField.interpretGetField(data: Frame): Code { + val receiver = (this.receiver as? IrDeclarationReference)?.symbol?.descriptor // receiver is null, for example, for top level fields + val result = receiver?.let { data.getVariableState(receiver).getState(this.symbol.descriptor)?.copy() } + if (result == null) { + return this.symbol.owner.initializer?.expression?.interpret(data) ?: Code.NEXT + } + data.pushReturnValue(result) + return Code.NEXT +} + +fun IrGetValue.interpretGetValue(data: Frame): Code { + data.pushReturnValue(data.getVariableState(this.symbol.descriptor).copy()) + return Code.NEXT +} + +fun IrVariable.interpretVariable(data: Frame): Code { + val code = this.initializer?.interpret(data) + if (code != Code.NEXT) return code ?: Code.NEXT + data.addVar(Variable(this.descriptor, data.popReturnValue())) + return Code.NEXT +} + +fun IrSetVariable.interpretSetVariable(data: Frame): Code { + val code = this.value.interpret(data) + if (code != Code.NEXT) return code + + if (data.contains(this.symbol.descriptor)) { + val variable = data.getVariableState(this.symbol.descriptor) + variable.setState(Variable(this.symbol.descriptor, data.popReturnValue())) + } else { + data.addVar(Variable(this.symbol.descriptor, data.popReturnValue())) + } + return Code.NEXT +} + +fun IrGetObjectValue.interpretGetObjectValue(data: Frame): Code { + data.pushReturnValue(Complex(this.symbol.owner, mutableListOf())) + return Code.NEXT +} + +fun IrTypeOperatorCall.interpretTypeOperatorCall(data: Frame): Code { + return when (this.operator) { + IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { + this.argument.interpret(data) + } + IrTypeOperator.CAST -> { + this.argument.interpret(data) //todo check cast correctness + } + else -> TODO("${this.operator} not implemented") + } +} \ No newline at end of file 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 7faa91551d9..0405c5b71e9 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 @@ -5,114 +5,35 @@ 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.backend.common.interpreter.stack.Complex +import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive +import org.jetbrains.kotlin.backend.common.interpreter.stack.State import org.jetbrains.kotlin.descriptors.* 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.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.types.classOrNull -import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.isFakeOverride import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf -fun IrInterpreter.calculateAbstract(irFunction: IrFunction?, data: Frame): State { - return irFunction?.body?.accept(this, data) - ?: throw NoSuchMethodException("Method \"$irFunction\" wasn't implemented") -} - -fun IrInterpreter.calculateOverridden(owner: IrFunctionImpl, data: Frame): State { - val overridden = owner.overriddenSymbols.first() - - val variableDescriptor = owner.symbol.getReceiverDescriptor()!! - val overriddenReceiver = overridden.getReceiverDescriptor()!! - val overriddenReceiverState = data.getVariableState(variableDescriptor).getState(overriddenReceiver) - ?: throw NoSuchElementException("Variable \"$variableDescriptor\" doesn't contains state \"$overriddenReceiver\"") - - val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters) - .map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) } - val newStates = InterpreterFrame((valueParameters + Variable(overriddenReceiver, overriddenReceiverState)).toMutableList()) - - var overriddenOwner: IrSimpleFunction? = overridden.owner - do { - val body = overriddenOwner?.body - when { - body != null -> return body.accept(this, newStates) - else -> overriddenOwner = overriddenOwner?.overriddenSymbols?.firstOrNull()?.owner - } - } while (overriddenOwner != null) - - throw NoSuchMethodException("$owner has no body") -} - -fun IrInterpreter.calculateBuiltIns(expression: IrCall, frame: Frame): Any { - val descriptor = expression.symbol.descriptor - 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 = 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() }) - return when (argsType.size) { - 1 -> { - val function = unaryFunctions[signature] - ?: throw NoSuchMethodException("For given function $signature there is no entry in unary map") - function.invoke(argsValues.first()) - } - 2 -> { - val function = binaryFunctions[signature] - ?: throw NoSuchMethodException("For given function $signature there is no entry in binary map") - when (methodName) { - "rangeTo" -> calculateRangeTo(expression, frame) - else -> function.invoke(argsValues[0], argsValues[1]) - } - } - else -> throw UnsupportedOperationException("Unsupported number of arguments") - } -} - -private fun IrInterpreter.calculateRangeTo(expression: IrExpression, data: Frame): Any { - val constructor = expression.type.classOrNull!!.owner.constructors.first() - val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) - - val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> } - primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getIrConst()) } - - val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters) - val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList()) - - return constructorCall.accept(this, newFrame) -} - -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?.let { add(Variable((memberAccess.symbol.descriptor as FunctionDescriptor).valueParameters[i], it)) } - } - } -} - // main purpose is to get receiver from constructor call -fun IrFunctionAccessExpression.getThisAsReceiver(): DeclarationDescriptor { +fun IrMemberAccessExpression.getThisAsReceiver(): DeclarationDescriptor { return (this.symbol.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter } -fun IrFunctionSymbol.getReceiverDescriptor(): DeclarationDescriptor? { - return this.owner.dispatchReceiverParameter?.descriptor ?: this.owner.extensionReceiverParameter?.descriptor +fun IrFunctionSymbol.getThisAsReceiver(): DeclarationDescriptor? { + return (this.descriptor.containingDeclaration as? ClassDescriptor)?.thisAsReceiverParameter + ?: this.owner.extensionReceiverParameter?.descriptor } +/*fun IrFunctionSymbol.getReceiverDescriptor(): DeclarationDescriptor? { + return this.owner.dispatchReceiverParameter?.descriptor ?: this.owner.extensionReceiverParameter?.descriptor +}*/ + fun IrFunctionAccessExpression.getBody(): IrBody? { return this.symbol.owner.body } @@ -143,7 +64,7 @@ fun IrCall.isFakeOverridden(): Boolean { } fun State?.getIrFunction(expression: IrCall): IrFunction { - return this.let { (it as? Complex)?.getIrFunctionByName(expression.symbol.descriptor.name) } ?: expression.symbol.owner + return this.let { it?.getIrFunctionByName(expression.symbol.descriptor.name) } ?: expression.symbol.owner } fun State.toIrExpression(expression: IrExpression): IrExpression { 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 f10be0a6334..92675aec81f 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 @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.backend.common.interpreter.stack import org.jetbrains.kotlin.backend.common.interpreter.equalTo import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor -import java.util.* +import kotlin.NoSuchElementException data class Variable(val descriptor: DeclarationDescriptor, val state: State) { override fun toString(): String { @@ -26,9 +26,19 @@ interface Frame { fun getVariableState(variableDescriptor: DeclarationDescriptor): State fun getAll(): List fun contains(descriptor: DeclarationDescriptor): Boolean + fun pushReturnValue(state: State) + fun pushReturnValue(frame: Frame) + fun peekReturnValue(): State + //fun peekReturnValueOrNull(): State? + fun popReturnValue(): State + //fun popReturnValueOrNull(): State? + fun hasReturnValue(): Boolean + fun copy(): Frame } class InterpreterFrame(val pool: MutableList = mutableListOf()) : Frame { + private val returnStack: MutableList = mutableListOf() + override fun addVar(variable: Variable) { pool.add(variable) } @@ -49,4 +59,36 @@ class InterpreterFrame(val pool: MutableList = mutableListOf()) : Fram override fun contains(descriptor: DeclarationDescriptor): Boolean { return pool.any { it.descriptor == descriptor } } + + override fun pushReturnValue(state: State) { + returnStack += state + } + + override fun pushReturnValue(frame: Frame) { + if (frame.hasReturnValue()) this.pushReturnValue(frame.popReturnValue()) + } + + override fun hasReturnValue(): Boolean { + return returnStack.isNotEmpty() + } + + override fun peekReturnValue(): State { + if (returnStack.isNotEmpty()) { + return returnStack.last() + } + throw NoSuchElementException("Return values stack is empty") + } + + override fun popReturnValue(): State { + if (returnStack.isNotEmpty()) { + val item = returnStack.last() + returnStack.removeAt(returnStack.size - 1) + return item + } + throw NoSuchElementException("Return values stack is empty") + } + + override fun copy(): Frame { + return InterpreterFrame(pool.toMutableList()) + } } 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 ebfe3dfd406..578b8ef046d 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 @@ -9,8 +9,8 @@ import org.jetbrains.kotlin.backend.common.interpreter.equalTo 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.declarations.IrProperty 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 @@ -19,6 +19,7 @@ interface State { fun getState(descriptor: DeclarationDescriptor): State? fun setState(newVar: Variable) fun copy(): State + fun getIrFunctionByName(name: Name): IrFunction? } class Primitive(private var value: IrConst) : State { @@ -39,24 +40,38 @@ class Primitive(private var value: IrConst) : State { return Primitive(value) } + override fun getIrFunctionByName(name: Name): IrFunction? { + //if (this.value.kind != IrConstKind.String) return null + val declarations = value.type.classOrNull!!.owner.declarations.flatMap { + when { + it is IrProperty -> listOf(it, it.getter) + else -> listOf(it) + } + } + return declarations.firstOrNull { it?.descriptor?.name == name } as? IrFunction + } + override fun toString(): String { return "Primitive(value=${value.value})" } } 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 + var superType: Complex? = null + + fun setSuperQualifier(superType: Complex) { + this.superType = superType } - private fun getSuperTypes(descriptor: IrClass): List { - val superTypesList = descriptor.superTypes.mapNotNull { it.classOrNull }.toMutableList() - return superTypesList + superTypesList.flatMap { getSuperTypes(it.owner) } + fun getSuperQualifier(): Complex? { + return superType } - fun getIrFunctionByName(name: Name): IrFunction? { + fun getThisReceiver(): DeclarationDescriptor { + return classOfObject.thisReceiver!!.descriptor + } + + override fun getIrFunctionByName(name: Name): IrFunction? { return classOfObject.declarations.filterIsInstance().firstOrNull { it.descriptor.name == name } } @@ -72,28 +87,10 @@ class Complex(private var classOfObject: IrClass, private val values: MutableLis } override fun copy(): State { - return Complex(classOfObject, values) + return Complex(classOfObject, values).apply { this@apply.superType = this@Complex.superType } } override fun toString(): String { - return "Complex(obj='${classOfObject.fqNameForIrSerialization}', values=$values)" + return "Complex(obj='${classOfObject.fqNameForIrSerialization}', super=$superType, 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