From 0c1f2edbf276b053136f2f9d8759fcb4fcc5a899 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Sun, 10 May 2020 21:05:46 +0300 Subject: [PATCH] Get rid of abstract and fake override checks in ir call interpretation For now interpreter will find necessary method for interpretation in one step instead of checking is this method abstract or fake override --- .../common/interpreter/IrInterpreter.kt | 59 ++----------------- .../backend/common/interpreter/Utils.kt | 51 +++++----------- .../intrinsics/IntrinsicImplementations.kt | 2 +- .../common/interpreter/state/Common.kt | 9 ++- .../common/interpreter/state/Complex.kt | 43 +++++++++++++- .../common/interpreter/state/Lambda.kt | 6 +- .../common/interpreter/state/Primitive.kt | 8 ++- .../backend/common/interpreter/state/State.kt | 4 +- 8 files changed, 81 insertions(+), 101 deletions(-) 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 27090690238..547735a50c1 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 @@ -164,51 +164,6 @@ class IrInterpreter(irModule: IrModuleFragment) { return IntrinsicEvaluator().evaluate(irFunction, stack) { this.interpret() } } - private suspend fun calculateAbstract(irFunction: IrFunction): ExecutionResult { - if (irFunction.body == null) { - val receiver = stack.getVariableState(irFunction.getReceiver()!!) as Complex - val instance = receiver.getOriginal() - - val functionImplementation = instance.getIrFunction(irFunction.descriptor) - if (functionImplementation?.body == null) throw InterpreterMethodNotFoundException("Method \"${irFunction.name}\" wasn't implemented") - - val valueArguments = mutableListOf() - valueArguments.add(Variable(functionImplementation.getReceiver()!!, instance)) - functionImplementation.valueParameters - .map { Variable(it.descriptor, stack.getVariableState(it.descriptor)) } - .forEach { valueArguments.add(it) } - return stack.newFrame(asSubFrame = true, initPool = valueArguments) { - functionImplementation.interpret() - } - } - return irFunction.body!!.interpret() - } - - private suspend fun calculateOverridden(owner: IrSimpleFunction): ExecutionResult { - val variableDescriptor = owner.getReceiver()!! - val superQualifier = (stack.getVariableState(variableDescriptor) as? Complex)?.superClass - if (superQualifier == null) { - // superQualifier is null for exception state => find method in builtins - return calculateBuiltIns(owner.getLastOverridden() as IrSimpleFunction) - } - val overridden = owner.overriddenSymbols.single() - - val valueArguments = mutableListOf() - valueArguments.add(Variable(overridden.owner.getReceiver()!!, superQualifier)) - owner.valueParameters.zip(overridden.owner.valueParameters) - .map { Variable(it.second.descriptor, stack.getVariableState(it.first.descriptor)) } - .forEach { valueArguments.add(it) } - - return stack.newFrame(asSubFrame = true, initPool = valueArguments) { - val overriddenOwner = overridden.owner - return@newFrame when { - overriddenOwner.body != null -> overriddenOwner.interpret() - superQualifier.superClass == null -> calculateBuiltIns(overriddenOwner) - else -> calculateOverridden(overriddenOwner) - } - } - } - private suspend fun calculateBuiltIns(irFunction: IrFunction): ExecutionResult { val descriptor = irFunction.descriptor val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) { @@ -286,7 +241,7 @@ class IrInterpreter(irModule: IrModuleFragment) { return stack.newFrame(asSubFrame = true, initPool = pool) { for (i in valueArguments.indices) { (valueArguments[i] ?: defaultValues[i])?.interpret()?.check { return@newFrame it } - ?: stack.pushReturnValue(listOf().toPrimitiveStateArray(expression.getVarargType(i)!!)) + ?: stack.pushReturnValue(listOf().toPrimitiveStateArray(expression.getVarargType(i)!!)) // if vararg is empty with(Variable(valueParametersDescriptors[i], stack.popReturnValue())) { stack.addVar(this) //must add value argument in current stack because it can be used later as default argument @@ -309,9 +264,9 @@ class IrInterpreter(irModule: IrModuleFragment) { rawExtensionReceiver?.interpret()?.check { return it } val extensionReceiver = rawExtensionReceiver?.let { stack.popReturnValue() } - // find correct ir function - val functionReceiver = dispatchReceiver?.getFunctionReceiver(expression.superQualifierSymbol?.owner) - val irFunction = functionReceiver?.getIrFunction(expression.symbol.descriptor) ?: expression.symbol.owner + // get correct ir function + val irFunction = dispatchReceiver?.getIrFunctionByIrCall(expression) ?: expression.symbol.owner + val functionReceiver = dispatchReceiver.getCorrectReceiverByFunction(irFunction) // it is important firstly to add receiver, then arguments; this order is used in builtin method call irFunction.getDispatchReceiver()?.let { functionReceiver?.let { receiver -> valueArguments.add(Variable(it, receiver)) } } @@ -332,9 +287,7 @@ class IrInterpreter(irModule: IrModuleFragment) { return@newFrame when { dispatchReceiver is Wrapper && !isInlineOnly -> dispatchReceiver.getMethod(irFunction).invokeMethod(irFunction) irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction) - irFunction.isAbstract() -> calculateAbstract(irFunction) //abstract check must be before fake overridden check - irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrSimpleFunction) - irFunction.body == null || dispatchReceiver is Primitive<*> -> calculateBuiltIns(irFunction) // is Primitive because of js char and long + irFunction.body == null || dispatchReceiver is Primitive<*> -> calculateBuiltIns(irFunction) // 'is Primitive' because of js char and long else -> irFunction.interpret() } } @@ -730,7 +683,7 @@ class IrInterpreter(irModule: IrModuleFragment) { is Common -> { val toStringFun = returnValue.getToStringFunction() stack.newFrame(initPool = mutableListOf(Variable(toStringFun.getReceiver()!!, returnValue))) { - toStringFun.body?.let { toStringFun.interpret() } ?: calculateOverridden(toStringFun) + toStringFun.body?.let { toStringFun.interpret() } ?: calculateBuiltIns(toStringFun) }.check { executionResult -> return executionResult } stack.popReturnValue().asString() } 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 eef2d262048..081aea44204 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 @@ -12,20 +12,15 @@ import org.jetbrains.kotlin.builtins.UnsignedTypes import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.descriptors.WrappedReceiverParameterDescriptor import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.types.* -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization -import org.jetbrains.kotlin.ir.util.isFakeOverride -import org.jetbrains.kotlin.ir.util.isInterface +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver -import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.utils.addToStdlib.safeAs // main purpose is to get receiver from constructor call @@ -50,7 +45,7 @@ fun IrFunctionAccessExpression.getBody(): IrBody? { } fun DeclarationDescriptor.equalTo(other: DeclarationDescriptor): Boolean { - return this.isSubtypeOf(other) || this.hasSameNameAs(other) || this == other + return this.isEqualByReceiverTo(other) || this.hasSameNameAs(other) || this == other } private fun WrappedReceiverParameterDescriptor.isEqualTo(other: DeclarationDescriptor): Boolean { @@ -60,14 +55,14 @@ private fun WrappedReceiverParameterDescriptor.isEqualTo(other: DeclarationDescr } } -private fun DeclarationDescriptor.isSubtypeOf(other: DeclarationDescriptor): Boolean { +private fun DeclarationDescriptor.isEqualByReceiverTo(other: DeclarationDescriptor): Boolean { if (this !is ReceiverParameterDescriptor || other !is ReceiverParameterDescriptor) return false return when { this is WrappedReceiverParameterDescriptor && other is WrappedReceiverParameterDescriptor -> this.isEqualTo(other) || other.isEqualTo(this) this is WrappedReceiverParameterDescriptor -> this.isEqualTo(other) other is WrappedReceiverParameterDescriptor -> other.isEqualTo(this) - this.value is ImplicitClassReceiver && other.value is ImplicitClassReceiver -> this.value.type.isSubtypeOf(other.value.type) + this.value is ImplicitClassReceiver && other.value is ImplicitClassReceiver -> this.value.type == other.value.type this.value is ExtensionReceiver && other.value is ExtensionReceiver -> this.value == other.value else -> false } @@ -81,14 +76,6 @@ private fun DeclarationDescriptor.hasSameNameAs(other: DeclarationDescriptor): B this.name == other.name) } -fun IrFunction.isAbstract(): Boolean { - return (this as? IrSimpleFunction)?.modality == Modality.ABSTRACT -} - -fun IrFunction.isFakeOverridden(): Boolean { - return this.isFakeOverride -} - fun State.toIrExpression(expression: IrExpression): IrExpression { val start = expression.startOffset val end = expression.endOffset @@ -177,7 +164,7 @@ fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? { } fun IrType.getFqName(): String? { - return this.classOrNull?.owner?.fqNameForIrSerialization?.asString() + return this.classOrNull?.owner?.fqNameWhenAvailable?.asString() } fun IrFunction.getArgsForMethodInvocation(args: List): List { @@ -202,13 +189,9 @@ fun IrFunction.getArgsForMethodInvocation(args: List): List { } fun IrFunction.getLastOverridden(): IrFunction { - if (this !is IrFunctionImpl) return this + if (this !is IrSimpleFunction) return this - var function = this as IrFunctionImpl - while (function.overriddenSymbols.isNotEmpty()) { - function = function.overriddenSymbols.first().owner as IrFunctionImpl - } - return function + return generateSequence(listOf(this)) { it.firstOrNull()?.overriddenSymbols?.map { it.owner } }.flatten().last() } fun List.toPrimitiveStateArray(type: IrType): Primitive<*> { @@ -225,18 +208,6 @@ fun List.toPrimitiveStateArray(type: IrType): Primitive<*> { } } -fun State?.getFunctionReceiver(superIrClass: IrClass?): State? { - return when { - superIrClass == null -> this - superIrClass.isInterface -> { - val interfaceState = Common(superIrClass) - (this!!.copy() as Complex).setSuperClassInstance(interfaceState) - interfaceState - } - else -> (this as Complex).superClass - } -} - fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? { val varargType = this.symbol.owner.valueParameters[index].varargElementType ?: return null varargType.classOrNull?.let { return this.symbol.owner.valueParameters[index].type } @@ -268,4 +239,12 @@ fun State?.extractNonLocalDeclarations(): List { this ?: return listOf() val state = this.takeIf { it !is Complex } ?: (this as Complex).getOriginal() return state.fields.filterNot { it.descriptor.containingDeclaration == state.irClass.descriptor } +} + +fun State?.getCorrectReceiverByFunction(irFunction: IrFunction): State? { + if (this !is Complex) return this + + val original: Complex? = this.getOriginal() + val other = irFunction.dispatchReceiverParameter?.descriptor ?: return this + return generateSequence(original) { it.superClass }.firstOrNull { it.irClass.descriptor.thisAsReceiverParameter.equalTo(other) } ?: this } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsics/IntrinsicImplementations.kt index c23cbfbd1db..49a044a09e9 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsics/IntrinsicImplementations.kt @@ -137,7 +137,7 @@ object RegexReplace : IntrinsicBase() { object EnumHashCode : IntrinsicBase() { override fun equalTo(irFunction: IrFunction): Boolean { val fqName = irFunction.fqNameWhenAvailable.toString() - return fqName.endsWith(".hashCode") && irFunction.parentAsClass.isEnumClass + return fqName == "kotlin.Enum.hashCode" } override suspend fun evaluate( 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 8efb2b48cbb..dcd3e2a1f5f 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 @@ -5,12 +5,14 @@ package org.jetbrains.kotlin.backend.common.interpreter.state +import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization +import org.jetbrains.kotlin.ir.util.isFakeOverride import org.jetbrains.kotlin.ir.util.isInterface class Common private constructor( @@ -42,10 +44,11 @@ class Common private constructor( return owner } - fun getToStringFunction(): IrFunctionImpl { + fun getToStringFunction(): IrFunction { return irClass.declarations.filterIsInstance() .filter { it.descriptor.name.asString() == "toString" } - .first { it.descriptor.valueParameters.isEmpty() } as IrFunctionImpl + .first { it.descriptor.valueParameters.isEmpty() } + .let { getOverridden(it as IrSimpleFunction, this) } } override fun copy(): State { 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 821e944ba35..ede24906e49 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 @@ -6,12 +6,17 @@ package org.jetbrains.kotlin.backend.common.interpreter.state import org.jetbrains.kotlin.backend.common.interpreter.equalTo +import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden +import org.jetbrains.kotlin.backend.common.interpreter.getCorrectReceiverByFunction import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable import org.jetbrains.kotlin.descriptors.FunctionDescriptor 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.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization +import org.jetbrains.kotlin.ir.util.isInterface abstract class Complex( override val irClass: IrClass, override val fields: MutableList, var superClass: Complex?, var subClass: Complex? @@ -47,9 +52,45 @@ abstract class Complex( } } - override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { + private fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { val propertyGetters = irClass.declarations.filterIsInstance().mapNotNull { it.getter } val functions = irClass.declarations.filterIsInstance() return (propertyGetters + functions).singleOrNull { it.descriptor.equalTo(descriptor) } } + + 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 + } + else -> this.superClass + } + } + + protected fun getOverridden(owner: IrSimpleFunction, qualifier: State?): IrSimpleFunction { + if (!owner.isFakeOverride) return owner + if (qualifier == null || qualifier is ExceptionState || (qualifier as? Complex)?.superClass == null) { + return owner.getLastOverridden() as IrSimpleFunction + } + + val overriddenOwner = owner.overriddenSymbols.single().owner + return when { + overriddenOwner.body != null -> overriddenOwner + else -> getOverridden(overriddenOwner, qualifier.superClass!!) + } + } + + override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { + val receiver = getThisOrSuperReceiver(expression.superQualifierSymbol?.owner) ?: return null + + val irFunction = receiver.getIrFunction(expression.symbol.descriptor) ?: return null + + return when (irFunction.body) { + null -> getOverridden(irFunction as IrSimpleFunction, this.getCorrectReceiverByFunction(irFunction)) + else -> irFunction + } + } } \ No newline at end of file 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 7e206623b1e..223c36a7120 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 @@ -7,9 +7,9 @@ package org.jetbrains.kotlin.backend.common.interpreter.state import org.jetbrains.kotlin.backend.common.interpreter.equalTo import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.nameForIrSerialization @@ -23,8 +23,8 @@ class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State throw UnsupportedOperationException("Method setState is not supported in Lambda class") } - override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { - return if (invokeDescriptor.equalTo(descriptor)) irFunction else null + override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { + return if (invokeDescriptor.equalTo(expression.symbol.descriptor)) irFunction else null } override fun copy(): State { 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 a92778d9ee9..66465e7e472 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 @@ -5,14 +5,16 @@ package org.jetbrains.kotlin.backend.common.interpreter.state +import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor 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.IrCall import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.util.isFakeOverride class Primitive(var value: T, val type: IrType) : State { override val fields: MutableList = mutableListOf() @@ -31,12 +33,14 @@ class Primitive(var value: T, val type: IrType) : State { return Primitive(value, type) } - override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { + 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 val declarations = irClass.declarations.map { if (it is IrProperty) it.getter else it } return declarations.filterIsInstance() .filter { it.descriptor.name == descriptor.name } .firstOrNull { it.descriptor.valueParameters.map { it.type } == descriptor.valueParameters.map { it.type } } + ?.let { if (it.isFakeOverride) it.getLastOverridden() else it } } override fun equals(other: Any?): Boolean { 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 b930f519643..0e8b44f3e35 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 @@ -8,9 +8,9 @@ package org.jetbrains.kotlin.backend.common.interpreter.state import org.jetbrains.kotlin.backend.common.interpreter.equalTo import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.expressions.IrCall interface State { val fields: MutableList @@ -31,7 +31,7 @@ interface State { */ fun copy(): State - fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? + fun getIrFunctionByIrCall(expression: IrCall): IrFunction? } fun State.asInt() = (this as Primitive<*>).value as Int