Add callback to methods of CallInterceptor to specify default behaviour

This commit is contained in:
Ivan Kylchik
2021-04-01 22:13:17 +03:00
committed by TeamCityServer
parent 285929ad07
commit 0e8ca12499
4 changed files with 67 additions and 69 deletions
@@ -37,10 +37,10 @@ internal interface CallInterceptor {
val interpreter: IrInterpreter
fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, expectedResultClass: Class<*> = Any::class.java): Any?
fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>)
fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>)
fun interceptGetObjectValue(expression: IrGetObjectValue)
fun interceptEnumEntry(enumEntry: IrEnumEntry)
fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>, defaultAction: () -> Unit)
fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>, 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<State>) {
override fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>, 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<State>) {
override fun interceptConstructor(
constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>, 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()
}
}
@@ -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<IrEnumEntry>().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<IrEnumEntry>()
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))
@@ -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<IrEnumEntry>()
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) {
@@ -112,7 +112,7 @@ internal object EnumValues : IntrinsicBase() {
val enumClass = getEnumClass(irFunction, environment)
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>()
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<Instruction> {
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) {