From 3326cbd9c04a0c47aaab88055824185673ff001c Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Wed, 2 Jun 2021 16:13:13 +0300 Subject: [PATCH] Support passing property as argument to array constructor in interpreter --- .../kotlin/ir/interpreter/CallInterceptor.kt | 3 ++- .../kotlin/ir/interpreter/IrInterpreter.kt | 24 ++++++++++-------- .../intrinsics/IntrinsicImplementations.kt | 21 +++++++++------ .../collections/arrayConstructor.kt | Bin 1449 -> 1720 bytes 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt index 6fd91d59243..fc90de101a9 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt @@ -36,6 +36,7 @@ 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 { @@ -74,7 +75,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.asString() == "invoke" -> handleInvoke(call, receiver, args) + receiver is KFunctionState && call.symbol.owner.name == OperatorNameConventions.INVOKE -> handleInvoke(call, receiver, args) receiver is ReflectionState -> 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 -> 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 6d409bbc636..4bf6f9d31ae 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 @@ -171,9 +171,11 @@ class IrInterpreter private constructor( } private fun interpretCall(call: IrCall) { - fun IrFunction.mustBeHandledWithSuperOf(state: State?): State? { - if (state is Common && this.parent == state.superWrapperClass?.irClass) return state.superWrapperClass - return state + fun State?.getThisOrSuperReceiver(irFunction: IrFunction): State? { + // check if this function must be handled by super wrapper object + if (this !is Common || this.superWrapperClass == null || irFunction.parent !is IrClass) return this + if (superWrapperClass!!.irClass.isSubclassOf(irFunction.parentAsClass)) return superWrapperClass + return this } val owner = call.symbol.owner @@ -184,7 +186,7 @@ class IrInterpreter private constructor( // 2. get correct function for interpretation val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner - val args = listOfNotNull(irFunction.mustBeHandledWithSuperOf(dispatchReceiver), extensionReceiver) + valueArguments + val args = listOfNotNull(dispatchReceiver.getThisOrSuperReceiver(irFunction), extensionReceiver) + valueArguments callStack.dropSubFrame() // drop intermediate frame that contains variables for default arg evaluation callStack.newFrame(irFunction) @@ -194,11 +196,9 @@ class IrInterpreter private constructor( callStack.addVariable(Variable(irFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner))) // 3. store arguments in memory (remap args on actual names) - val variables = mutableListOf() - irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> variables.add(Variable(it, receiver)) } } - irFunction.getExtensionReceiver()?.let { variables.add(Variable(it, extensionReceiver ?: valueArguments.removeFirst())) } - irFunction.valueParameters.forEach { variables.add(Variable(it.symbol, valueArguments.removeFirst())) } - variables.forEach { callStack.addVariable(it) } + irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> callStack.addVariable(Variable(it, receiver)) } } + irFunction.getExtensionReceiver()?.let { callStack.addVariable(Variable(it, extensionReceiver ?: valueArguments.removeFirst())) } + irFunction.valueParameters.forEach { callStack.addVariable(Variable(it.symbol, valueArguments.removeFirst())) } // 4. store reified type parameters irFunction.typeParameters.filter { it.isReified } @@ -592,8 +592,10 @@ class IrInterpreter private constructor( val extensionReceiver = reference.extensionReceiver?.let { callStack.getState(irFunction.getExtensionReceiver()!!) } callStack.dropSubFrame() - irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> function.fields += Variable(it, receiver) } } - irFunction.getExtensionReceiver()?.let { extensionReceiver?.let { receiver -> function.fields += Variable(it, receiver) } } + // 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 if (irFunction.isLocal) callStack.storeUpValues(function) callStack.pushState(function) 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 a6aaa79619a..8aa1eea2198 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 @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.interpreter.* import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException import org.jetbrains.kotlin.ir.interpreter.state.* import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState +import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.buildSimpleType @@ -217,19 +218,23 @@ internal object ArrayConstructor : IntrinsicBase() { override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List { if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment)) + val callStack = environment.callStack val instructions = mutableListOf(customEvaluateInstruction(irFunction, environment)) - val sizeDescriptor = irFunction.valueParameters[0].symbol - val size = environment.callStack.getState(sizeDescriptor).asInt() + val sizeSymbol = irFunction.valueParameters[0].symbol + val size = callStack.getState(sizeSymbol).asInt() + + val initSymbol = irFunction.valueParameters[1].symbol + val function = when (val state = callStack.getState(initSymbol)) { + is KFunctionState -> state.irFunction.apply { callStack.loadUpValues(state) } + is KPropertyState -> state.property.getter + else -> TODO("Unsupported `init` in array constructor: $state") + } as IrSimpleFunction - val initDescriptor = irFunction.valueParameters[1].symbol - val initLambda = environment.callStack.getState(initDescriptor) as KFunctionState - environment.callStack.loadUpValues(initLambda) - val function = initLambda.irFunction as IrSimpleFunction - val index = initLambda.irFunction.valueParameters.single() for (i in size - 1 downTo 0) { val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.returnType, function.symbol) - call.putValueArgument(0, IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, index.type, i)) + val arg = IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, environment.irBuiltIns.intType, i) + if (function.correspondingPropertySymbol == null) call.putValueArgument(0, arg) else call.extensionReceiver = arg instructions += CompoundInstruction(call) } diff --git a/compiler/testData/ir/interpreter/collections/arrayConstructor.kt b/compiler/testData/ir/interpreter/collections/arrayConstructor.kt index 8ce941f8d7f53959ca3b0c27a62a7ac7b20d0d95..300f26b22585027242db11ac1e44c7d374589ae9 100644 GIT binary patch delta 231 zcmW-Zy$%6E7)7gXM!dsSArb#kY!Dk15{1Ij8f(~z-5HtrR-zCO;VE=Vk7s7Plbn0c zr}C?QKf#O5<~qO0Ol)N?<~%DBo^g^|q0>RaRh@7Y$hoXmmyJQoa~Qg0vpudYchNeIw#!9`Ll=Dv--lonJjb;u`vZPPOuzsD delta 7 OcmdnNyOMjuN>%_2Jp$MO