Add CallInterceptor interface and implement its default realization

CallInterceptor will handle calls, constructor calls, getting enum
entries and objects. It will make a decision for interpreter: this call
must be handled as intrinsic or it must be interpreted.
This commit is contained in:
Ivan Kylchik
2021-03-29 16:17:16 +03:00
committed by TeamCityServer
parent c8b268a789
commit 25d01099d8
2 changed files with 234 additions and 180 deletions
@@ -0,0 +1,221 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.interpreter
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretBinaryFunction
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretTernaryFunction
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretUnaryFunction
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
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 java.lang.invoke.MethodHandle
internal interface CallInterceptor {
val environment: IrInterpreterEnvironment
val interpreter: IrInterpreter
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 interceptJavaStaticField(expression: IrGetField)
}
internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : CallInterceptor {
override val environment: IrInterpreterEnvironment = interpreter.environment
private val callStack: CallStack
get() = environment.callStack
private val irBuiltIns: IrBuiltIns
get() = environment.irBuiltIns
private val bodyMap: Map<IdSignature, IrBody>
get() = interpreter.bodyMap
override fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>) {
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
val originalCallName = call.symbol.owner.name.asString()
when {
receiver is Wrapper && !isInlineOnly -> receiver.getMethod(irFunction).invokeMethod(irFunction, args)
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, args)
receiver is KFunctionState && originalCallName == "invoke" -> callStack.addInstruction(CompoundInstruction(irFunction))
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 is IrSyntheticBody -> handleIntrinsicMethods(irFunction)
irFunction.body == null ->
irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction, args)
else -> callStack.addInstruction(CompoundInstruction(irFunction))
}
}
override fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>) {
val constructor = constructorCall.symbol.owner
val irClass = constructor.parentAsClass
when {
irClass.hasAnnotation(evaluateIntrinsicAnnotation) || irClass.fqNameWhenAvailable!!.startsWith(Name.identifier("java")) -> {
Wrapper.getConstructorMethod(constructor).invokeMethod(constructor, args)
if (constructorCall !is IrConstructorCall) (receiver as Common).superWrapperClass = callStack.popState() as Wrapper
}
irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> {
// array constructor doesn't have body so must be treated separately
callStack.addVariable(Variable(constructor.symbol, KTypeState(constructorCall.type, irBuiltIns.anyClass.owner)))
handleIntrinsicMethods(constructor)
}
irClass.defaultType.isUnsignedType() -> {
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))
}
}
}
override fun interceptGetObjectValue(expression: IrGetObjectValue) {
val objectClass = expression.symbol.owner
if (objectClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
val result = Wrapper.getCompanionObject(objectClass)
environment.mapOfObjects[expression.symbol] = result
callStack.pushState(result)
}
}
override fun interceptEnumEntry(enumEntry: IrEnumEntry) {
val enumClass = enumEntry.symbol.owner.parentAsClass
when {
enumClass.hasAnnotation(evaluateIntrinsicAnnotation) -> {
val enumEntryName = enumEntry.name.asString().toState(environment.irBuiltIns.stringType)
val valueOfFun = enumClass.declarations.single { it.nameForIrSerialization.asString() == "valueOf" } as IrFunction
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()
}
}
}
override fun interceptJavaStaticField(expression: IrGetField) {
val field = expression.symbol.owner
assert(field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic)
assert(field.initializer?.expression !is IrConst<*>)
callStack.pushState(Wrapper.getStaticGetter(field)!!.invokeWithArguments().toState(field.type))
}
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
this ?: return handleIntrinsicMethods(irFunction)
val argsForMethodInvocation = irFunction.getArgsForMethodInvocation(interpreter, this.type(), args)
withExceptionHandler(environment) {
val result = this.invokeWithArguments(argsForMethodInvocation)
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
}
}
private fun handleIntrinsicMethods(irFunction: IrFunction) {
IntrinsicEvaluator.unwindInstructions(irFunction, environment).forEach { callStack.addInstruction(it) }
}
private fun calculateBuiltIns(irFunction: IrFunction, args: List<State>) {
val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) {
null -> irFunction.name.asString()
else -> property.owner.name.asString()
}
val receiverType = irFunction.dispatchReceiverParameter?.type
val argsType = listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }
val argsValues = args.map { it.wrap(interpreter, calledFromBuiltIns = methodName !in setOf("plus", IrBuiltIns.OperatorNames.EQEQ)) }
fun IrType.getOnlyName(): String {
return when {
this.originalKotlinType != null -> this.originalKotlinType.toString()
this is IrSimpleType -> (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
else -> this.render()
}
}
// TODO replace unary, binary, ternary functions with vararg
withExceptionHandler(environment) {
val result = when (argsType.size) {
1 -> interpretUnaryFunction(methodName, argsType[0].getOnlyName(), argsValues[0])
2 -> when (methodName) {
"rangeTo" -> return calculateRangeTo(irFunction.returnType, args)
else -> interpretBinaryFunction(
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsValues[0], argsValues[1]
)
}
3 -> interpretTernaryFunction(
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(),
argsValues[0], argsValues[1], argsValues[2]
)
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin functions")
}
// TODO check "result is Unit"
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
}
}
private fun calculateRangeTo(type: IrType, args: List<State>) {
val constructor = type.classOrNull!!.owner.constructors.first()
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
val constructorValueParameters = constructor.valueParameters.map { it.symbol }
val primitiveValueParameters = args.map { it as Primitive<*> }
primitiveValueParameters.forEachIndexed { index, primitive ->
constructorCall.putValueArgument(index, primitive.value.toIrConst(constructorValueParameters[index].owner.type))
}
callStack.addInstruction(CompoundInstruction(constructorCall))
}
private fun Any?.getType(defaultType: IrType): IrType {
return when (this) {
is Boolean -> irBuiltIns.booleanType
is Char -> irBuiltIns.charType
is Byte -> irBuiltIns.byteType
is Short -> irBuiltIns.shortType
is Int -> irBuiltIns.intType
is Long -> irBuiltIns.longType
is String -> irBuiltIns.stringType
is Float -> irBuiltIns.floatType
is Double -> irBuiltIns.doubleType
null -> irBuiltIns.nothingNType
else -> defaultType
}
}
private fun IrFunction.trySubstituteFunctionBody(): IrElement? {
val signature = this.symbol.signature ?: return null
this.body = bodyMap[signature] ?: return null
callStack.addInstruction(CompoundInstruction(this))
return body
}
// TODO fix in FIR2IR; const val getter must have body with IrGetField node
private fun IrFunction.tryCalculateLazyConst(): IrExpression? {
if (this !is IrSimpleFunction) return null
val expression = this.correspondingPropertySymbol?.owner?.backingField?.initializer?.expression
return expression?.apply { callStack.addInstruction(CompoundInstruction(this)) }
}
}
@@ -11,38 +11,18 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretBinaryFunction
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretTernaryFunction
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretUnaryFunction
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterTimeOutError
import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.interpreter.state.Complex
import org.jetbrains.kotlin.ir.interpreter.state.ExceptionState
import org.jetbrains.kotlin.ir.interpreter.state.Primitive
import org.jetbrains.kotlin.ir.interpreter.state.State
import org.jetbrains.kotlin.ir.interpreter.state.asBoolean
import org.jetbrains.kotlin.ir.interpreter.state.isSubtypeOf
import org.jetbrains.kotlin.ir.interpreter.state.reflection.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KClassState
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.interpreter.state.reflection.ReflectionState
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import java.lang.invoke.MethodHandle
internal interface Instruction {
val element: IrElement?
@@ -56,13 +36,13 @@ internal class CustomInstruction(val evaluate: () -> Unit) : Instruction {
}
class IrInterpreter private constructor(
private val bodyMap: Map<IdSignature, IrBody>,
private val environment: IrInterpreterEnvironment
internal val bodyMap: Map<IdSignature, IrBody>, internal val environment: IrInterpreterEnvironment
) {
val irBuiltIns: IrBuiltIns
get() = environment.irBuiltIns
private val callStack: CallStack
get() = environment.callStack
private val callInterceptor: CallInterceptor = DefaultCallInterceptor(this)
private var commandCount = 0
constructor(irBuiltIns: IrBuiltIns, bodyMap: Map<IdSignature, IrBody> = emptyMap()) :
@@ -78,22 +58,6 @@ class IrInterpreter private constructor(
if (commandCount >= IrInterpreterEnvironment.MAX_COMMANDS) InterpreterTimeOutError().handleUserException(environment)
}
private fun Any?.getType(defaultType: IrType): IrType {
return when (this) {
is Boolean -> irBuiltIns.booleanType
is Char -> irBuiltIns.charType
is Byte -> irBuiltIns.byteType
is Short -> irBuiltIns.shortType
is Int -> irBuiltIns.intType
is Long -> irBuiltIns.longType
is String -> irBuiltIns.stringType
is Float -> irBuiltIns.floatType
is Double -> irBuiltIns.doubleType
null -> irBuiltIns.nothingNType
else -> defaultType
}
}
private fun getUnitState(): State {
return environment.mapOfObjects.getOrPut(irBuiltIns.unitClass) { Common(irBuiltIns.unitClass.owner) }
}
@@ -177,6 +141,11 @@ class IrInterpreter private constructor(
}
}
private fun IrFunction.tryResetFunctionBody() {
val signature = this.symbol.signature ?: return
if (bodyMap[signature] != null) this.body = null
}
private fun interpretFunction(function: IrSimpleFunction) {
function.tryResetFunctionBody()
if (function.checkCast(environment)) {
@@ -184,71 +153,6 @@ class IrInterpreter private constructor(
}
}
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
this ?: return handleIntrinsicMethods(irFunction)
val argsForMethodInvocation = irFunction.getArgsForMethodInvocation(this@IrInterpreter, this.type(), args)
withExceptionHandler(environment) {
val result = this.invokeWithArguments(argsForMethodInvocation)
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
}
}
private fun handleIntrinsicMethods(irFunction: IrFunction) {
IntrinsicEvaluator.unwindInstructions(irFunction, environment).forEach { callStack.addInstruction(it) }
}
private fun calculateBuiltIns(irFunction: IrFunction, args: List<State>) {
val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) {
null -> irFunction.name.asString()
else -> property.owner.name.asString()
}
val receiverType = irFunction.dispatchReceiverParameter?.type
val argsType = listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }
val argsValues = args.map { it.wrap(this, calledFromBuiltIns = methodName !in setOf("plus", IrBuiltIns.OperatorNames.EQEQ)) }
fun IrType.getOnlyName(): String {
return when {
this.originalKotlinType != null -> this.originalKotlinType.toString()
this is IrSimpleType -> (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
else -> this.render()
}
}
// TODO replace unary, binary, ternary functions with vararg
withExceptionHandler(environment) {
val result = when (argsType.size) {
1 -> interpretUnaryFunction(methodName, argsType[0].getOnlyName(), argsValues[0])
2 -> when (methodName) {
"rangeTo" -> return calculateRangeTo(irFunction.returnType, args)
else -> interpretBinaryFunction(
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsValues[0], argsValues[1]
)
}
3 -> interpretTernaryFunction(
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(),
argsValues[0], argsValues[1], argsValues[2]
)
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin functions")
}
// TODO check "result is Unit"
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
}
}
private fun calculateRangeTo(type: IrType, args: List<State>) {
val constructor = type.classOrNull!!.owner.constructors.first()
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
val constructorValueParameters = constructor.valueParameters.map { it.symbol }
val primitiveValueParameters = args.map { it as Primitive<*> }
primitiveValueParameters.forEachIndexed { index, primitive ->
constructorCall.putValueArgument(index, primitive.value.toIrConst(constructorValueParameters[index].owner.type))
}
callStack.addInstruction(CompoundInstruction(constructorCall))
}
private fun interpretValueParameter(valueParameter: IrValueParameter) {
val irFunction = valueParameter.parent as IrFunction
fun isReceiver() = irFunction.dispatchReceiverParameter == valueParameter || irFunction.extensionReceiverParameter == valueParameter
@@ -314,39 +218,7 @@ class IrInterpreter private constructor(
generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) }
}
val states = args.map { it.state }
// inline only methods are not presented in lookup table, so must be interpreted instead of execution
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
when {
dispatchReceiver is Wrapper && !isInlineOnly -> dispatchReceiver.getMethod(irFunction).invokeMethod(irFunction, states)
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, states)
dispatchReceiver is KFunctionState && call.symbol.owner.name.asString() == "invoke" -> callStack.addInstruction(CompoundInstruction(irFunction))
dispatchReceiver is ReflectionState -> Wrapper.getReflectionMethod(irFunction).invokeMethod(irFunction, states)
dispatchReceiver is Primitive<*> -> calculateBuiltIns(irFunction, states) // 'is Primitive' check for js char, js long and get field for primitives
irFunction.body is IrSyntheticBody -> handleIntrinsicMethods(irFunction)
irFunction.body == null ->
irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction, states)
else -> callStack.addInstruction(CompoundInstruction(irFunction))
}
}
private fun IrFunction.trySubstituteFunctionBody(): IrElement? {
val signature = this.symbol.signature ?: return null
this.body = bodyMap[signature] ?: return null
callStack.addInstruction(CompoundInstruction(this))
return body
}
private fun IrFunction.tryResetFunctionBody() {
val signature = this.symbol.signature ?: return
if (bodyMap[signature] != null) this.body = null
}
// TODO fix in FIR2IR; const val getter must have body with IrGetField node
private fun IrFunction.tryCalculateLazyConst(): IrExpression? {
if (this !is IrSimpleFunction) return null
val expression = this.correspondingPropertySymbol?.owner?.backingField?.initializer?.expression
return expression?.apply { callStack.addInstruction(CompoundInstruction(this)) }
callInterceptor.interceptCall(call, irFunction, dispatchReceiver, args.map { it.state })
}
private fun interpretInstanceInitializerCall(call: IrInstanceInitializerCall) {
@@ -408,26 +280,7 @@ class IrInterpreter private constructor(
}
superReceiver?.let { callStack.addVariable(Variable(it, objectVar.state)) }
when {
irClass.hasAnnotation(evaluateIntrinsicAnnotation) || irClass.fqNameWhenAvailable!!.startsWith(Name.identifier("java")) -> {
Wrapper.getConstructorMethod(constructor).invokeMethod(constructor, valueArguments)
if (constructorCall !is IrConstructorCall) (objectVar.state as Common).superWrapperClass = callStack.popState() as Wrapper
}
irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> {
// array constructor doesn't have body so must be treated separately
callStack.addVariable(Variable(constructor.symbol, KTypeState(constructorCall.type, irBuiltIns.anyClass.owner)))
handleIntrinsicMethods(constructor)
}
irClass.defaultType.isUnsignedType() && valueArguments.size == 1 && constructor.valueParameters.size == 1 -> {
callStack.pushState(objectVar.state.apply { fields.add(valueArguments.single()) })
callStack.addInstruction(SimpleInstruction(constructor))
}
else -> {
callStack.pushState(objectVar.state)
callStack.addInstruction(CompoundInstruction(constructor))
}
}
callInterceptor.interceptConstructor(constructorCall, objectVar.state, valueArguments)
}
private fun interpretDelegatingConstructorCall(constructorCall: IrDelegatingConstructorCall) {
@@ -507,12 +360,12 @@ class IrInterpreter private constructor(
private fun interpretGetField(expression: IrGetField) {
val receiver = (expression.receiver as? IrDeclarationReference)?.symbol
val field = expression.symbol.owner
// for java static variables
when {
field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic -> {
// for java static variables
when (val initializerExpression = field.initializer?.expression) {
is IrConst<*> -> callStack.addInstruction(SimpleInstruction(initializerExpression))
else -> callStack.pushState(Wrapper.getStaticGetter(field)!!.invokeWithArguments().toState(field.type))
else -> callInterceptor.interceptJavaStaticField(expression)
}
}
field.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD && field.correspondingPropertySymbol?.owner?.isConst == true -> {
@@ -534,13 +387,7 @@ class IrInterpreter private constructor(
private fun interpretGetObjectValue(expression: IrGetObjectValue) {
callStack.dropSubFrame()
val objectClass = expression.symbol.owner
if (objectClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
val result = Wrapper.getCompanionObject(objectClass)
environment.mapOfObjects[expression.symbol] = result
callStack.pushState(result)
}
callInterceptor.interceptGetObjectValue(expression)
}
private fun interpretGetEnumValue(expression: IrGetEnumValue) {
@@ -548,21 +395,7 @@ class IrInterpreter private constructor(
}
private fun interpretEnumEntry(enumEntry: IrEnumEntry) {
val enumClass = enumEntry.symbol.owner.parentAsClass
when {
enumClass.hasAnnotation(evaluateIntrinsicAnnotation) -> {
val enumEntryName = enumEntry.name.asString().toState(environment.irBuiltIns.stringType)
val valueOfFun = enumClass.declarations.single { it.nameForIrSerialization.asString() == "valueOf" } as IrFunction
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()
}
}
callInterceptor.interceptEnumEntry(enumEntry)
}
private fun interpretTypeOperatorCall(expression: IrTypeOperatorCall) {