From 09c31b09000cfea0ba31092dd61b573cf4b92b09 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Mon, 26 Jul 2021 16:36:19 +0300 Subject: [PATCH] Implement simple cache for dynamically created wrapper for lambda --- .../kotlin/ir/interpreter/IrInterpreter.kt | 3 +- .../interpreter/IrInterpreterEnvironment.kt | 3 + .../intrinsics/IntrinsicImplementations.kt | 2 +- .../state/reflection/KClassState.kt | 10 +- .../state/reflection/KFunctionState.kt | 108 ++++++++++-------- .../state/reflection/KPropertyState.kt | 5 +- 6 files changed, 78 insertions(+), 53 deletions(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 929f19a17f0..bd948f0f548 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -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) } ) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreterEnvironment.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreterEnvironment.kt index 2e06bdbcbe8..15018dfc6ec 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreterEnvironment.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreterEnvironment.kt @@ -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() internal var mapOfEnums = mutableMapOf() internal var mapOfObjects = mutableMapOf() + internal var cachedLambdasAndReferences = mutableMapOf() init { mapOfObjects[irBuiltIns.unitClass] = Common(irBuiltIns.unitClass.owner) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt index cb4444fb5ba..47a0927f282 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt @@ -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) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KClassState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KClassState.kt index b2ba67e9033..8d94bf448ab 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KClassState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KClassState.kt @@ -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() - .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!! } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt index fef3cce38f9..04eb5b77bfa 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt @@ -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, + val irFunction: IrFunction, + override val irClass: IrClass, + environment: IrInterpreterEnvironment, + override val fields: MutableList = mutableListOf() ) : ReflectionState(), StateWithClosure { override val upValues: MutableList = mutableListOf() private var _parameters: List? = null private var _returnType: KType? = null private var _typeParameters: List? = 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().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() + .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) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KPropertyState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KPropertyState.kt index 7eb60282f56..3bc17dd0e29 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KPropertyState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KPropertyState.kt @@ -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? = 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 {