From 0e8ca12499f27bf76f8f32281fefdc140cb14b59 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 1 Apr 2021 22:13:17 +0300 Subject: [PATCH] Add callback to methods of CallInterceptor to specify default behaviour --- .../kotlin/ir/interpreter/CallInterceptor.kt | 42 ++++++++-------- .../ir/interpreter/InstructionsUnfolder.kt | 42 +--------------- .../kotlin/ir/interpreter/IrInterpreter.kt | 48 +++++++++++++++++-- .../intrinsics/IntrinsicImplementations.kt | 4 +- 4 files changed, 67 insertions(+), 69 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 88135e38493..86b6eebf369 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 @@ -37,10 +37,10 @@ internal interface CallInterceptor { val interpreter: IrInterpreter fun interceptProxy(irFunction: IrFunction, valueArguments: List, expectedResultClass: Class<*> = Any::class.java): Any? - fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List) - fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List) - fun interceptGetObjectValue(expression: IrGetObjectValue) - fun interceptEnumEntry(enumEntry: IrEnumEntry) + fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List, defaultAction: () -> Unit) + fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List, defaultAction: () -> Unit) + fun interceptGetObjectValue(expression: IrGetObjectValue, defaultAction: () -> Unit) + fun interceptEnumEntry(enumEntry: IrEnumEntry, defaultAction: () -> Unit) fun interceptJavaStaticField(expression: IrGetField) } @@ -57,7 +57,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : }.wrap(this@DefaultCallInterceptor, expectedResultClass) } - override fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List) { + override fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List, defaultAction: () -> Unit) { val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly")) val originalCallName = call.symbol.owner.name.asString() when { @@ -69,11 +69,13 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : irFunction.body is IrSyntheticBody -> handleIntrinsicMethods(irFunction) irFunction.body == null -> irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction, args) - else -> callStack.addInstruction(CompoundInstruction(irFunction)) + else -> defaultAction() } } - override fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List) { + override fun interceptConstructor( + constructorCall: IrFunctionAccessExpression, receiver: State, args: List, defaultAction: () -> Unit + ) { val constructor = constructorCall.symbol.owner val irClass = constructor.parentAsClass when { @@ -90,23 +92,23 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : val propertySymbol = irClass.declarations.single { it is IrProperty }.symbol callStack.pushState(receiver.apply { fields += Variable(propertySymbol, args.single()) }) } - else -> { - callStack.pushState(receiver) - callStack.addInstruction(CompoundInstruction(constructor)) - } + else -> defaultAction() } } - override fun interceptGetObjectValue(expression: IrGetObjectValue) { + override fun interceptGetObjectValue(expression: IrGetObjectValue, defaultAction: () -> Unit) { val objectClass = expression.symbol.owner - if (objectClass.hasAnnotation(evaluateIntrinsicAnnotation)) { - val result = Wrapper.getCompanionObject(objectClass) - environment.mapOfObjects[expression.symbol] = result - callStack.pushState(result) + when { + objectClass.hasAnnotation(evaluateIntrinsicAnnotation) -> { + val result = Wrapper.getCompanionObject(objectClass) + environment.mapOfObjects[expression.symbol] = result + callStack.pushState(result) + } + else -> defaultAction() } } - override fun interceptEnumEntry(enumEntry: IrEnumEntry) { + override fun interceptEnumEntry(enumEntry: IrEnumEntry, defaultAction: () -> Unit) { val enumClass = enumEntry.symbol.owner.parentAsClass when { @@ -116,11 +118,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : Wrapper.getEnumEntry(enumClass)!!.invokeMethod(valueOfFun, listOf(enumEntryName)) environment.mapOfEnums[enumEntry.symbol] = callStack.popState() as Complex } - else -> { - val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall) - enumSuperCall?.apply { (0 until this.valueArgumentsCount).forEach { putValueArgument(it, null) } } // restore to null - callStack.dropSubFrame() - } + else -> defaultAction() } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt index 6765da62529..ad934e26e7b 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt @@ -12,9 +12,7 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl -import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError import org.jetbrains.kotlin.ir.interpreter.stack.CallStack import org.jetbrains.kotlin.ir.interpreter.stack.Variable @@ -22,7 +20,6 @@ import org.jetbrains.kotlin.ir.interpreter.state.* import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.util.hasAnnotation internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEnvironment) { val callStack = environment.callStack @@ -44,7 +41,6 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn is IrGetValue -> unfoldGetValue(element, environment) is IrGetObjectValue -> unfoldGetObjectValue(element, environment) is IrGetEnumValue -> unfoldGetEnumValue(element, environment) - is IrEnumEntry -> unfoldEnumEntry(element, environment) is IrConst<*> -> callStack.addInstruction(SimpleInstruction(element)) is IrVariable -> unfoldVariable(element, callStack) is IrSetValue -> unfoldSetValue(element, callStack) @@ -235,18 +231,7 @@ private fun unfoldGetObjectValue(expression: IrGetObjectValue, environment: IrIn val objectClass = expression.symbol.owner environment.mapOfObjects[objectClass.symbol]?.let { return callStack.pushState(it) } - callStack.newSubFrame(expression, listOf(SimpleInstruction(expression))) - when { - !objectClass.hasAnnotation(evaluateIntrinsicAnnotation) -> { - val state = Common(objectClass) - environment.mapOfObjects[objectClass.symbol] = state // must set object's state here to avoid cyclic evaluation - callStack.addVariable(Variable(objectClass.thisReceiver!!.symbol, state)) - - val constructor = objectClass.constructors.first() - val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) - callStack.addInstruction(CompoundInstruction(constructorCall)) - } - } + callStack.addInstruction(SimpleInstruction(expression)) } private fun unfoldGetEnumValue(expression: IrGetEnumValue, environment: IrInterpreterEnvironment) { @@ -257,33 +242,10 @@ private fun unfoldGetEnumValue(expression: IrGetEnumValue, environment: IrInterp val enumEntry = expression.symbol.owner val enumClass = enumEntry.symbol.owner.parentAsClass enumClass.declarations.filterIsInstance().forEach { - if (enumClass.hasAnnotation(evaluateIntrinsicAnnotation)) return@forEach callStack.addInstruction(SimpleInstruction(it)) - callStack.addInstruction(CompoundInstruction(it)) + callStack.addInstruction(SimpleInstruction(it)) } } -private fun unfoldEnumEntry(enumEntry: IrEnumEntry, environment: IrInterpreterEnvironment) { - val enumClass = enumEntry.symbol.owner.parentAsClass - val enumEntries = enumClass.declarations.filterIsInstance() - - val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall) - if (enumEntries.isNotEmpty() && enumSuperCall != null) { - val valueArguments = listOf( - enumEntry.name.asString().toIrConst(environment.irBuiltIns.stringType), - enumEntries.indexOf(enumEntry).toIrConst(environment.irBuiltIns.intType) - ) - valueArguments.forEachIndexed { index, irConst -> enumSuperCall.putValueArgument(index, irConst) } - } - - val enumConstructorCall = enumEntry.initializerExpression?.expression as? IrEnumConstructorCall - ?: throw InterpreterError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null") - val enumClassObject = Variable(enumConstructorCall.getThisReceiver(), Common(enumEntry.correspondingClass ?: enumClass)) - environment.mapOfEnums[enumEntry.symbol] = enumClassObject.state as Complex - - environment.callStack.newSubFrame(enumEntry, listOf(CompoundInstruction(enumConstructorCall), SimpleInstruction(enumEntry))) - environment.callStack.addVariable(enumClassObject) -} - private fun unfoldVariable(variable: IrVariable, callStack: CallStack) { when (variable.initializer) { null -> callStack.addVariable(Variable(variable.symbol)) 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 2cbf044252a..22e22865285 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 @@ -211,7 +211,9 @@ class IrInterpreter private constructor( generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) } } - callInterceptor.interceptCall(call, irFunction, dispatchReceiver, args.map { it.state }) + callInterceptor.interceptCall(call, irFunction, dispatchReceiver, args.map { it.state }) { + callStack.addInstruction(CompoundInstruction(irFunction)) + } } private fun interpretInstanceInitializerCall(call: IrInstanceInitializerCall) { @@ -273,7 +275,10 @@ class IrInterpreter private constructor( } superReceiver?.let { callStack.addVariable(Variable(it, objectVar.state)) } - callInterceptor.interceptConstructor(constructorCall, objectVar.state, valueArguments) + callInterceptor.interceptConstructor(constructorCall, objectVar.state, valueArguments) { + callStack.pushState(objectVar.state) + callStack.addInstruction(CompoundInstruction(constructor)) + } } private fun interpretDelegatingConstructorCall(constructorCall: IrDelegatingConstructorCall) { @@ -379,8 +384,16 @@ class IrInterpreter private constructor( } private fun interpretGetObjectValue(expression: IrGetObjectValue) { - callStack.dropSubFrame() - callInterceptor.interceptGetObjectValue(expression) + callInterceptor.interceptGetObjectValue(expression) { + val objectClass = expression.symbol.owner + val state = Common(objectClass) + environment.mapOfObjects[objectClass.symbol] = state // must set object's state here to avoid cyclic evaluation + callStack.addVariable(Variable(objectClass.thisReceiver!!.symbol, state)) + + val constructor = objectClass.constructors.first() + val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) + callStack.newSubFrame(constructorCall, listOf(SimpleInstruction(constructorCall))) + } } private fun interpretGetEnumValue(expression: IrGetEnumValue) { @@ -388,7 +401,32 @@ class IrInterpreter private constructor( } private fun interpretEnumEntry(enumEntry: IrEnumEntry) { - callInterceptor.interceptEnumEntry(enumEntry) + callInterceptor.interceptEnumEntry(enumEntry) { + val enumClass = enumEntry.symbol.owner.parentAsClass + val enumEntries = enumClass.declarations.filterIsInstance() + val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall) + + val cleanEnumSuperCall = fun() { + enumSuperCall?.apply { (0 until this.valueArgumentsCount).forEach { putValueArgument(it, null) } } // restore to null + callStack.dropSubFrame() + } + + if (enumEntries.isNotEmpty() && enumSuperCall != null) { + val valueArguments = listOf( + enumEntry.name.asString().toIrConst(irBuiltIns.stringType), + enumEntries.indexOf(enumEntry).toIrConst(irBuiltIns.intType) + ) + valueArguments.forEachIndexed { index, irConst -> enumSuperCall.putValueArgument(index, irConst) } + } + + val enumConstructorCall = enumEntry.initializerExpression?.expression as? IrEnumConstructorCall + ?: throw InterpreterError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null") + val enumClassObject = Variable(enumConstructorCall.getThisReceiver(), Common(enumEntry.correspondingClass ?: enumClass)) + environment.mapOfEnums[enumEntry.symbol] = enumClassObject.state as Complex + + callStack.newSubFrame(enumEntry, listOf(CompoundInstruction(enumConstructorCall), CustomInstruction(cleanEnumSuperCall))) + callStack.addVariable(enumClassObject) + } } private fun interpretTypeOperatorCall(expression: IrTypeOperatorCall) { 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 a30c1c162fc..820a92aca82 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 @@ -112,7 +112,7 @@ internal object EnumValues : IntrinsicBase() { val enumClass = getEnumClass(irFunction, environment) val enumEntries = enumClass.declarations.filterIsInstance() - return listOf(customEvaluateInstruction(irFunction, environment)) + enumEntries.reversed().map { CompoundInstruction(it) } + return listOf(customEvaluateInstruction(irFunction, environment)) + enumEntries.reversed().map { SimpleInstruction(it) } } override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { @@ -151,7 +151,7 @@ internal object EnumValueOf : IntrinsicBase() { override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List { val enumEntry = getEnumEntryByName(irFunction, environment) ?: return emptyList() - return listOf(customEvaluateInstruction(irFunction, environment), CompoundInstruction(enumEntry)) + return listOf(customEvaluateInstruction(irFunction, environment), SimpleInstruction(enumEntry)) } override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {