Simplify logic of interpreting invoke method for lambdas

For now will be created separate invoke method that will contains
a call to lambda. This way it is clearer and more intuitive
This commit is contained in:
Ivan Kylchik
2021-06-03 02:54:17 +03:00
committed by TeamCityServer
parent 06a8156376
commit b44fd1a6fe
7 changed files with 120 additions and 68 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ plugins {
}
dependencies {
compileOnly(project(":compiler:ir.tree"))
compileOnly(project(":compiler:ir.tree.impl"))
compileOnly(project(":kotlin-reflect-api"))
}
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
@@ -36,7 +33,6 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.lang.invoke.MethodHandle
internal interface CallInterceptor {
@@ -75,8 +71,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
receiver is Wrapper && !isInlineOnly -> receiver.getMethod(irFunction).invokeMethod(irFunction, args)
Wrapper.mustBeHandledWithWrapper(irFunction) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, args)
handleIntrinsicMethods(irFunction) -> return
receiver is KFunctionState && call.symbol.owner.name == OperatorNameConventions.INVOKE -> handleInvoke(call, receiver, args)
receiver is ReflectionState -> Wrapper.getReflectionMethod(irFunction).invokeMethod(irFunction, args)
receiver.mustBeHandledAsReflection(call) -> Wrapper.getReflectionMethod(irFunction).invokeMethod(irFunction, args)
receiver is Primitive<*> -> calculateBuiltIns(irFunction, args) // check for js char, js long and get field for primitives
irFunction.body == null ->
irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction, args)
@@ -84,52 +79,6 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
}
}
// TODO unite this logic with interpretCall
private fun handleInvoke(call: IrCall, functionState: KFunctionState, args: List<State>) {
val invokedFunction = functionState.irFunction
var index = 1 // drop first arg that is reference to function
val dispatchReceiver = invokedFunction.dispatchReceiverParameter?.let { functionState.getField(it.symbol) ?: args[index++] }
val extensionReceiver = invokedFunction.extensionReceiverParameter?.let { functionState.getField(it.symbol) ?: args[index++] }
val valueArguments = invokedFunction.valueParameters.map { args[index++] }
val function = when (val symbol = invokedFunction.symbol) {
is IrSimpleFunctionSymbol -> {
val irCall = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, invokedFunction.returnType, symbol)
val actualFunction = dispatchReceiver?.getIrFunctionByIrCall(irCall) ?: invokedFunction
callStack.newFrame(actualFunction)
callStack.addInstruction(SimpleInstruction(actualFunction))
callStack.addVariable(Variable(actualFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner)))
actualFunction
}
is IrConstructorSymbol -> {
val irConstructorCall = IrConstructorCallImpl.fromSymbolOwner(invokedFunction.returnType, symbol)
callStack.newSubFrame(irConstructorCall)
callStack.addInstruction(SimpleInstruction(irConstructorCall))
callStack.addVariable(Variable(invokedFunction.parentAsClass.thisReceiver!!.symbol, Common(invokedFunction.parentAsClass)))
invokedFunction
}
else -> TODO("unsupported symbol $symbol for invoke")
}
function.dispatchReceiverParameter?.let { callStack.addVariable(Variable(it.symbol, dispatchReceiver!!)) }
function.extensionReceiverParameter?.let { callStack.addVariable(Variable(it.symbol, extensionReceiver!!)) }
function.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) }
if (invokedFunction.symbol is IrConstructorSymbol) return
callStack.loadUpValues(functionState)
if (extensionReceiver is StateWithClosure) callStack.loadUpValues(extensionReceiver)
if (dispatchReceiver is Complex && function.parentClassOrNull?.isInner == true) {
generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) }
}
this.interceptCall(call, function, listOfNotNull(dispatchReceiver, extensionReceiver) + valueArguments) {
callStack.addInstruction(CompoundInstruction(function))
}
}
override fun interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List<State>, defaultAction: () -> Unit) {
val receiver = callStack.getState(constructorCall.getThisReceiver())
val irConstructor = constructorCall.symbol.owner
@@ -275,4 +224,4 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
val expression = this.correspondingPropertySymbol?.owner?.backingField?.initializer?.expression
return expression?.apply { callStack.addInstruction(CompoundInstruction(this)) }
}
}
}
@@ -585,18 +585,18 @@ class IrInterpreter private constructor(
}
private fun interpretFunctionReference(reference: IrFunctionReference) {
val function = KFunctionState(reference)
val irFunction = function.irFunction
val irFunction = reference.symbol.owner
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getState(irFunction.getDispatchReceiver()!!) }
val extensionReceiver = reference.extensionReceiver?.let { callStack.getState(irFunction.getExtensionReceiver()!!) }
callStack.dropSubFrame()
// receivers in fields are used in comparison of two functions in KFunctionProxy
dispatchReceiver?.let { function.fields += Variable(irFunction.getDispatchReceiver()!!, it) }
extensionReceiver?.let { function.fields += Variable(irFunction.getExtensionReceiver()!!, it) }
function.upValues += function.fields
val function = KFunctionState(
reference,
dispatchReceiver?.let { Variable(irFunction.getDispatchReceiver()!!, it) },
extensionReceiver?.let { Variable(irFunction.getExtensionReceiver()!!, it) }
)
if (irFunction.isLocal) callStack.storeUpValues(function)
callStack.pushState(function)
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
import java.lang.invoke.MethodType
@@ -269,4 +270,4 @@ internal fun IrType.getOnlyName(): String {
internal fun IrFieldAccessExpression.accessesTopLevelOrObjectField(): Boolean {
return this.receiver == null || (this.receiver?.type?.classifierOrNull?.owner as? IrClass)?.isObject == true
}
}
@@ -5,15 +5,18 @@
package org.jetbrains.kotlin.ir.interpreter.state
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
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.interpreter.IrInterpreterEnvironment
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.util.OperatorNameConventions
internal interface State {
val fields: MutableList<Variable>
@@ -74,4 +77,8 @@ internal fun State.checkNullability(
return null
}
return this
}
internal fun State?.mustBeHandledAsReflection(call: IrCall): Boolean {
return this is ReflectionState && !(this is KFunctionState && call.symbol.owner.name == OperatorNameConventions.INVOKE)
}
@@ -5,32 +5,125 @@
package org.jetbrains.kotlin.ir.interpreter.state.reflection
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.expressions.putArgument
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KParameterProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeParameterProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
import kotlin.reflect.KParameter
import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter
internal class KFunctionState(val irFunction: IrFunction, override val irClass: IrClass) : ReflectionState(), StateWithClosure {
internal class KFunctionState(
val irFunction: IrFunction, override val irClass: IrClass, override val fields: MutableList<Variable>,
) : ReflectionState(), StateWithClosure {
override val upValues: MutableList<Variable> = mutableListOf()
override val fields: MutableList<Variable> = mutableListOf()
private var _parameters: List<KParameter>? = null
private var _returnType: KType? = null
private var _typeParameters: List<KTypeParameter>? = null
constructor(functionReference: IrFunctionReference) : this(functionReference.symbol.owner, functionReference.type.classOrNull!!.owner)
private val functionClass: IrClass
val invokeSymbol: IrFunctionSymbol
init {
val invokeFunction = irClass.declarations.filterIsInstance<IrSimpleFunction>().single { it.name == OperatorNameConventions.INVOKE }
// TODO do we need new class here? if yes, do we need different names for temp classes?
functionClass = IrFactoryImpl.createClass(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
object : IrDeclarationOriginImpl("TEMP_CLASS_FOR_INTERPRETER") {}, IrClassSymbolImpl(),
Name.identifier("Function\$0"), ClassKind.CLASS, DescriptorVisibilities.PRIVATE, Modality.FINAL
).apply {
parent = irFunction.parent
}
functionClass.superTypes += irClass.defaultType
functionClass.declarations += IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
object : IrDeclarationOriginImpl("TEMP_FUNCTION_FOR_INTERPRETER") {}, IrSimpleFunctionSymbolImpl(),
OperatorNameConventions.INVOKE, DescriptorVisibilities.PUBLIC, Modality.FINAL, irFunction.returnType,
isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isOperator = true, isInfix = false, isExpect = false
).apply impl@{
parent = functionClass
overriddenSymbols = listOf(invokeFunction.symbol)
dispatchReceiverParameter = invokeFunction.dispatchReceiverParameter?.deepCopyWithSymbols(initialParent = this)
valueParameters = mutableListOf()
val call = when (val symbol = irFunction.symbol) {
is IrSimpleFunctionSymbol -> IrCallImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
irFunction.returnType, symbol, irFunction.typeParameters.size, irFunction.valueParameters.size
)
is IrConstructorSymbol -> IrConstructorCallImpl.fromSymbolOwner(irFunction.returnType, symbol)
else -> TODO("Unsupported symbol $symbol for invoke")
}.apply {
val dispatchParameter = irFunction.dispatchReceiverParameter
val extensionParameter = irFunction.extensionReceiverParameter
if (dispatchParameter != null && getField(dispatchParameter.symbol) == null) {
dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchParameter.type, dispatchParameter.symbol)
(this@impl.valueParameters as MutableList).add(dispatchParameter)
}
if (extensionParameter != null && getField(extensionParameter.symbol) == null) {
extensionReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionParameter.type, extensionParameter.symbol)
(this@impl.valueParameters as MutableList).add(extensionParameter)
}
irFunction.valueParameters.forEach {
putArgument(it, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, it.symbol))
(this@impl.valueParameters as MutableList).add(it)
}
}
body = IrBlockBodyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
listOf(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.returnType, this.symbol, call))
)
invokeSymbol = this.symbol
}
}
constructor(irFunction: IrFunction, irClass: IrClass) : this(irFunction, irClass, mutableListOf())
constructor(functionReference: IrFunctionReference, dispatchReceiver: Variable?, extensionReceiver: Variable?) : this(
functionReference.symbol.owner,
functionReference.type.classOrNull!!.owner,
listOfNotNull(dispatchReceiver, extensionReceiver).toMutableList()
) {
// receivers are used in comparison of two functions in KFunctionProxy
upValues += fields
}
constructor(irFunction: IrFunction, irBuiltIns: IrBuiltIns) :
this(irFunction, irBuiltIns.kFunctionN(irFunction.valueParameters.size))
this(irFunction, irBuiltIns.kFunctionN(irFunction.valueParameters.size), mutableListOf())
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
if (expression.symbol.owner.name == OperatorNameConventions.INVOKE) return invokeSymbol.owner
return super.getIrFunctionByIrCall(expression)
}
fun getParameters(callInterceptor: CallInterceptor): List<KParameter> {
if (_parameters != null) return _parameters!!
@@ -59,6 +59,7 @@ Exception java.lang.ClassCastException: kotlin.Int cannot be cast to kotlin.Stri
const val stringList = getIntList<List<String>>().<!WAS_NOT_EVALUATED: `
Exception java.lang.ClassCastException: kotlin.Int cannot be cast to kotlin.String
at ClassCastExceptionKt.stringList.<anonymous>(classCastException.kt:54)
at ClassCastExceptionKt.stringList.Function$0.invoke(classCastException.kt:0)
at StandardKt.kotlin.let(Standard.kt:32)
at ClassCastExceptionKt.<clinit>(classCastException.kt:53)`!>let {
it[0].length
@@ -66,6 +67,7 @@ Exception java.lang.ClassCastException: kotlin.Int cannot be cast to kotlin.Stri
const val nullableStringList = getStringNullableList<List<String>>().<!WAS_NOT_EVALUATED: `
Exception java.lang.NullPointerException
at ClassCastExceptionKt.nullableStringList.<anonymous>(classCastException.kt)
at ClassCastExceptionKt.nullableStringList.Function$0.invoke(classCastException.kt:0)
at StandardKt.kotlin.let(Standard.kt:32)
at ClassCastExceptionKt.<clinit>(classCastException.kt:56)`!>let { it[0].length }<!>
const val nullableStringLength = <!WAS_NOT_EVALUATED: `