Implement simple cache for dynamically created wrapper for lambda

This commit is contained in:
Ivan Kylchik
2021-07-26 16:36:19 +03:00
committed by TeamCityServer
parent 6482abc602
commit 09c31b0900
6 changed files with 78 additions and 53 deletions
@@ -573,7 +573,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
}
private fun interpretFunctionExpression(expression: IrFunctionExpression) {
val function = KFunctionState(expression.function, expression.type.classOrNull!!.owner)
val function = KFunctionState(expression.function, expression.type.classOrNull!!.owner, environment)
if (expression.function.isLocal) callStack.storeUpValues(function)
callStack.pushState(function)
}
@@ -586,6 +586,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val function = KFunctionState(
reference,
environment,
dispatchReceiver?.let { Variable(irFunction.getDispatchReceiver()!!, it) },
extensionReceiver?.let { Variable(irFunction.getExtensionReceiver()!!, it) }
)
@@ -7,10 +7,12 @@ package org.jetbrains.kotlin.ir.interpreter
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.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.state.Common
import org.jetbrains.kotlin.ir.interpreter.state.Complex
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.isSubclassOf
@@ -22,6 +24,7 @@ class IrInterpreterEnvironment(
internal val irExceptions = mutableListOf<IrClass>()
internal var mapOfEnums = mutableMapOf<IrSymbol, Complex>()
internal var mapOfObjects = mutableMapOf<IrSymbol, Complex>()
internal var cachedLambdasAndReferences = mutableMapOf<IrFunctionSymbol, IrFunctionSymbol>()
init {
mapOfObjects[irBuiltIns.unitClass] = Common(irBuiltIns.unitClass.owner)
@@ -222,7 +222,7 @@ internal object ArrayConstructor : IntrinsicBase() {
val initSymbol = irFunction.valueParameters[1].symbol
val state = callStack.getState(initSymbol).let {
(it as? KFunctionState) ?: (it as KPropertyState).convertGetterToKFunctionState()
(it as? KFunctionState) ?: (it as KPropertyState).convertGetterToKFunctionState(environment)
}
// if property was converted, then we must replace symbol in memory to get correct receiver later
callStack.setState(initSymbol, state)
@@ -51,7 +51,10 @@ internal class KClassState(val classReference: IrClass, override val irClass: Ir
else -> TODO()
}
}
is IrFunction -> KFunctionProxy(KFunctionState(it, callInterceptor.irBuiltIns), callInterceptor)
is IrFunction -> {
val irClass = callInterceptor.irBuiltIns.kFunctionN(it.valueParameters.size)
KFunctionProxy(KFunctionState(it, irClass, callInterceptor.environment), callInterceptor)
}
else -> TODO()
}
}
@@ -62,7 +65,10 @@ internal class KClassState(val classReference: IrClass, override val irClass: Ir
if (_constructors != null) return _constructors!!
_constructors = classReference.declarations
.filterIsInstance<IrConstructor>()
.map { KFunctionProxy(KFunctionState(it, callInterceptor.irBuiltIns), callInterceptor) }
.map {
val irClass = callInterceptor.irBuiltIns.kFunctionN(it.valueParameters.size)
KFunctionProxy(KFunctionState(it, irClass, callInterceptor.environment), callInterceptor)
}
return _constructors!!
}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.ir.interpreter.state.reflection
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -14,10 +13,6 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.putArgument
import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.TEMP_FUNCTION_FOR_INTERPRETER
import org.jetbrains.kotlin.ir.interpreter.createTempClass
import org.jetbrains.kotlin.ir.interpreter.createTempFunction
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
@@ -34,72 +29,91 @@ import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter
internal class KFunctionState(
val irFunction: IrFunction, override val irClass: IrClass, override val fields: MutableList<Variable>,
val irFunction: IrFunction,
override val irClass: IrClass,
environment: IrInterpreterEnvironment,
override val fields: MutableList<Variable> = mutableListOf()
) : ReflectionState(), StateWithClosure {
override val upValues: MutableList<Variable> = mutableListOf()
private var _parameters: List<KParameter>? = null
private var _returnType: KType? = null
private var _typeParameters: List<KTypeParameter>? = null
private val functionClass: IrClass
val invokeSymbol: IrFunctionSymbol
val invokeSymbol: IrFunctionSymbol = environment.cachedLambdasAndReferences
.getOrDefault(
irFunction.symbol,
createInvokeFunction(
irFunction,
irClass,
irFunction.dispatchReceiverParameter?.let { getField(it.symbol) } != null,
irFunction.extensionReceiverParameter?.let { getField(it.symbol) } != null
).symbol
)
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 = createTempClass(Name.identifier("Function\$0")).apply { parent = irFunction.parent }
companion object {
fun createInvokeFunction(
irFunction: IrFunction, irClass: IrClass, hasDispatchReceiver: Boolean, hasExtensionReceiver: Boolean
): IrSimpleFunction {
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?
val functionClass = createTempClass(Name.identifier("Function\$0")).apply { parent = irFunction.parent }
functionClass.superTypes += irClass.defaultType
functionClass.declarations += createTempFunction(
OperatorNameConventions.INVOKE, irFunction.returnType, TEMP_FUNCTION_FOR_INTERPRETER
).apply impl@{
parent = functionClass
overriddenSymbols = listOf(invokeFunction.symbol)
functionClass.superTypes += irClass.defaultType
val newFunctionToInvoke = createTempFunction(
OperatorNameConventions.INVOKE, irFunction.returnType, TEMP_FUNCTION_FOR_INTERPRETER
).apply impl@{
parent = functionClass
overriddenSymbols = listOf(invokeFunction.symbol)
dispatchReceiverParameter = invokeFunction.dispatchReceiverParameter?.deepCopyWithSymbols(initialParent = this)
valueParameters = mutableListOf()
dispatchReceiverParameter = invokeFunction.dispatchReceiverParameter?.deepCopyWithSymbols(initialParent = this)
valueParameters = mutableListOf()
val call = when (irFunction) {
is IrSimpleFunction -> irFunction.createCall()
is IrConstructor -> irFunction.createConstructorCall()
else -> TODO("Unsupported symbol $symbol for invoke")
}.apply {
val dispatchParameter = irFunction.dispatchReceiverParameter
val extensionParameter = irFunction.extensionReceiverParameter
val call = when (irFunction) {
is IrSimpleFunction -> irFunction.createCall()
is IrConstructor -> irFunction.createConstructorCall()
else -> TODO("Unsupported symbol $symbol for invoke")
}.apply {
val dispatchParameter = irFunction.dispatchReceiverParameter
val extensionParameter = irFunction.extensionReceiverParameter
if (dispatchParameter != null) {
dispatchReceiver = dispatchParameter.createGetValue()
if (getField(dispatchParameter.symbol) == null) (this@impl.valueParameters as MutableList) += dispatchParameter
}
if (extensionParameter != null) {
extensionReceiver = extensionParameter.createGetValue()
if (getField(extensionParameter.symbol) == null) (this@impl.valueParameters as MutableList) += extensionParameter
}
irFunction.valueParameters.forEach {
putArgument(it, it.createGetValue())
(this@impl.valueParameters as MutableList) += it
if (dispatchParameter != null) {
dispatchReceiver = dispatchParameter.createGetValue()
if (!hasDispatchReceiver) (this@impl.valueParameters as MutableList) += dispatchParameter
}
if (extensionParameter != null) {
extensionReceiver = extensionParameter.createGetValue()
if (!hasExtensionReceiver) (this@impl.valueParameters as MutableList) += extensionParameter
}
irFunction.valueParameters.forEach {
putArgument(it, it.createGetValue())
(this@impl.valueParameters as MutableList) += it
}
}
body = listOf(this.createReturn(call)).wrapWithBlockBody()
}
body = listOf(this.createReturn(call)).wrapWithBlockBody()
invokeSymbol = this.symbol
functionClass.declarations += newFunctionToInvoke
return newFunctionToInvoke
}
}
constructor(irFunction: IrFunction, irClass: IrClass) : this(irFunction, irClass, mutableListOf())
constructor(functionReference: IrFunctionReference, dispatchReceiver: Variable?, extensionReceiver: Variable?) : this(
constructor(
functionReference: IrFunctionReference,
environment: IrInterpreterEnvironment,
dispatchReceiver: Variable?,
extensionReceiver: Variable?
) : this(
functionReference.symbol.owner,
functionReference.type.classOrNull!!.owner,
environment,
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), mutableListOf())
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
if (expression.symbol.owner.name == OperatorNameConventions.INVOKE) return invokeSymbol.owner
return super.getIrFunctionByIrCall(expression)
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KParameterProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
import org.jetbrains.kotlin.ir.interpreter.state.State
@@ -23,10 +24,10 @@ internal class KPropertyState(val property: IrProperty, override val irClass: Ir
private var _parameters: List<KParameter>? = null
private var _returnType: KType? = null
fun convertGetterToKFunctionState(): KFunctionState {
fun convertGetterToKFunctionState(environment: IrInterpreterEnvironment): KFunctionState {
val getterClass = irClass.getIrClassOfReflection("getter")
val functionType = getterClass.superTypes.single { it.classOrNull?.owner?.name?.asString() == "Function1" }
return KFunctionState(property.getter!!, functionType.classOrNull!!.owner)
return KFunctionState(property.getter!!, functionType.classOrNull!!.owner, environment)
}
fun getParameters(callInterceptor: CallInterceptor): List<KParameter> {