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
This commit is contained in:
Ivan Kylchik
2020-05-10 21:05:46 +03:00
parent 80d83f8703
commit 0c1f2edbf2
8 changed files with 81 additions and 101 deletions
@@ -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<Variable>()
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<Variable>()
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<Any?>().toPrimitiveStateArray(expression.getVarargType(i)!!))
?: stack.pushReturnValue(listOf<Any?>().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()
}
@@ -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<Variable>): List<Any?> {
@@ -202,13 +189,9 @@ fun IrFunction.getArgsForMethodInvocation(args: List<Variable>): List<Any?> {
}
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<Any?>.toPrimitiveStateArray(type: IrType): Primitive<*> {
@@ -225,18 +208,6 @@ fun List<Any?>.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<Variable> {
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
}
@@ -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(
@@ -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<IrFunction>()
.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 {
@@ -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<Variable>, 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<IrProperty>().mapNotNull { it.getter }
val functions = irClass.declarations.filterIsInstance<IrFunction>()
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
}
}
}
@@ -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 {
@@ -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<T>(var value: T, val type: IrType) : State {
override val fields: MutableList<Variable> = mutableListOf()
@@ -31,12 +33,14 @@ class Primitive<T>(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<IrFunction>()
.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 {
@@ -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<Variable>
@@ -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