Speed up interpreter's stack by using map of variables instead of list

This commit is contained in:
Ivan Kylchik
2021-08-09 19:09:18 +03:00
committed by TeamCityServer
parent a630273af2
commit ac2dffa74e
23 changed files with 184 additions and 196 deletions
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.ir.interpreter.exceptions.withExceptionHandler
import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack 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.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
@@ -35,7 +34,7 @@ internal interface CallInterceptor {
val irBuiltIns: IrBuiltIns val irBuiltIns: IrBuiltIns
val interpreter: IrInterpreter val interpreter: IrInterpreter
fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, expectedResultClass: Class<*> = Any::class.java): Any? fun interceptProxy(irFunction: IrFunction, valueArguments: List<State>, expectedResultClass: Class<*> = Any::class.java): Any?
fun interceptCall(call: IrCall, irFunction: IrFunction, args: List<State>, defaultAction: () -> Unit) fun interceptCall(call: IrCall, irFunction: IrFunction, args: List<State>, defaultAction: () -> Unit)
fun interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List<State>, defaultAction: () -> Unit) fun interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List<State>, defaultAction: () -> Unit)
fun interceptGetObjectValue(expression: IrGetObjectValue, defaultAction: () -> Unit) fun interceptGetObjectValue(expression: IrGetObjectValue, defaultAction: () -> Unit)
@@ -49,11 +48,11 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
override val irBuiltIns: IrBuiltIns = environment.irBuiltIns override val irBuiltIns: IrBuiltIns = environment.irBuiltIns
private val bodyMap: Map<IdSignature, IrBody> = interpreter.bodyMap private val bodyMap: Map<IdSignature, IrBody> = interpreter.bodyMap
override fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, expectedResultClass: Class<*>): Any? { override fun interceptProxy(irFunction: IrFunction, valueArguments: List<State>, expectedResultClass: Class<*>): Any? {
val irCall = irFunction.createCall() val irCall = irFunction.createCall()
return interpreter.withNewCallStack(irCall) { return interpreter.withNewCallStack(irCall) {
this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall)) this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall))
valueArguments.forEach { this@withNewCallStack.environment.callStack.pushState(it.state) } valueArguments.forEach { this@withNewCallStack.environment.callStack.pushState(it) }
}.wrap(this@DefaultCallInterceptor, remainArraysAsIs = false, extendFrom = expectedResultClass) }.wrap(this@DefaultCallInterceptor, remainArraysAsIs = false, extendFrom = expectedResultClass)
} }
@@ -78,7 +77,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
val irConstructor = constructorCall.symbol.owner val irConstructor = constructorCall.symbol.owner
val irClass = irConstructor.parentAsClass val irClass = irConstructor.parentAsClass
when { when {
Wrapper.mustBeHandledWithWrapper(irClass) || irClass.fqName.startsWith("java") -> { Wrapper.mustBeHandledWithWrapper(irClass) -> {
Wrapper.getConstructorMethod(irConstructor).invokeMethod(irConstructor, args) Wrapper.getConstructorMethod(irConstructor).invokeMethod(irConstructor, args)
when { when {
irClass.isSubclassOfThrowable() -> (receiver as ExceptionState).copyFieldsFrom(callStack.popState() as Wrapper) irClass.isSubclassOfThrowable() -> (receiver as ExceptionState).copyFieldsFrom(callStack.popState() as Wrapper)
@@ -88,12 +87,11 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
} }
irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> { irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> {
// array constructor doesn't have body so must be treated separately // array constructor doesn't have body so must be treated separately
callStack.addVariable(Variable(irConstructor.symbol, KTypeState(constructorCall.type, environment.kTypeClass.owner)))
verify(handleIntrinsicMethods(irConstructor)) { "Unsupported intrinsic constructor: ${irConstructor.render()}" } verify(handleIntrinsicMethods(irConstructor)) { "Unsupported intrinsic constructor: ${irConstructor.render()}" }
} }
irClass.defaultType.isUnsignedType() -> { irClass.defaultType.isUnsignedType() -> {
val propertySymbol = irClass.declarations.single { it is IrProperty }.symbol val propertySymbol = irClass.declarations.single { it is IrProperty }.symbol
callStack.pushState(receiver.apply { fields += Variable(propertySymbol, args.single()) }) callStack.pushState(receiver.apply { this.setField(propertySymbol, args.single()) })
} }
else -> defaultAction() else -> defaultAction()
} }
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.exceptions.verify import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack 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.*
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.types.isUnit
@@ -98,7 +97,7 @@ private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack)
irClass.declarations.filterIsInstance<IrProperty>().forEach { property -> irClass.declarations.filterIsInstance<IrProperty>().forEach { property ->
val parameter = constructor.valueParameters.singleOrNull { it.name == property.name } val parameter = constructor.valueParameters.singleOrNull { it.name == property.name }
val state = parameter?.let { callStack.getState(it.symbol) } ?: Primitive.nullStateOfType(property.getter!!.returnType) val state = parameter?.let { callStack.getState(it.symbol) } ?: Primitive.nullStateOfType(property.getter!!.returnType)
receiverState.setField(Variable(property.symbol, state)) receiverState.setField(property.symbol, state)
} }
} }
else -> { else -> {
@@ -268,7 +267,7 @@ private fun unfoldGetEnumValue(expression: IrGetEnumValue, environment: IrInterp
private fun unfoldVariable(variable: IrVariable, callStack: CallStack) { private fun unfoldVariable(variable: IrVariable, callStack: CallStack) {
when (variable.initializer) { when (variable.initializer) {
null -> callStack.addVariable(Variable(variable.symbol)) null -> callStack.addVariable(variable.symbol, null)
else -> { else -> {
callStack.addInstruction(SimpleInstruction(variable)) callStack.addInstruction(SimpleInstruction(variable))
callStack.addInstruction(CompoundInstruction(variable.initializer!!)) callStack.addInstruction(CompoundInstruction(variable.initializer!!))
@@ -337,7 +336,7 @@ private fun unfoldCatch(element: IrCatch, callStack: CallStack) {
val frameOwner = callStack.currentFrameOwner as IrTry val frameOwner = callStack.currentFrameOwner as IrTry
callStack.dropSubFrame() // drop other catch blocks callStack.dropSubFrame() // drop other catch blocks
callStack.newSubFrame(element) // new frame with IrTry instruction to interpret finally block at the end callStack.newSubFrame(element) // new frame with IrTry instruction to interpret finally block at the end
callStack.addVariable(Variable(element.catchParameter.symbol, exceptionState)) callStack.addVariable(element.catchParameter.symbol, exceptionState)
callStack.addInstruction(SimpleInstruction(frameOwner)) callStack.addInstruction(SimpleInstruction(frameOwner))
callStack.addInstruction(CompoundInstruction(element.result)) callStack.addInstruction(CompoundInstruction(element.result))
} }
@@ -360,7 +359,7 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
// TODO this check can be dropped after serialization introduction // TODO this check can be dropped after serialization introduction
// for now declarations in unsigned class don't have bodies and must be treated separately // for now declarations in unsigned class don't have bodies and must be treated separately
if (state.irClass.defaultType.isUnsigned()) { if (state.irClass.defaultType.isUnsigned()) {
val result = when (val value = (state.fields.single().state as Primitive<*>).value) { val result = when (val value = (state.fields.values.single() as Primitive<*>).value) {
is Byte -> value.toUByte().toString() is Byte -> value.toUByte().toString()
is Short -> value.toUShort().toString() is Short -> value.toUShort().toString()
is Int -> value.toUInt().toString() is Int -> value.toUInt().toString()
@@ -12,12 +12,9 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.interpreter.exceptions.* import org.jetbrains.kotlin.ir.interpreter.exceptions.*
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy 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.Proxy
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack 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.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.* import org.jetbrains.kotlin.ir.interpreter.state.reflection.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
@@ -108,7 +105,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
is IrGetEnumValue -> interpretGetEnumValue(element) is IrGetEnumValue -> interpretGetEnumValue(element)
is IrEnumEntry -> interpretEnumEntry(element) is IrEnumEntry -> interpretEnumEntry(element)
is IrConst<*> -> interpretConst(element) is IrConst<*> -> interpretConst(element)
is IrVariable -> callStack.addVariable(Variable(element.symbol, callStack.popState())) is IrVariable -> callStack.addVariable(element.symbol, callStack.popState())
is IrSetValue -> callStack.setState(element.symbol, callStack.popState()) is IrSetValue -> callStack.setState(element.symbol, callStack.popState())
is IrTypeOperatorCall -> interpretTypeOperatorCall(element) is IrTypeOperatorCall -> interpretTypeOperatorCall(element)
is IrBranch -> interpretBranch(element) is IrBranch -> interpretBranch(element)
@@ -173,11 +170,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val args = listOfNotNull(dispatchReceiver.getThisOrSuperReceiver(irFunction), extensionReceiver) + valueArguments val args = listOfNotNull(dispatchReceiver.getThisOrSuperReceiver(irFunction), extensionReceiver) + valueArguments
// 3. evaluate reified type arguments; must do it here, before new frame, because outer type arguments can be loaded at this point // 3. evaluate reified type arguments; must do it here, before new frame, because outer type arguments can be loaded at this point
val reifiedTypeArguments = irFunction.typeParameters.filter { it.isReified } val reifiedTypeArguments = environment.loadReifiedTypeArguments(call)
.map {
val reifiedType = call.getTypeArgument(it.index)!!.getTypeIfReified(callStack)
Variable(it.symbol, KTypeState(reifiedType, environment.kTypeClass.owner))
}
callStack.newFrame(irFunction) callStack.newFrame(irFunction)
callStack.addInstruction(SimpleInstruction(irFunction)) callStack.addInstruction(SimpleInstruction(irFunction))
@@ -188,14 +181,14 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame() if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame()
// 5. store arguments in memory (remap args on actual names) // 5. store arguments in memory (remap args on actual names)
irFunction.getDispatchReceiver()?.let { callStack.addVariable(Variable(it, dispatchReceiver!!)) } irFunction.getDispatchReceiver()?.let { callStack.addVariable(it, dispatchReceiver!!) }
irFunction.getExtensionReceiver()?.let { callStack.addVariable(Variable(it, extensionReceiver ?: callStack.getState(it))) } irFunction.getExtensionReceiver()?.let { callStack.addVariable(it, extensionReceiver ?: callStack.getState(it)) }
irFunction.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) } irFunction.valueParameters.forEachIndexed { i, param -> callStack.addVariable(param.symbol, valueArguments[i]) }
// `call.type` is used in check cast and emptyArray // `call.type` is used in check cast and emptyArray
callStack.addVariable(Variable(irFunction.symbol, KTypeState(call.type, environment.kTypeClass.owner))) callStack.addVariable(irFunction.symbol, KTypeState(call.type, environment.kTypeClass.owner))
// 6. store reified type parameters // 6. store reified type parameters
reifiedTypeArguments.forEach { callStack.addVariable(it) } reifiedTypeArguments.forEach { callStack.addVariable(it.key, it.value) }
// 7. load outer class object // 7. load outer class object
if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) dispatchReceiver.loadOuterClassesInto(callStack) if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) dispatchReceiver.loadOuterClassesInto(callStack)
@@ -209,7 +202,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val irClass = field.parentAsClass val irClass = field.parentAsClass
val receiver = irClass.thisReceiver!!.symbol val receiver = irClass.thisReceiver!!.symbol
val receiverState = callStack.getState(receiver) val receiverState = callStack.getState(receiver)
receiverState.setField(Variable(field.correspondingPropertySymbol!!, callStack.popState())) receiverState.setField(field.correspondingPropertySymbol!!, callStack.popState())
} }
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
@@ -247,13 +240,15 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure) if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure)
val outerClass = receiverSymbol?.let { callStack.popState() } val outerClass = receiverSymbol?.let { callStack.popState() }
val returnType = constructorCall.type.getTypeIfReified(callStack)
callStack.newFrame(constructor) callStack.newFrame(constructor)
callStack.addInstruction(SimpleInstruction(constructor)) callStack.addInstruction(SimpleInstruction(constructor))
if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure) if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure)
callStack.addVariable(Variable(constructorCall.getThisReceiver(), objectState)) callStack.addVariable(constructorCall.getThisReceiver(), objectState)
constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) } constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(param.symbol, valueArguments[i]) }
callStack.addVariable(constructor.symbol, KTypeState(returnType, environment.kTypeClass.owner))
val superReceiver = when (val irStatement = constructor.body?.statements?.get(0)) { val superReceiver = when (val irStatement = constructor.body?.statements?.get(0)) {
null -> null // for jvm null -> null // for jvm
@@ -262,16 +257,16 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
is IrBlock -> (irStatement.statements.last() as IrFunctionAccessExpression).getThisReceiver() is IrBlock -> (irStatement.statements.last() as IrFunctionAccessExpression).getThisReceiver()
else -> TODO("${irStatement::class.java} is not supported as first statement in constructor call") else -> TODO("${irStatement::class.java} is not supported as first statement in constructor call")
} }
superReceiver?.let { callStack.addVariable(Variable(it, objectState)) } superReceiver?.let { callStack.addVariable(it, objectState) }
if (outerClass != null) { if (outerClass != null) {
val outerClassVar = Variable(irClass.parentAsClass.thisReceiver!!.symbol, outerClass) val outerClassSymbolToState = irClass.parentAsClass.thisReceiver!!.symbol to outerClass
(objectState as Complex).outerClass = outerClassVar (objectState as Complex).outerClass = outerClassSymbolToState
if (superReceiver?.owner?.type != receiverSymbol.owner.type) { if (superReceiver?.owner?.type != receiverSymbol.owner.type) {
// This check is needed to test that this inner class is not subclass of its outer. // This check is needed to test that this inner class is not subclass of its outer.
// If it is true and if we add the next symbol, it will interfere with super symbol in memory. // If it is true and if we add the next symbol, it will interfere with super symbol in memory.
// In other case, we need this variable when inner class has inner super class. // In other case, we need this variable when inner class has inner super class.
callStack.addVariable(Variable(receiverSymbol, outerClass)) callStack.addVariable(receiverSymbol, outerClass)
// used to get information from outer class // used to get information from outer class
objectState.loadOuterClassesInto(callStack, constructorCall.getThisReceiver()) objectState.loadOuterClassesInto(callStack, constructorCall.getThisReceiver())
} }
@@ -349,7 +344,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
private fun interpretSetField(expression: IrSetField) { private fun interpretSetField(expression: IrSetField) {
val receiver = (expression.receiver as IrDeclarationReference).symbol val receiver = (expression.receiver as IrDeclarationReference).symbol
val propertySymbol = expression.symbol.owner.correspondingPropertySymbol!! val propertySymbol = expression.symbol.owner.correspondingPropertySymbol!!
callStack.getState(receiver).apply { this.setField(Variable(propertySymbol, callStack.popState())) } callStack.getState(receiver).apply { this.setField(propertySymbol, callStack.popState()) }
} }
private fun interpretGetField(expression: IrGetField) { private fun interpretGetField(expression: IrGetField) {
@@ -427,13 +422,13 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
valueArguments.forEachIndexed { index, irConst -> enumSuperCall.putValueArgument(index, irConst) } valueArguments.forEachIndexed { index, irConst -> enumSuperCall.putValueArgument(index, irConst) }
} }
val enumClassObject = Variable(enumConstructorCall.getThisReceiver(), Common(enumEntry.correspondingClass ?: enumClass)) val enumClassObject = Common(enumEntry.correspondingClass ?: enumClass)
environment.mapOfEnums[enumEntry.symbol] = enumClassObject.state as Complex environment.mapOfEnums[enumEntry.symbol] = enumClassObject
callStack.newSubFrame(enumEntry) callStack.newSubFrame(enumEntry)
callStack.addInstruction(CustomInstruction(cleanEnumSuperCall)) callStack.addInstruction(CustomInstruction(cleanEnumSuperCall))
callStack.addInstruction(CompoundInstruction(enumInitializer)) callStack.addInstruction(CompoundInstruction(enumInitializer))
callStack.addVariable(enumClassObject) callStack.addVariable(enumConstructorCall.getThisReceiver(), enumClassObject)
} }
} }
@@ -495,10 +490,11 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val functionClass = invokeFunction.getLastOverridden().parentAsClass val functionClass = invokeFunction.getLastOverridden().parentAsClass
// receiver will be stored as up value // receiver will be stored as up value
val dispatchReceiver = Variable(invokeFunction.dispatchReceiverParameter!!.symbol, state) val dispatchReceiver = invokeFunction.dispatchReceiverParameter!!.symbol to state
val newInvoke = invokeFunction.deepCopyWithSymbols(samClass).apply { dispatchReceiverParameter = null } val newInvoke = invokeFunction.deepCopyWithSymbols(samClass).apply { dispatchReceiverParameter = null }
KFunctionState(newInvoke, functionClass, environment, mutableListOf(dispatchReceiver)) KFunctionState(newInvoke, functionClass, environment, mutableMapOf(dispatchReceiver)).apply {
.apply { this.funInterface = typeOperand } this.funInterface = typeOperand
}
} }
} }
callStack.pushState(newState) callStack.pushState(newState)
@@ -532,7 +528,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
else -> arrayToList(result.value) else -> arrayToList(result.value)
} }
is Common -> when { is Common -> when {
result.irClass.defaultType.isUnsignedArray() -> arrayToList((result.fields.single().state as Primitive<*>).value) result.irClass.defaultType.isUnsignedArray() -> arrayToList((result.fields.values.single() as Primitive<*>).value)
else -> listOf(result.asProxy(callInterceptor)) else -> listOf(result.asProxy(callInterceptor))
} }
else -> listOf(result) else -> listOf(result)
@@ -545,12 +541,12 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val storageProperty = owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "storage" } val storageProperty = owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "storage" }
val primitiveArray = args.map { val primitiveArray = args.map {
when (it) { when (it) {
is Proxy -> (it.state.fields.single().state as Primitive<*>).value // is unsigned number is Proxy -> (it.state.fields.values.single() as Primitive<*>).value // is unsigned number
else -> it // is primitive number else -> it // is primitive number
} }
} }
val unsignedArray = primitiveArray.toPrimitiveStateArray(storageProperty.backingField!!.type) val unsignedArray = primitiveArray.toPrimitiveStateArray(storageProperty.backingField!!.type)
Common(owner).apply { fields.add(Variable(storageProperty.symbol, unsignedArray)) } Common(owner).apply { setField(storageProperty.symbol, unsignedArray) }
} }
else -> args.toPrimitiveStateArray(expression.type) else -> args.toPrimitiveStateArray(expression.type)
} }
@@ -604,8 +600,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val function = KFunctionState( val function = KFunctionState(
reference, reference,
environment, environment,
dispatchReceiver?.let { Variable(irFunction.getDispatchReceiver()!!, it) }, dispatchReceiver?.let { irFunction.getDispatchReceiver()!! to it },
extensionReceiver?.let { Variable(irFunction.getExtensionReceiver()!!, it) } extensionReceiver?.let { irFunction.getExtensionReceiver()!! to it }
) )
if (irFunction.isLocal) callStack.storeUpValues(function) if (irFunction.isLocal) callStack.storeUpValues(function)
callStack.pushState(function) callStack.pushState(function)
@@ -619,7 +615,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
fun List<IrTypeParameter>.addToFields() { fun List<IrTypeParameter>.addToFields() {
(0 until propertyReference.typeArgumentsCount).forEach { index -> (0 until propertyReference.typeArgumentsCount).forEach { index ->
val kTypeState = KTypeState(propertyReference.getTypeArgument(index)!!, environment.kTypeClass.owner) val kTypeState = KTypeState(propertyReference.getTypeArgument(index)!!, environment.kTypeClass.owner)
propertyState.fields += Variable(this[index].symbol, kTypeState) propertyState.setField(this[index].symbol, kTypeState)
} }
} }
propertyReference.getter?.owner?.typeParameters?.addToFields() propertyReference.getter?.owner?.typeParameters?.addToFields()
@@ -82,7 +82,7 @@ internal fun State.toIrExpression(expression: IrExpression): IrExpression {
is Complex -> { is Complex -> {
val stateType = this.irClass.defaultType val stateType = this.irClass.defaultType
when { when {
stateType.isUnsignedType() -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end) stateType.isUnsignedType() -> (this.fields.values.single() as Primitive<*>).value.toIrConst(type, start, end)
else -> expression else -> expression
} }
} }
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
import org.jetbrains.kotlin.utils.keysToMap
import java.lang.invoke.MethodType import java.lang.invoke.MethodType
val compileTimeAnnotation = FqName("kotlin.CompileTimeCalculation") val compileTimeAnnotation = FqName("kotlin.CompileTimeCalculation")
@@ -265,6 +266,13 @@ internal fun IrType.getTypeIfReified(getType: (IrClassifierSymbol) -> IrType): I
} }
} }
internal fun IrInterpreterEnvironment.loadReifiedTypeArguments(expression: IrFunctionAccessExpression): Map<IrTypeParameterSymbol, KTypeState> {
return expression.symbol.owner.typeParameters.filter { it.isReified }.map { it.symbol }.keysToMap {
val reifiedType = expression.getTypeArgument(it.owner.index)!!.getTypeIfReified(callStack)
KTypeState(reifiedType, this.kTypeClass.owner)
}
}
internal fun IrFunctionAccessExpression.getSuperEnumCall(): IrEnumConstructorCall { internal fun IrFunctionAccessExpression.getSuperEnumCall(): IrEnumConstructorCall {
val name = this.symbol.owner.parentClassOrNull?.fqName val name = this.symbol.owner.parentClassOrNull?.fqName
if (this is IrEnumConstructorCall && name == "kotlin.Enum") return this if (this is IrEnumConstructorCall && name == "kotlin.Enum") return this
@@ -274,12 +274,8 @@ internal object ArrayConstructor : IntrinsicBase() {
} }
} }
val state = irFunction.valueParameters.getOrNull(1)?.symbol?.let { environment.callStack.getState(it) as StateWithClosure } val type = (environment.callStack.getState(irFunction.symbol) as KTypeState).irType
val typeFromMemory = (environment.callStack.getState(irFunction.symbol) as KTypeState).irType environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type))
val type = state?.let {
typeFromMemory.getTypeIfReified { typeSymbol -> (it.upValues.single { it.symbol == typeSymbol }.state as KTypeState).irType }
}
environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type ?: typeFromMemory))
} }
} }
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.interpreter.* import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.getDispatchReceiver import org.jetbrains.kotlin.ir.interpreter.getDispatchReceiver
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.Common import org.jetbrains.kotlin.ir.interpreter.state.Common
import org.jetbrains.kotlin.ir.interpreter.state.State import org.jetbrains.kotlin.ir.interpreter.state.State
import org.jetbrains.kotlin.ir.util.isFakeOverriddenFromAny import org.jetbrains.kotlin.ir.util.isFakeOverriddenFromAny
@@ -34,31 +33,31 @@ internal class CommonProxy private constructor(override val state: Common, overr
if (this === other) return true if (this === other) return true
if (other == null) return false if (other == null) return false
val valueArguments = mutableListOf<Variable>() val valueArguments = mutableListOf<State>()
val equalsFun = state.getEqualsFunction() val equalsFun = state.getEqualsFunction()
if (equalsFun.isFakeOverriddenFromAny() || equalsFun.wasAlreadyCalled()) return defaultEquals(other) if (equalsFun.isFakeOverriddenFromAny() || equalsFun.wasAlreadyCalled()) return defaultEquals(other)
equalsFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } equalsFun.getDispatchReceiver()!!.let { valueArguments.add(state) }
valueArguments.add(Variable(equalsFun.valueParameters.single().symbol, if (other is Proxy) other.state else other as State)) valueArguments.add(if (other is Proxy) other.state else other as State)
return callInterceptor.interceptProxy(equalsFun, valueArguments) as Boolean return callInterceptor.interceptProxy(equalsFun, valueArguments) as Boolean
} }
override fun hashCode(): Int { override fun hashCode(): Int {
val valueArguments = mutableListOf<Variable>() val valueArguments = mutableListOf<State>()
val hashCodeFun = state.getHashCodeFunction() val hashCodeFun = state.getHashCodeFunction()
if (hashCodeFun.isFakeOverriddenFromAny() || hashCodeFun.wasAlreadyCalled()) return defaultHashCode() if (hashCodeFun.isFakeOverriddenFromAny() || hashCodeFun.wasAlreadyCalled()) return defaultHashCode()
hashCodeFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } hashCodeFun.getDispatchReceiver()!!.let { valueArguments.add(state) }
return callInterceptor.interceptProxy(hashCodeFun, valueArguments) as Int return callInterceptor.interceptProxy(hashCodeFun, valueArguments) as Int
} }
override fun toString(): String { override fun toString(): String {
val valueArguments = mutableListOf<Variable>() val valueArguments = mutableListOf<State>()
val toStringFun = state.getToStringFunction() val toStringFun = state.getToStringFunction()
if (toStringFun.isFakeOverriddenFromAny() || toStringFun.wasAlreadyCalled()) return defaultToString() if (toStringFun.isFakeOverriddenFromAny() || toStringFun.wasAlreadyCalled()) return defaultToString()
toStringFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) } toStringFun.getDispatchReceiver()!!.let { valueArguments.add(state) }
return callInterceptor.interceptProxy(toStringFun, valueArguments) as String return callInterceptor.interceptProxy(toStringFun, valueArguments) as String
} }
@@ -81,10 +80,9 @@ internal class CommonProxy private constructor(override val state: Common, overr
else -> { else -> {
val irFunction = commonProxy.state.getIrFunction(method) val irFunction = commonProxy.state.getIrFunction(method)
?: return@newProxyInstance commonProxy.fallbackIfMethodNotFound(method) ?: return@newProxyInstance commonProxy.fallbackIfMethodNotFound(method)
val valueArguments = mutableListOf<Variable>() val valueArguments = mutableListOf<State>(commonProxy.state)
valueArguments += Variable(irFunction.getDispatchReceiver()!!, commonProxy.state)
valueArguments += irFunction.valueParameters.mapIndexed { index, parameter -> valueArguments += irFunction.valueParameters.mapIndexed { index, parameter ->
Variable(parameter.symbol, callInterceptor.environment.convertToState(args[index], parameter.type)) callInterceptor.environment.convertToState(args[index], parameter.type)
} }
callInterceptor.interceptProxy(irFunction, valueArguments, method.returnType) callInterceptor.interceptProxy(irFunction, valueArguments, method.returnType)
} }
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrReturn import org.jetbrains.kotlin.ir.expressions.IrReturn
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.hasTheSameFieldsWith import org.jetbrains.kotlin.ir.interpreter.state.hasTheSameFieldsWith
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
@@ -52,12 +51,10 @@ internal class KFunctionProxy(
override fun call(vararg args: Any?): Any? { override fun call(vararg args: Any?): Any? {
// TODO check arity // TODO check arity
var index = 0 var index = 0
val dispatchReceiver = state.irFunction.dispatchReceiverParameter val dispatchReceiver = state.irFunction.dispatchReceiverParameter?.let { environment.convertToState(args[index++], it.type) }
?.let { Variable(it.symbol, environment.convertToState(args[index++], it.type)) } val extensionReceiver = state.irFunction.extensionReceiverParameter?.let { environment.convertToState(args[index++], it.type) }
val extensionReceiver = state.irFunction.extensionReceiverParameter
?.let { Variable(it.symbol, environment.convertToState(args[index++], it.type)) }
val argsVariables = state.irFunction.valueParameters.map { parameter -> val argsVariables = state.irFunction.valueParameters.map { parameter ->
Variable(parameter.symbol, environment.convertToState(args[index++], parameter.type)) environment.convertToState(args[index++], parameter.type)
} }
val valueArguments = listOfNotNull(dispatchReceiver, extensionReceiver) + argsVariables val valueArguments = listOfNotNull(dispatchReceiver, extensionReceiver) + argsVariables
return callInterceptor.interceptProxy(state.irFunction, valueArguments) return callInterceptor.interceptProxy(state.irFunction, valueArguments)
@@ -5,16 +5,16 @@
package org.jetbrains.kotlin.ir.interpreter.proxy.reflection package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.exceptions.verify import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
import org.jetbrains.kotlin.ir.interpreter.getExtensionReceiver import org.jetbrains.kotlin.ir.interpreter.getExtensionReceiver
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.isNull import org.jetbrains.kotlin.ir.interpreter.state.isNull
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState
import org.jetbrains.kotlin.ir.util.isObject import org.jetbrains.kotlin.ir.util.isObject
import org.jetbrains.kotlin.ir.util.resolveFakeOverride import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import kotlin.reflect.* import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KParameter
import kotlin.reflect.KProperty0
internal open class KProperty0Proxy( internal open class KProperty0Proxy(
state: KPropertyState, callInterceptor: CallInterceptor state: KPropertyState, callInterceptor: CallInterceptor
@@ -32,11 +32,7 @@ internal open class KProperty0Proxy(
val value = receiver.getField(actualPropertySymbol) val value = receiver.getField(actualPropertySymbol)
return when { return when {
// null value <=> property is extension or Primitive; receiver.isNull() <=> nullable extension // null value <=> property is extension or Primitive; receiver.isNull() <=> nullable extension
value == null || receiver.isNull() -> { value == null || receiver.isNull() -> callInterceptor.interceptProxy(getter, listOf(receiver))
val receiverSymbol = getter.getReceiver()
val receiverVariable = receiverSymbol?.let { Variable(it, receiver) }
callInterceptor.interceptProxy(getter, listOfNotNull(receiverVariable))
}
else -> value else -> value
} }
} }
@@ -70,11 +66,8 @@ internal class KMutableProperty0Proxy(
val receiver = state.receiver!! val receiver = state.receiver!!
val newValue = environment.convertToState(args.single(), propertyType) val newValue = environment.convertToState(args.single(), propertyType)
setter.getExtensionReceiver() setter.getExtensionReceiver()
?.let { ?.let { callInterceptor.interceptProxy(setter, listOf(receiver, newValue)) }
val fieldSymbol = setter.valueParameters.single().symbol ?: receiver.setField(state.property.symbol, newValue)
callInterceptor.interceptProxy(setter, listOf(Variable(it, receiver), Variable(fieldSymbol, newValue)))
}
?: receiver.setField(Variable(state.property.symbol, newValue))
} }
override fun callBy(args: Map<KParameter, Any?>) { override fun callBy(args: Map<KParameter, Any?>) {
@@ -7,13 +7,14 @@ package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState 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.KTypeState
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrFail
import kotlin.reflect.* import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KParameter
import kotlin.reflect.KProperty1
internal open class KProperty1Proxy( internal open class KProperty1Proxy(
state: KPropertyState, callInterceptor: CallInterceptor state: KPropertyState, callInterceptor: CallInterceptor
@@ -32,7 +33,7 @@ internal open class KProperty1Proxy(
override fun call(vararg args: Any?): Any? { override fun call(vararg args: Any?): Any? {
checkArguments(1, args.size) checkArguments(1, args.size)
val receiverParameter = (getter.dispatchReceiverParameter ?: getter.extensionReceiverParameter)!! val receiverParameter = (getter.dispatchReceiverParameter ?: getter.extensionReceiverParameter)!!
val receiver = Variable(receiverParameter.symbol, environment.convertToState(args[0], receiverParameter.getActualType())) val receiver = environment.convertToState(args[0], receiverParameter.getActualType())
return callInterceptor.interceptProxy(getter, listOf(receiver)) return callInterceptor.interceptProxy(getter, listOf(receiver))
} }
@@ -60,9 +61,9 @@ internal class KMutableProperty1Proxy(
override fun call(vararg args: Any?) { override fun call(vararg args: Any?) {
checkArguments(2, args.size) checkArguments(2, args.size)
val receiverParameter = (setter.dispatchReceiverParameter ?: setter.extensionReceiverParameter)!! val receiverParameter = (setter.dispatchReceiverParameter ?: setter.extensionReceiverParameter)!!
val receiver = Variable(receiverParameter.symbol, environment.convertToState(args[0], receiverParameter.getActualType())) val receiver = environment.convertToState(args[0], receiverParameter.getActualType())
val valueParameter = setter.valueParameters.single() val valueParameter = setter.valueParameters.single()
val value = Variable(valueParameter.symbol, environment.convertToState(args[1], valueParameter.getActualType())) val value = environment.convertToState(args[1], valueParameter.getActualType())
callInterceptor.interceptProxy(setter, listOf(receiver, value)) callInterceptor.interceptProxy(setter, listOf(receiver, value))
} }
@@ -6,9 +6,10 @@
package org.jetbrains.kotlin.ir.interpreter.proxy.reflection package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState
import kotlin.reflect.* import kotlin.reflect.KMutableProperty2
import kotlin.reflect.KParameter
import kotlin.reflect.KProperty2
internal open class KProperty2Proxy( internal open class KProperty2Proxy(
state: KPropertyState, callInterceptor: CallInterceptor state: KPropertyState, callInterceptor: CallInterceptor
@@ -21,8 +22,8 @@ internal open class KProperty2Proxy(
checkArguments(2, args.size) checkArguments(2, args.size)
val dispatchParameter = getter.dispatchReceiverParameter!! val dispatchParameter = getter.dispatchReceiverParameter!!
val extensionReceiverParameter = getter.extensionReceiverParameter!! val extensionReceiverParameter = getter.extensionReceiverParameter!!
val dispatch = Variable(dispatchParameter.symbol, environment.convertToState(args[0], dispatchParameter.type)) val dispatch = environment.convertToState(args[0], dispatchParameter.type)
val extension = Variable(extensionReceiverParameter.symbol, environment.convertToState(args[1], extensionReceiverParameter.type)) val extension = environment.convertToState(args[1], extensionReceiverParameter.type)
return callInterceptor.interceptProxy(getter, listOf(dispatch, extension)) return callInterceptor.interceptProxy(getter, listOf(dispatch, extension))
} }
@@ -25,18 +25,15 @@ internal class CallStack {
internal val currentFrameOwner get() = currentFrame.currentSubFrameOwner internal val currentFrameOwner get() = currentFrame.currentSubFrameOwner
fun newFrame(frameOwner: IrElement, irFile: IrFile? = null) { fun newFrame(frameOwner: IrElement, irFile: IrFile? = null) {
val newFrame = SubFrame(frameOwner) frames.add(Frame(frameOwner, irFile))
frames.add(Frame(newFrame, irFile))
} }
fun newFrame(frameOwner: IrFunction) { fun newFrame(frameOwner: IrFunction) {
val newFrame = SubFrame(frameOwner) frames.add(Frame(frameOwner, frameOwner.fileOrNull))
frames.add(Frame(newFrame, frameOwner.fileOrNull))
} }
fun newSubFrame(frameOwner: IrElement) { fun newSubFrame(frameOwner: IrElement) {
val newFrame = SubFrame(frameOwner) currentFrame.addSubFrame(frameOwner)
currentFrame.addSubFrame(newFrame)
} }
fun dropFrame() { fun dropFrame() {
@@ -174,8 +171,12 @@ internal class CallStack {
fun popState(): State = currentFrame.popState() fun popState(): State = currentFrame.popState()
fun peekState(): State? = currentFrame.peekState() fun peekState(): State? = currentFrame.peekState()
fun addVariable(variable: Variable) { fun addVariable(symbol: IrSymbol, state: State?) {
currentFrame.addVariable(variable) currentFrame.addVariable(symbol, state)
}
private fun addVariable(symbol: IrSymbol, variable: Variable) {
currentFrame.addVariable(symbol, variable)
} }
fun getState(symbol: IrSymbol): State = currentFrame.getState(symbol) fun getState(symbol: IrSymbol): State = currentFrame.getState(symbol)
@@ -184,19 +185,15 @@ internal class CallStack {
fun storeUpValues(state: StateWithClosure) { fun storeUpValues(state: StateWithClosure) {
// TODO save only necessary declarations // TODO save only necessary declarations
currentFrame.getAll().reversed().forEach { variable -> currentFrame.copyMemoryInto(state)
// TODO replace list with map
val index = state.upValues.indexOfFirst { it.symbol == variable.symbol }
if (index == -1) state.upValues.add(variable) else state.upValues[index] = variable
}
} }
fun loadUpValues(state: StateWithClosure) { fun loadUpValues(state: StateWithClosure) {
state.upValues.forEach { addVariable(it) } state.upValues.forEach { (symbol, variable) -> addVariable(symbol, variable) }
} }
fun copyUpValuesFromPreviousFrame() { fun copyUpValuesFromPreviousFrame() {
frames[frames.size - 2].getAll().forEach { if (!containsVariable(it.symbol)) addVariable(it) } frames[frames.size - 2].copyMemoryInto(currentFrame)
} }
fun getStackTrace(): List<String> { fun getStackTrace(): List<String> {
@@ -11,12 +11,13 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.interpreter.Instruction import org.jetbrains.kotlin.ir.interpreter.Instruction
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
import org.jetbrains.kotlin.ir.interpreter.state.State import org.jetbrains.kotlin.ir.interpreter.state.State
import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) { internal class Frame(subFrameOwner: IrElement, val irFile: IrFile? = null) {
private val innerStack = mutableListOf(subFrame) private val innerStack = mutableListOf(SubFrame(subFrameOwner))
private var currentInstruction: Instruction? = null private var currentInstruction: Instruction? = null
private val currentFrame get() = innerStack.last() private val currentFrame get() = innerStack.last()
@@ -26,8 +27,8 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
const val NOT_DEFINED = "Not defined" const val NOT_DEFINED = "Not defined"
} }
fun addSubFrame(frame: SubFrame) { fun addSubFrame(subFrameOwner: IrElement) {
innerStack.add(frame) innerStack.add(SubFrame(subFrameOwner))
} }
fun removeSubFrame() { fun removeSubFrame() {
@@ -59,8 +60,12 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
fun popState(): State = currentFrame.popState() fun popState(): State = currentFrame.popState()
fun peekState(): State? = currentFrame.peekState() fun peekState(): State? = currentFrame.peekState()
fun addVariable(variable: Variable) { fun addVariable(symbol: IrSymbol, state: State?) {
currentFrame.addVariable(variable) currentFrame.addVariable(symbol, state)
}
fun addVariable(symbol: IrSymbol, variable: Variable) {
currentFrame.addVariable(symbol, variable)
} }
fun getState(symbol: IrSymbol): State { fun getState(symbol: IrSymbol): State {
@@ -77,7 +82,15 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
fun containsVariable(symbol: IrSymbol): Boolean = (innerStack.lastIndex downTo 0).any { innerStack[it].containsVariable(symbol) } fun containsVariable(symbol: IrSymbol): Boolean = (innerStack.lastIndex downTo 0).any { innerStack[it].containsVariable(symbol) }
fun getAll(): List<Variable> = innerStack.flatMap { it.getAll() } fun copyMemoryInto(newFrame: Frame) {
this.getAll().forEach { (symbol, variable) -> if (!newFrame.containsVariable(symbol)) newFrame.addVariable(symbol, variable) }
}
fun copyMemoryInto(closure: StateWithClosure) {
getAll().reversed().forEach { (symbol, variable) -> closure.upValues[symbol] = variable }
}
private fun getAll(): List<Pair<IrSymbol, Variable>> = innerStack.flatMap { it.getAll() }
private fun getLineNumberForCurrentInstruction(): String { private fun getLineNumberForCurrentInstruction(): String {
irFile ?: return "" irFile ?: return ""
@@ -105,10 +118,10 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
} }
} }
internal class SubFrame(val owner: IrElement) { private class SubFrame(val owner: IrElement) {
private val instructions = mutableListOf<Instruction>() private val instructions = mutableListOf<Instruction>()
private val dataStack = DataStack() private val dataStack = DataStack()
private val memory = mutableListOf<Variable>() private val memory = mutableMapOf<IrSymbol, Variable>()
// Methods to work with instruction // Methods to work with instruction
fun isEmpty() = instructions.isEmpty() fun isEmpty() = instructions.isEmpty()
@@ -122,18 +135,21 @@ internal class SubFrame(val owner: IrElement) {
fun peekState(): State? = dataStack.peek() fun peekState(): State? = dataStack.peek()
// Methods to work with memory // Methods to work with memory
fun addVariable(variable: Variable) { fun addVariable(symbol: IrSymbol, variable: Variable) {
memory.add(0, variable) memory[symbol] = variable
} }
private fun getVariable(symbol: IrSymbol): Variable? = memory.firstOrNull { it.symbol == symbol } fun addVariable(symbol: IrSymbol, state: State?) {
fun containsVariable(symbol: IrSymbol): Boolean = getVariable(symbol) != null memory[symbol] = Variable(state)
fun getState(symbol: IrSymbol): State? = getVariable(symbol)?.state }
fun containsVariable(symbol: IrSymbol): Boolean = memory[symbol] != null
fun getState(symbol: IrSymbol): State? = memory[symbol]?.state
fun setState(symbol: IrSymbol, newState: State) { fun setState(symbol: IrSymbol, newState: State) {
getVariable(symbol)?.state = newState memory[symbol]?.state = newState
} }
fun getAll(): List<Variable> = memory fun getAll(): List<Pair<IrSymbol, Variable>> = memory.toList()
} }
private class DataStack { private class DataStack {
@@ -1,23 +1,10 @@
/* /*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * 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. * 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.stack package org.jetbrains.kotlin.ir.interpreter.stack
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
import org.jetbrains.kotlin.ir.interpreter.state.State import org.jetbrains.kotlin.ir.interpreter.state.State
import org.jetbrains.kotlin.ir.symbols.IrSymbol
// TODO maybe switch to typealias and use map instead of list internal data class Variable(var state: State?)
internal data class Variable(val symbol: IrSymbol) {
lateinit var state: State
constructor(symbol: IrSymbol, state: State) : this(symbol) {
this.state = state
}
override fun toString(): String {
return "Variable(symbol=${(symbol.owner as? IrDeclarationWithName)?.name}, state=$state)"
}
}
@@ -13,17 +13,20 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.interpreter.createCall import org.jetbrains.kotlin.ir.interpreter.createCall
import org.jetbrains.kotlin.ir.interpreter.fqName import org.jetbrains.kotlin.ir.interpreter.fqName
import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.util.nameForIrSerialization import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import org.jetbrains.kotlin.ir.util.resolveFakeOverride import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
internal class Common private constructor(override val irClass: IrClass, override val fields: MutableList<Variable>) : Complex, StateWithClosure { internal class Common private constructor(
override val upValues: MutableList<Variable> = mutableListOf() override val irClass: IrClass, override val fields: MutableMap<IrSymbol, State>
) : Complex, StateWithClosure {
override val upValues: MutableMap<IrSymbol, Variable> = mutableMapOf()
override var superWrapperClass: Wrapper? = null override var superWrapperClass: Wrapper? = null
override var outerClass: Variable? = null override var outerClass: Pair<IrSymbol, State>? = null
constructor(irClass: IrClass) : this(irClass, mutableListOf()) constructor(irClass: IrClass) : this(irClass, mutableMapOf())
// This method is used to get correct java method name // This method is used to get correct java method name
private fun getKotlinName(declaringClassName: String, methodName: String): String { private fun getKotlinName(declaringClassName: String, methodName: String): String {
@@ -5,18 +5,21 @@
package org.jetbrains.kotlin.ir.interpreter.state package org.jetbrains.kotlin.ir.interpreter.state
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.interpreter.fqName import org.jetbrains.kotlin.ir.interpreter.fqName
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.util.overrides import org.jetbrains.kotlin.ir.util.overrides
import org.jetbrains.kotlin.ir.util.resolveFakeOverride import org.jetbrains.kotlin.ir.util.resolveFakeOverride
internal interface Complex : State { internal interface Complex : State {
var superWrapperClass: Wrapper? var superWrapperClass: Wrapper?
var outerClass: Variable? var outerClass: Pair<IrSymbol, State>?
fun irClassFqName() = irClass.fqName fun irClassFqName() = irClass.fqName
@@ -53,12 +56,12 @@ internal interface Complex : State {
return list return list
} }
generateSequence(outerClass) { (it.state as? Complex)?.outerClass } generateSequence(outerClass) { (it.second as? Complex)?.outerClass }
.toList() .toList()
.takeFromEndWhile { receiver == null || it.symbol != receiver } // only state's below receiver must be loaded on stack .takeFromEndWhile { receiver == null || it.first != receiver } // only state's below receiver must be loaded on stack
.forEach { variable -> .forEach { (symbol, state) ->
callStack.addVariable(variable) callStack.addVariable(symbol, state)
(variable.state as? StateWithClosure)?.let { callStack.loadUpValues(it) } (state as? StateWithClosure)?.let { callStack.loadUpValues(it) }
} }
} }
} }
@@ -8,15 +8,16 @@ package org.jetbrains.kotlin.ir.interpreter.state
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.interpreter.getOriginalPropertyByName import org.jetbrains.kotlin.ir.interpreter.getOriginalPropertyByName
import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.isSubclassOf import org.jetbrains.kotlin.ir.util.isSubclassOf
import kotlin.math.min import kotlin.math.min
internal class ExceptionState private constructor( internal class ExceptionState private constructor(
override val irClass: IrClass, override val fields: MutableList<Variable>, stackTrace: List<String> override val irClass: IrClass, override val fields: MutableMap<IrSymbol, State>, stackTrace: List<String>
) : Complex, StateWithClosure, Throwable() { ) : Complex, StateWithClosure, Throwable() {
override val upValues: MutableList<Variable> = mutableListOf() override val upValues: MutableMap<IrSymbol, Variable> = mutableMapOf()
override var superWrapperClass: Wrapper? = null override var superWrapperClass: Wrapper? = null
override var outerClass: Variable? = null override var outerClass: Pair<IrSymbol, State>? = null
override val message: String? override val message: String?
get() = getField(messageProperty.symbol)?.asStringOrNull() get() = getField(messageProperty.symbol)?.asStringOrNull()
@@ -32,11 +33,11 @@ internal class ExceptionState private constructor(
init { init {
if (!this::exceptionFqName.isInitialized) this.exceptionFqName = irClassFqName() if (!this::exceptionFqName.isInitialized) this.exceptionFqName = irClassFqName()
if (fields.none { it.symbol == messageProperty.symbol }) setMessage(null) if (!fields.containsKey(messageProperty.symbol)) setMessage(null)
if (fields.none { it.symbol == causeProperty.symbol }) setCause(null) if (!fields.containsKey(causeProperty.symbol)) setCause(null)
} }
constructor(irClass: IrClass, stackTrace: List<String>) : this(irClass, mutableListOf(), stackTrace) constructor(irClass: IrClass, stackTrace: List<String>) : this(irClass, mutableMapOf(), stackTrace)
constructor( constructor(
exception: Throwable, irClass: IrClass, stackTrace: List<String> exception: Throwable, irClass: IrClass, stackTrace: List<String>
@@ -58,8 +59,8 @@ internal class ExceptionState private constructor(
} }
} }
override fun setField(newVar: Variable) { override fun setField(symbol: IrSymbol, state: State) {
super.setField(newVar) super.setField(symbol, state)
recalculateCauseAndMessage() recalculateCauseAndMessage()
} }
@@ -78,11 +79,11 @@ internal class ExceptionState private constructor(
} }
private fun setMessage(messageValue: String?) { private fun setMessage(messageValue: String?) {
setField(Variable(messageProperty.symbol, Primitive(messageValue, messageProperty.getter!!.returnType))) setField(messageProperty.symbol, Primitive(messageValue, messageProperty.getter!!.returnType))
} }
private fun setCause(causeValue: State?) { private fun setCause(causeValue: State?) {
setField(Variable(causeProperty.symbol, causeValue ?: Primitive.nullStateOfType(causeProperty.getter!!.returnType))) setField(causeProperty.symbol, causeValue ?: Primitive.nullStateOfType(causeProperty.getter!!.returnType))
} }
fun getFullDescription(): String { fun getFullDescription(): String {
@@ -99,15 +100,15 @@ internal class ExceptionState private constructor(
override fun toString(): String = message?.let { "$exceptionFqName: $it" } ?: exceptionFqName override fun toString(): String = message?.let { "$exceptionFqName: $it" } ?: exceptionFqName
companion object { companion object {
private fun evaluateFields(exception: Throwable, irClass: IrClass, stackTrace: List<String>): MutableList<Variable> { private fun evaluateFields(exception: Throwable, irClass: IrClass, stackTrace: List<String>): MutableMap<IrSymbol, State> {
val messageProperty = irClass.getOriginalPropertyByName("message") val messageProperty = irClass.getOriginalPropertyByName("message")
val causeProperty = irClass.getOriginalPropertyByName("cause") val causeProperty = irClass.getOriginalPropertyByName("cause")
val messageVar = Variable(messageProperty.symbol, Primitive(exception.message, messageProperty.getter!!.returnType)) val messageVar = messageProperty.symbol to Primitive(exception.message, messageProperty.getter!!.returnType)
val causeVar = exception.cause?.let { val causeVar = exception.cause?.let {
Variable(causeProperty.symbol, ExceptionState(it, irClass, stackTrace + it.stackTrace.reversed().map { "at $it" })) causeProperty.symbol to ExceptionState(it, irClass, stackTrace + it.stackTrace.reversed().map { "at $it" })
} }
return causeVar?.let { mutableListOf(messageVar, it) } ?: mutableListOf(messageVar) return causeVar?.let { mutableMapOf(messageVar, it) } ?: mutableMapOf(messageVar)
} }
private fun evaluateAdditionalStackTrace(e: Throwable): List<String> { private fun evaluateAdditionalStackTrace(e: Throwable): List<String> {
@@ -9,14 +9,13 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.interpreter.getLastOverridden import org.jetbrains.kotlin.ir.interpreter.getLastOverridden
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
internal class Primitive<T>(val value: T, val type: IrType) : State { internal class Primitive<T>(val value: T, val type: IrType) : State {
override val fields: MutableList<Variable> = mutableListOf() override val fields: MutableMap<IrSymbol, State> = mutableMapOf()
override val irClass: IrClass = type.classOrNull!!.owner override val irClass: IrClass = type.classOrNull!!.owner
override fun getField(symbol: IrSymbol): State? = null override fun getField(symbol: IrSymbol): State? = null
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.isFunction import org.jetbrains.kotlin.ir.interpreter.isFunction
import org.jetbrains.kotlin.ir.interpreter.isKFunction import org.jetbrains.kotlin.ir.interpreter.isKFunction
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
@@ -22,18 +21,15 @@ import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
internal interface State { internal interface State {
val fields: MutableList<Variable> val fields: MutableMap<IrSymbol, State>
val irClass: IrClass val irClass: IrClass
fun getField(symbol: IrSymbol): State? { fun getField(symbol: IrSymbol): State? {
return fields.firstOrNull { it.symbol == symbol }?.state return fields[symbol]
} }
fun setField(newVar: Variable) { fun setField(symbol: IrSymbol, state: State) {
when (val oldState = fields.firstOrNull { it.symbol == newVar.symbol }) { fields[symbol] = state
null -> fields.add(newVar) // newVar isn't present in value list
else -> fields[fields.indexOf(oldState)].state = newVar.state // newVar already present
}
} }
fun getIrFunctionByIrCall(expression: IrCall): IrFunction? fun getIrFunctionByIrCall(expression: IrCall): IrFunction?
@@ -103,9 +99,8 @@ internal fun State?.mustBeHandledAsReflection(call: IrCall): Boolean {
internal fun State.hasTheSameFieldsWith(other: State): Boolean { internal fun State.hasTheSameFieldsWith(other: State): Boolean {
if (this.fields.size != other.fields.size) return false if (this.fields.size != other.fields.size) return false
for (i in 0 until this.fields.size) { // TODO prove that this will always work or find better solution
val firstState = this.fields[i].state this.fields.values.zip(other.fields.values).forEach { (firstState, secondState) ->
val secondState = other.fields[i].state
when { when {
firstState is Primitive<*> && secondState is Primitive<*> -> if (firstState.value != secondState.value) return false firstState is Primitive<*> && secondState is Primitive<*> -> if (firstState.value != secondState.value) return false
else -> if (firstState !== secondState) return false else -> if (firstState !== secondState) return false
@@ -6,7 +6,8 @@
package org.jetbrains.kotlin.ir.interpreter.state package org.jetbrains.kotlin.ir.interpreter.state
import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.symbols.IrSymbol
internal interface StateWithClosure { internal interface StateWithClosure {
val upValues: MutableList<Variable> val upValues: MutableMap<IrSymbol, Variable>
} }
@@ -10,8 +10,8 @@ import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.interpreter.* import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
@@ -23,10 +23,10 @@ import kotlin.collections.HashMap
import kotlin.collections.LinkedHashMap import kotlin.collections.LinkedHashMap
internal class Wrapper(val value: Any, override val irClass: IrClass, environment: IrInterpreterEnvironment) : Complex { internal class Wrapper(val value: Any, override val irClass: IrClass, environment: IrInterpreterEnvironment) : Complex {
override val fields: MutableList<Variable> = mutableListOf() override val fields: MutableMap<IrSymbol, State> = mutableMapOf()
override var superWrapperClass: Wrapper? = null override var superWrapperClass: Wrapper? = null
override var outerClass: Variable? = null override var outerClass: Pair<IrSymbol, State>? = null
private val receiverClass = irClass.defaultType.getClass(true) private val receiverClass = irClass.defaultType.getClass(true)
@@ -15,16 +15,18 @@ 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.KTypeParameterProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.State
import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.resolveFakeOverride import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.util.OperatorNameConventions
import kotlin.reflect.KParameter import kotlin.reflect.KParameter
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter import kotlin.reflect.KTypeParameter
@@ -33,9 +35,9 @@ internal class KFunctionState(
val irFunction: IrFunction, val irFunction: IrFunction,
override val irClass: IrClass, override val irClass: IrClass,
environment: IrInterpreterEnvironment, environment: IrInterpreterEnvironment,
override val fields: MutableList<Variable> = mutableListOf() override val fields: MutableMap<IrSymbol, State> = mutableMapOf()
) : ReflectionState(), StateWithClosure { ) : ReflectionState(), StateWithClosure {
override val upValues: MutableList<Variable> = mutableListOf() override val upValues: MutableMap<IrSymbol, Variable> = mutableMapOf()
var funInterface: IrType? = null var funInterface: IrType? = null
set(value) { set(value) {
@@ -123,16 +125,18 @@ internal class KFunctionState(
constructor( constructor(
functionReference: IrFunctionReference, functionReference: IrFunctionReference,
environment: IrInterpreterEnvironment, environment: IrInterpreterEnvironment,
dispatchReceiver: Variable?, dispatchReceiver: Pair<IrSymbol, State>?,
extensionReceiver: Variable? extensionReceiver: Pair<IrSymbol, State>?
) : this( ) : this(
functionReference.symbol.owner, functionReference.symbol.owner,
functionReference.type.classOrNull!!.owner, functionReference.type.classOrNull!!.owner,
environment, environment,
listOfNotNull(dispatchReceiver, extensionReceiver).toMutableList() listOfNotNull(dispatchReceiver, extensionReceiver).toMap().toMutableMap()
) { ) {
dispatchReceiver?.let { (symbol, state) -> setField(symbol, state) }
extensionReceiver?.let { (symbol, state) -> setField(symbol, state) }
// receivers are used in comparison of two functions in KFunctionProxy // receivers are used in comparison of two functions in KFunctionProxy
upValues += fields upValues += fields.map { it.key to Variable(it.value) }
} }
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? { override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
@@ -5,25 +5,20 @@
package org.jetbrains.kotlin.ir.interpreter.state.reflection package org.jetbrains.kotlin.ir.interpreter.state.reflection
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.State import org.jetbrains.kotlin.ir.interpreter.state.State
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import org.jetbrains.kotlin.ir.util.parentClassOrNull import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.util.render
import kotlin.math.min import kotlin.math.min
internal abstract class ReflectionState : State { internal abstract class ReflectionState : State {
override val fields: MutableList<Variable> = mutableListOf() override val fields: MutableMap<IrSymbol, State> = mutableMapOf()
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null