From 11e808715bb7f0a8f5f5a0a37da1de7b95cbca8c Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 7 Nov 2019 18:37:56 +0300 Subject: [PATCH] Rethink main goal of stack frame --- .../common/interpreter/IrInterpreter.kt | 121 ++++++++---------- .../backend/common/interpreter/Utils.kt | 40 ++++++ .../backend/common/interpreter/stack/Frame.kt | 2 +- .../backend/common/interpreter/stack/State.kt | 68 +++++++--- 4 files changed, 146 insertions(+), 85 deletions(-) create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt 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 8b72a402da2..6503ccf120d 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 @@ -9,9 +9,10 @@ import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunct 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.descriptors.ClassDescriptor 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.IrStatement import org.jetbrains.kotlin.ir.declarations.IrConstructor @@ -19,7 +20,6 @@ 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 @@ -27,7 +27,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.types.TypeUtils class IrInterpreter : IrElementVisitor { - private val unit = Complex(null, emptyList()) + private val builtIns = DefaultBuiltIns.Instance + private val unit = Complex(builtIns.unit, mutableListOf()) + private val any = Complex(builtIns.any, mutableListOf()) fun interpret(expression: IrExpression): IrExpression { return visitExpression(expression, InterpreterFrame()).toIrExpression() @@ -39,7 +41,7 @@ class IrInterpreter : IrElementVisitor { else -> TODO("not supported") } } - + //todo move out util methods private fun IrElement?.getState(descriptor: DeclarationDescriptor, data: Frame): State? { val arg = this?.accept(this@IrInterpreter, data) ?: return null return arg.setDescriptor(descriptor) @@ -48,28 +50,26 @@ class IrInterpreter : IrElementVisitor { 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 } + this.getValueArgument(i).getState((this.symbol.descriptor as FunctionDescriptor).valueParameters[i], data)?.let { state += it } } return state } - private fun IrFunctionSymbol.caclOverridden(states: List): State { - val owner = this.owner as IrFunctionImpl + private fun calculateOverridden(symbol: IrFunctionSymbol, data: Frame): State { + val owner = symbol.owner as IrFunctionImpl val overridden = owner.overriddenSymbols.first() - val newStates = states.first { it.getDescriptor() == this.descriptor.containingDeclaration }.getState().toMutableList() + val overriddenReceiver = data.getVar(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()) return if (overridden.owner.body != null) { - val temp = newStates.first { it.getDescriptor() == overridden.descriptor.containingDeclaration } - overridden.owner.body!!.accept(this@IrInterpreter, InterpreterFrame(mutableListOf(temp))) + overridden.owner.body!!.accept(this@IrInterpreter, newStates) } else { - overridden.caclOverridden(newStates) + calculateOverridden(overridden.owner.symbol, 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 @@ -87,31 +87,12 @@ class IrInterpreter : IrElementVisitor { 2 -> { val function = binaryFunctions[signature] ?: throw NoSuchMethodException("For given function $signature there is no entry in binary map") - function.invoke(argsValues[0], argsValues[1]) + function.invoke(argsValues[1], argsValues[0]) } else -> throw UnsupportedOperationException("Unsupported number of arguments") } } - private fun Any.toIrConst(expression: IrExpression): IrConst<*> { - return when (this) { - is Boolean -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Boolean, this) - is Char -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Char, this) - is Byte -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Byte, this) - is Short -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Short, this) - is Int -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Int, this) - is Long -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Long, this) - is String -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.String, this) - is Float -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Float, this) - is Double -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Double, this) - else -> throw UnsupportedOperationException("Unsupported const element type $this") - } - } - - private fun IrConst.toPrimitive(): Primitive { - return Primitive(this) - } - override fun visitElement(element: IrElement, data: Frame): State { return when (element) { is IrCall -> visitCall(element, data) @@ -127,15 +108,19 @@ class IrInterpreter : IrElementVisitor { } override fun visitCall(expression: IrCall, data: Frame): State { - val dispatchReceiver = expression.dispatchReceiver?.accept(this, data) - val extensionReceiver = expression.extensionReceiver?.accept(this, data) val newFrame = InterpreterFrame(expression.convertValueParameters(data)) + if (expression.symbol.owner.isFakeOverride) { + expression.dispatchReceiver?.accept(this, data)?.let { newFrame.addVar(it) } + return calculateOverridden(expression.symbol, newFrame) + } + + val dispatchReceiver = expression.dispatchReceiver?.accept(this, data) + ?.setDescriptor(expression.symbol.descriptor.dispatchReceiverParameter!!) + val extensionReceiver = expression.extensionReceiver?.accept(this, data) + ?.setDescriptor(expression.symbol.descriptor.extensionReceiverParameter?.containingDeclaration!!) (dispatchReceiver ?: extensionReceiver)?.also { newFrame.addVar(it) } 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) @@ -143,40 +128,45 @@ class IrInterpreter : IrElementVisitor { } override fun visitConst(expression: IrConst, data: Frame): State { - return Primitive(expression) + return expression.toPrimitive() + } + + private fun visitConstructor(constructor: IrFunctionAccessExpression, data: Frame): State { + val newFrame = InterpreterFrame(constructor.convertValueParameters(data)) + val obj = Complex((constructor.symbol.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter, mutableListOf()) + constructor.getBody()?.statements?.forEach { + when (it) { + is IrDelegatingConstructorCall -> { + obj.addSuperQualifier(visitDelegatingConstructorCall(it, newFrame) as Complex) + newFrame.addVar(obj) + } + else -> it.accept(this, newFrame) + } + } + return obj } 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()) + return visitConstructor(expression, data) } override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Frame): State { - if (expression.symbol.descriptor.containingDeclaration.classId?.asString() == "kotlin/Any") { - return unit + if (expression.symbol.descriptor.containingDeclaration.defaultType == builtIns.anyType) { + return any } - val newFrame = InterpreterFrame(expression.convertValueParameters(data)) - val state = expression.getBody()?.accept(this, newFrame) ?: unit - return Complex(expression.symbol.descriptor.containingDeclaration, state.getState()) + return visitConstructor(expression, data) } 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) + is IrReturn -> return it.accept(this, data) + else -> it.accept(this, data) } } - state.removeIf { it == unit } - return when (state.size) { - 0 -> unit - 1 -> state.first() - else -> Complex(null, state) - } + return unit } override fun visitReturn(expression: IrReturn, data: Frame): State { @@ -184,21 +174,18 @@ class IrInterpreter : IrElementVisitor { } override fun visitSetField(expression: IrSetField, data: Frame): State { - val value = expression.value.accept(this, data) - return value.setDescriptor(expression.symbol.owner.descriptor) + val value = expression.value.accept(this, data).setDescriptor(expression.symbol.owner.descriptor) + val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor + data.getVar(receiver).setState(value) + return unit } override fun visitGetField(expression: IrGetField, data: Frame): State { - return data.getVar(expression.symbol.descriptor.containingDeclaration) - .getState() - .first { it.getDescriptor() == expression.descriptor } - .copy() + val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor + return data.getVar(receiver).getState(expression.symbol.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/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt new file mode 100644 index 00000000000..709ab08b206 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt @@ -0,0 +1,40 @@ +/* + * 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 + +import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl +import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol + +fun IrFunctionSymbol.getThisAsReceiver(): ReceiverParameterDescriptor { + return (this.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter +} + +fun IrFunctionAccessExpression.getBody(): IrBody? { + return this.symbol.owner.body +} + +fun Any.toIrConst(expression: IrExpression): IrConst<*> { + return when (this) { + is Boolean -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Boolean, this) + is Char -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Char, this) + is Byte -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Byte, this) + is Short -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Short, this) + is Int -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Int, this) + is Long -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Long, this) + is String -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.String, this) + is Float -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Float, this) + is Double -> IrConstImpl(expression.startOffset, expression.endOffset, expression.type, IrConstKind.Double, this) + else -> throw UnsupportedOperationException("Unsupported const element type $this") + } +} + +fun IrConst.toPrimitive(): Primitive { + return Primitive(this) +} \ No newline at end of file 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 c73878e0d9c..2924c6a63cb 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 @@ -20,7 +20,7 @@ class InterpreterFrame(val pool: MutableList = mutableListOf()) : Frame { } override fun getVar(descriptor: DeclarationDescriptor): State { - return pool.firstOrNull { it.getDescriptor() == descriptor } + return pool.firstOrNull { it.isTypeOf(descriptor) } ?: throw NoSuchElementException("Frame pool doesn't contains variable with 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 49d457b297a..4cc13ed4e49 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,24 +9,38 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.ir.expressions.IrConst interface State { - fun getState(): List - fun getDescriptor(): DeclarationDescriptor? + fun getState(descriptor: DeclarationDescriptor): State + fun setState(newState: State) + fun getDescriptor(): DeclarationDescriptor fun setDescriptor(descriptor: DeclarationDescriptor): State + fun isTypeOf(descriptor: DeclarationDescriptor): Boolean fun copy(): State } -class Primitive(private val value: IrConst) : State { +class Primitive(private var value: IrConst) : State { private lateinit var declarationDescriptor: DeclarationDescriptor - private constructor(descriptor: DeclarationDescriptor, value: IrConst) : this(value) { + constructor(descriptor: DeclarationDescriptor, value: IrConst) : this(value) { declarationDescriptor = descriptor } - override fun getState(): List { - return listOf(this) + fun getIrConst(): IrConst { + return value } - override fun getDescriptor(): DeclarationDescriptor? { + override fun getState(descriptor: DeclarationDescriptor): State { + return when (descriptor) { + this.declarationDescriptor -> this + else -> throw IllegalAccessException("Can't get descriptor $descriptor from $this") + } + } + + 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 } @@ -35,24 +49,40 @@ class Primitive(private val value: IrConst) : State { return this } + override fun isTypeOf(descriptor: DeclarationDescriptor): Boolean { + return declarationDescriptor == descriptor + } + 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(private var declarationDescriptor: DeclarationDescriptor?, private val values: List) : State { - override fun getState(): List { - return values +class Complex(private var declarationDescriptor: DeclarationDescriptor, private val values: MutableList) : State { + private val superQualifiers = mutableListOf() + + public fun addSuperQualifier(superObj: Complex) { + superQualifiers += superObj.superQualifiers + superQualifiers += superObj } - override fun getDescriptor(): DeclarationDescriptor? { + override fun getState(descriptor: DeclarationDescriptor): State { + return (values + superQualifiers).first { it.getDescriptor() == 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 getDescriptor(): DeclarationDescriptor { return declarationDescriptor } @@ -61,11 +91,15 @@ class Complex(private var declarationDescriptor: DeclarationDescriptor?, private return this } + override fun isTypeOf(descriptor: DeclarationDescriptor): Boolean { + return (superQualifiers + this).any { it.declarationDescriptor == descriptor } + } + override fun copy(): State { - return Complex(declarationDescriptor, values) + return Complex(declarationDescriptor, values).apply { this.superQualifiers += this@Complex.superQualifiers } } override fun toString(): String { - return "Complex(objName='${declarationDescriptor?.name}', values=$values)" + return "Complex(obj='$declarationDescriptor', super=$superQualifiers, values=$values)" } } \ No newline at end of file