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.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.KTypeState
import org.jetbrains.kotlin.ir.types.IrType
@@ -35,7 +34,7 @@ internal interface CallInterceptor {
val irBuiltIns: IrBuiltIns
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 interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List<State>, 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
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()
return interpreter.withNewCallStack(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)
}
@@ -78,7 +77,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
val irConstructor = constructorCall.symbol.owner
val irClass = irConstructor.parentAsClass
when {
Wrapper.mustBeHandledWithWrapper(irClass) || irClass.fqName.startsWith("java") -> {
Wrapper.mustBeHandledWithWrapper(irClass) -> {
Wrapper.getConstructorMethod(irConstructor).invokeMethod(irConstructor, args)
when {
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() -> {
// 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()}" }
}
irClass.defaultType.isUnsignedType() -> {
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()
}
@@ -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.verify
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.types.classOrNull
import org.jetbrains.kotlin.ir.types.isUnit
@@ -98,7 +97,7 @@ private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack)
irClass.declarations.filterIsInstance<IrProperty>().forEach { property ->
val parameter = constructor.valueParameters.singleOrNull { it.name == property.name }
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 -> {
@@ -268,7 +267,7 @@ private fun unfoldGetEnumValue(expression: IrGetEnumValue, environment: IrInterp
private fun unfoldVariable(variable: IrVariable, callStack: CallStack) {
when (variable.initializer) {
null -> callStack.addVariable(Variable(variable.symbol))
null -> callStack.addVariable(variable.symbol, null)
else -> {
callStack.addInstruction(SimpleInstruction(variable))
callStack.addInstruction(CompoundInstruction(variable.initializer!!))
@@ -337,7 +336,7 @@ private fun unfoldCatch(element: IrCatch, callStack: CallStack) {
val frameOwner = callStack.currentFrameOwner as IrTry
callStack.dropSubFrame() // drop other catch blocks
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(CompoundInstruction(element.result))
}
@@ -360,7 +359,7 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
// TODO this check can be dropped after serialization introduction
// for now declarations in unsigned class don't have bodies and must be treated separately
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 Short -> value.toUShort().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.impl.IrConstructorCallImpl
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.Proxy
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.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
@@ -108,7 +105,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
is IrGetEnumValue -> interpretGetEnumValue(element)
is IrEnumEntry -> interpretEnumEntry(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 IrTypeOperatorCall -> interpretTypeOperatorCall(element)
is IrBranch -> interpretBranch(element)
@@ -173,11 +170,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
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
val reifiedTypeArguments = irFunction.typeParameters.filter { it.isReified }
.map {
val reifiedType = call.getTypeArgument(it.index)!!.getTypeIfReified(callStack)
Variable(it.symbol, KTypeState(reifiedType, environment.kTypeClass.owner))
}
val reifiedTypeArguments = environment.loadReifiedTypeArguments(call)
callStack.newFrame(irFunction)
callStack.addInstruction(SimpleInstruction(irFunction))
@@ -188,14 +181,14 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame()
// 5. store arguments in memory (remap args on actual names)
irFunction.getDispatchReceiver()?.let { callStack.addVariable(Variable(it, dispatchReceiver!!)) }
irFunction.getExtensionReceiver()?.let { callStack.addVariable(Variable(it, extensionReceiver ?: callStack.getState(it))) }
irFunction.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) }
irFunction.getDispatchReceiver()?.let { callStack.addVariable(it, dispatchReceiver!!) }
irFunction.getExtensionReceiver()?.let { callStack.addVariable(it, extensionReceiver ?: callStack.getState(it)) }
irFunction.valueParameters.forEachIndexed { i, param -> callStack.addVariable(param.symbol, valueArguments[i]) }
// `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
reifiedTypeArguments.forEach { callStack.addVariable(it) }
reifiedTypeArguments.forEach { callStack.addVariable(it.key, it.value) }
// 7. load outer class object
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 receiver = irClass.thisReceiver!!.symbol
val receiverState = callStack.getState(receiver)
receiverState.setField(Variable(field.correspondingPropertySymbol!!, callStack.popState()))
receiverState.setField(field.correspondingPropertySymbol!!, callStack.popState())
}
@Suppress("UNUSED_PARAMETER")
@@ -247,13 +240,15 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure)
val outerClass = receiverSymbol?.let { callStack.popState() }
val returnType = constructorCall.type.getTypeIfReified(callStack)
callStack.newFrame(constructor)
callStack.addInstruction(SimpleInstruction(constructor))
if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure)
callStack.addVariable(Variable(constructorCall.getThisReceiver(), objectState))
constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) }
callStack.addVariable(constructorCall.getThisReceiver(), objectState)
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)) {
null -> null // for jvm
@@ -262,16 +257,16 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
is IrBlock -> (irStatement.statements.last() as IrFunctionAccessExpression).getThisReceiver()
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) {
val outerClassVar = Variable(irClass.parentAsClass.thisReceiver!!.symbol, outerClass)
(objectState as Complex).outerClass = outerClassVar
val outerClassSymbolToState = irClass.parentAsClass.thisReceiver!!.symbol to outerClass
(objectState as Complex).outerClass = outerClassSymbolToState
if (superReceiver?.owner?.type != receiverSymbol.owner.type) {
// 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.
// 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
objectState.loadOuterClassesInto(callStack, constructorCall.getThisReceiver())
}
@@ -349,7 +344,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
private fun interpretSetField(expression: IrSetField) {
val receiver = (expression.receiver as IrDeclarationReference).symbol
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) {
@@ -427,13 +422,13 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
valueArguments.forEachIndexed { index, irConst -> enumSuperCall.putValueArgument(index, irConst) }
}
val enumClassObject = Variable(enumConstructorCall.getThisReceiver(), Common(enumEntry.correspondingClass ?: enumClass))
environment.mapOfEnums[enumEntry.symbol] = enumClassObject.state as Complex
val enumClassObject = Common(enumEntry.correspondingClass ?: enumClass)
environment.mapOfEnums[enumEntry.symbol] = enumClassObject
callStack.newSubFrame(enumEntry)
callStack.addInstruction(CustomInstruction(cleanEnumSuperCall))
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
// 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 }
KFunctionState(newInvoke, functionClass, environment, mutableListOf(dispatchReceiver))
.apply { this.funInterface = typeOperand }
KFunctionState(newInvoke, functionClass, environment, mutableMapOf(dispatchReceiver)).apply {
this.funInterface = typeOperand
}
}
}
callStack.pushState(newState)
@@ -532,7 +528,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
else -> arrayToList(result.value)
}
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)
@@ -545,12 +541,12 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val storageProperty = owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "storage" }
val primitiveArray = args.map {
when (it) {
is Proxy -> (it.state.fields.single().state as Primitive<*>).value // is unsigned number
else -> it // is primitive number
is Proxy -> (it.state.fields.values.single() as Primitive<*>).value // is unsigned number
else -> it // is primitive number
}
}
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)
}
@@ -604,8 +600,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val function = KFunctionState(
reference,
environment,
dispatchReceiver?.let { Variable(irFunction.getDispatchReceiver()!!, it) },
extensionReceiver?.let { Variable(irFunction.getExtensionReceiver()!!, it) }
dispatchReceiver?.let { irFunction.getDispatchReceiver()!! to it },
extensionReceiver?.let { irFunction.getExtensionReceiver()!! to it }
)
if (irFunction.isLocal) callStack.storeUpValues(function)
callStack.pushState(function)
@@ -619,7 +615,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
fun List<IrTypeParameter>.addToFields() {
(0 until propertyReference.typeArgumentsCount).forEach { index ->
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()
@@ -82,7 +82,7 @@ internal fun State.toIrExpression(expression: IrExpression): IrExpression {
is Complex -> {
val stateType = this.irClass.defaultType
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
}
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
import org.jetbrains.kotlin.utils.keysToMap
import java.lang.invoke.MethodType
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 {
val name = this.symbol.owner.parentClassOrNull?.fqName
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 typeFromMemory = (environment.callStack.getState(irFunction.symbol) as KTypeState).irType
val type = state?.let {
typeFromMemory.getTypeIfReified { typeSymbol -> (it.upValues.single { it.symbol == typeSymbol }.state as KTypeState).irType }
}
environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type ?: typeFromMemory))
val type = (environment.callStack.getState(irFunction.symbol) as KTypeState).irType
environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type))
}
}
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
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.State
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 (other == null) return false
val valueArguments = mutableListOf<Variable>()
val valueArguments = mutableListOf<State>()
val equalsFun = state.getEqualsFunction()
if (equalsFun.isFakeOverriddenFromAny() || equalsFun.wasAlreadyCalled()) return defaultEquals(other)
equalsFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) }
valueArguments.add(Variable(equalsFun.valueParameters.single().symbol, if (other is Proxy) other.state else other as State))
equalsFun.getDispatchReceiver()!!.let { valueArguments.add(state) }
valueArguments.add(if (other is Proxy) other.state else other as State)
return callInterceptor.interceptProxy(equalsFun, valueArguments) as Boolean
}
override fun hashCode(): Int {
val valueArguments = mutableListOf<Variable>()
val valueArguments = mutableListOf<State>()
val hashCodeFun = state.getHashCodeFunction()
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
}
override fun toString(): String {
val valueArguments = mutableListOf<Variable>()
val valueArguments = mutableListOf<State>()
val toStringFun = state.getToStringFunction()
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
}
@@ -81,10 +80,9 @@ internal class CommonProxy private constructor(override val state: Common, overr
else -> {
val irFunction = commonProxy.state.getIrFunction(method)
?: return@newProxyInstance commonProxy.fallbackIfMethodNotFound(method)
val valueArguments = mutableListOf<Variable>()
valueArguments += Variable(irFunction.getDispatchReceiver()!!, commonProxy.state)
val valueArguments = mutableListOf<State>(commonProxy.state)
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)
}
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrReturn
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
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.reflection.KFunctionState
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
@@ -52,12 +51,10 @@ internal class KFunctionProxy(
override fun call(vararg args: Any?): Any? {
// TODO check arity
var index = 0
val dispatchReceiver = state.irFunction.dispatchReceiverParameter
?.let { Variable(it.symbol, environment.convertToState(args[index++], it.type)) }
val extensionReceiver = state.irFunction.extensionReceiverParameter
?.let { Variable(it.symbol, environment.convertToState(args[index++], it.type)) }
val dispatchReceiver = state.irFunction.dispatchReceiverParameter?.let { environment.convertToState(args[index++], it.type) }
val extensionReceiver = state.irFunction.extensionReceiverParameter?.let { environment.convertToState(args[index++], it.type) }
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
return callInterceptor.interceptProxy(state.irFunction, valueArguments)
@@ -5,16 +5,16 @@
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.exceptions.verify
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.reflection.KPropertyState
import org.jetbrains.kotlin.ir.util.isObject
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(
state: KPropertyState, callInterceptor: CallInterceptor
@@ -32,11 +32,7 @@ internal open class KProperty0Proxy(
val value = receiver.getField(actualPropertySymbol)
return when {
// null value <=> property is extension or Primitive; receiver.isNull() <=> nullable extension
value == null || receiver.isNull() -> {
val receiverSymbol = getter.getReceiver()
val receiverVariable = receiverSymbol?.let { Variable(it, receiver) }
callInterceptor.interceptProxy(getter, listOfNotNull(receiverVariable))
}
value == null || receiver.isNull() -> callInterceptor.interceptProxy(getter, listOf(receiver))
else -> value
}
}
@@ -70,11 +66,8 @@ internal class KMutableProperty0Proxy(
val receiver = state.receiver!!
val newValue = environment.convertToState(args.single(), propertyType)
setter.getExtensionReceiver()
?.let {
val fieldSymbol = setter.valueParameters.single().symbol
callInterceptor.interceptProxy(setter, listOf(Variable(it, receiver), Variable(fieldSymbol, newValue)))
}
?: receiver.setField(Variable(state.property.symbol, newValue))
?.let { callInterceptor.interceptProxy(setter, listOf(receiver, newValue)) }
?: receiver.setField(state.property.symbol, newValue)
}
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.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.KTypeState
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
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(
state: KPropertyState, callInterceptor: CallInterceptor
@@ -32,7 +33,7 @@ internal open class KProperty1Proxy(
override fun call(vararg args: Any?): Any? {
checkArguments(1, args.size)
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))
}
@@ -60,9 +61,9 @@ internal class KMutableProperty1Proxy(
override fun call(vararg args: Any?) {
checkArguments(2, args.size)
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 value = Variable(valueParameter.symbol, environment.convertToState(args[1], valueParameter.getActualType()))
val value = environment.convertToState(args[1], valueParameter.getActualType())
callInterceptor.interceptProxy(setter, listOf(receiver, value))
}
@@ -6,9 +6,10 @@
package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
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 kotlin.reflect.*
import kotlin.reflect.KMutableProperty2
import kotlin.reflect.KParameter
import kotlin.reflect.KProperty2
internal open class KProperty2Proxy(
state: KPropertyState, callInterceptor: CallInterceptor
@@ -21,8 +22,8 @@ internal open class KProperty2Proxy(
checkArguments(2, args.size)
val dispatchParameter = getter.dispatchReceiverParameter!!
val extensionReceiverParameter = getter.extensionReceiverParameter!!
val dispatch = Variable(dispatchParameter.symbol, environment.convertToState(args[0], dispatchParameter.type))
val extension = Variable(extensionReceiverParameter.symbol, environment.convertToState(args[1], extensionReceiverParameter.type))
val dispatch = environment.convertToState(args[0], dispatchParameter.type)
val extension = environment.convertToState(args[1], extensionReceiverParameter.type)
return callInterceptor.interceptProxy(getter, listOf(dispatch, extension))
}
@@ -25,18 +25,15 @@ internal class CallStack {
internal val currentFrameOwner get() = currentFrame.currentSubFrameOwner
fun newFrame(frameOwner: IrElement, irFile: IrFile? = null) {
val newFrame = SubFrame(frameOwner)
frames.add(Frame(newFrame, irFile))
frames.add(Frame(frameOwner, irFile))
}
fun newFrame(frameOwner: IrFunction) {
val newFrame = SubFrame(frameOwner)
frames.add(Frame(newFrame, frameOwner.fileOrNull))
frames.add(Frame(frameOwner, frameOwner.fileOrNull))
}
fun newSubFrame(frameOwner: IrElement) {
val newFrame = SubFrame(frameOwner)
currentFrame.addSubFrame(newFrame)
currentFrame.addSubFrame(frameOwner)
}
fun dropFrame() {
@@ -174,8 +171,12 @@ internal class CallStack {
fun popState(): State = currentFrame.popState()
fun peekState(): State? = currentFrame.peekState()
fun addVariable(variable: Variable) {
currentFrame.addVariable(variable)
fun addVariable(symbol: IrSymbol, state: State?) {
currentFrame.addVariable(symbol, state)
}
private fun addVariable(symbol: IrSymbol, variable: Variable) {
currentFrame.addVariable(symbol, variable)
}
fun getState(symbol: IrSymbol): State = currentFrame.getState(symbol)
@@ -184,19 +185,15 @@ internal class CallStack {
fun storeUpValues(state: StateWithClosure) {
// TODO save only necessary declarations
currentFrame.getAll().reversed().forEach { variable ->
// 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
}
currentFrame.copyMemoryInto(state)
}
fun loadUpValues(state: StateWithClosure) {
state.upValues.forEach { addVariable(it) }
state.upValues.forEach { (symbol, variable) -> addVariable(symbol, variable) }
}
fun copyUpValuesFromPreviousFrame() {
frames[frames.size - 2].getAll().forEach { if (!containsVariable(it.symbol)) addVariable(it) }
frames[frames.size - 2].copyMemoryInto(currentFrame)
}
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.exceptions.InterpreterError
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.util.fqNameWhenAvailable
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
private val innerStack = mutableListOf(subFrame)
internal class Frame(subFrameOwner: IrElement, val irFile: IrFile? = null) {
private val innerStack = mutableListOf(SubFrame(subFrameOwner))
private var currentInstruction: Instruction? = null
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"
}
fun addSubFrame(frame: SubFrame) {
innerStack.add(frame)
fun addSubFrame(subFrameOwner: IrElement) {
innerStack.add(SubFrame(subFrameOwner))
}
fun removeSubFrame() {
@@ -59,8 +60,12 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
fun popState(): State = currentFrame.popState()
fun peekState(): State? = currentFrame.peekState()
fun addVariable(variable: Variable) {
currentFrame.addVariable(variable)
fun addVariable(symbol: IrSymbol, state: State?) {
currentFrame.addVariable(symbol, state)
}
fun addVariable(symbol: IrSymbol, variable: Variable) {
currentFrame.addVariable(symbol, variable)
}
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 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 {
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 dataStack = DataStack()
private val memory = mutableListOf<Variable>()
private val memory = mutableMapOf<IrSymbol, Variable>()
// Methods to work with instruction
fun isEmpty() = instructions.isEmpty()
@@ -122,18 +135,21 @@ internal class SubFrame(val owner: IrElement) {
fun peekState(): State? = dataStack.peek()
// Methods to work with memory
fun addVariable(variable: Variable) {
memory.add(0, variable)
fun addVariable(symbol: IrSymbol, variable: Variable) {
memory[symbol] = variable
}
private fun getVariable(symbol: IrSymbol): Variable? = memory.firstOrNull { it.symbol == symbol }
fun containsVariable(symbol: IrSymbol): Boolean = getVariable(symbol) != null
fun getState(symbol: IrSymbol): State? = getVariable(symbol)?.state
fun addVariable(symbol: IrSymbol, state: State?) {
memory[symbol] = Variable(state)
}
fun containsVariable(symbol: IrSymbol): Boolean = memory[symbol] != null
fun getState(symbol: IrSymbol): State? = memory[symbol]?.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 {
@@ -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.
*/
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.symbols.IrSymbol
// TODO maybe switch to typealias and use map instead of list
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)"
}
}
internal data class Variable(var 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.fqName
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.util.nameForIrSerialization
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.name.Name
internal class Common private constructor(override val irClass: IrClass, override val fields: MutableList<Variable>) : Complex, StateWithClosure {
override val upValues: MutableList<Variable> = mutableListOf()
internal class Common private constructor(
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 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
private fun getKotlinName(declaringClassName: String, methodName: String): String {
@@ -5,18 +5,21 @@
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.interpreter.fqName
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.util.overrides
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
internal interface Complex : State {
var superWrapperClass: Wrapper?
var outerClass: Variable?
var outerClass: Pair<IrSymbol, State>?
fun irClassFqName() = irClass.fqName
@@ -53,12 +56,12 @@ internal interface Complex : State {
return list
}
generateSequence(outerClass) { (it.state as? Complex)?.outerClass }
generateSequence(outerClass) { (it.second as? Complex)?.outerClass }
.toList()
.takeFromEndWhile { receiver == null || it.symbol != receiver } // only state's below receiver must be loaded on stack
.forEach { variable ->
callStack.addVariable(variable)
(variable.state as? StateWithClosure)?.let { callStack.loadUpValues(it) }
.takeFromEndWhile { receiver == null || it.first != receiver } // only state's below receiver must be loaded on stack
.forEach { (symbol, state) ->
callStack.addVariable(symbol, state)
(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.interpreter.getOriginalPropertyByName
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.isSubclassOf
import kotlin.math.min
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() {
override val upValues: MutableList<Variable> = mutableListOf()
override val upValues: MutableMap<IrSymbol, Variable> = mutableMapOf()
override var superWrapperClass: Wrapper? = null
override var outerClass: Variable? = null
override var outerClass: Pair<IrSymbol, State>? = null
override val message: String?
get() = getField(messageProperty.symbol)?.asStringOrNull()
@@ -32,11 +33,11 @@ internal class ExceptionState private constructor(
init {
if (!this::exceptionFqName.isInitialized) this.exceptionFqName = irClassFqName()
if (fields.none { it.symbol == messageProperty.symbol }) setMessage(null)
if (fields.none { it.symbol == causeProperty.symbol }) setCause(null)
if (!fields.containsKey(messageProperty.symbol)) setMessage(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(
exception: Throwable, irClass: IrClass, stackTrace: List<String>
@@ -58,8 +59,8 @@ internal class ExceptionState private constructor(
}
}
override fun setField(newVar: Variable) {
super.setField(newVar)
override fun setField(symbol: IrSymbol, state: State) {
super.setField(symbol, state)
recalculateCauseAndMessage()
}
@@ -78,11 +79,11 @@ internal class ExceptionState private constructor(
}
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?) {
setField(Variable(causeProperty.symbol, causeValue ?: Primitive.nullStateOfType(causeProperty.getter!!.returnType)))
setField(causeProperty.symbol, causeValue ?: Primitive.nullStateOfType(causeProperty.getter!!.returnType))
}
fun getFullDescription(): String {
@@ -99,15 +100,15 @@ internal class ExceptionState private constructor(
override fun toString(): String = message?.let { "$exceptionFqName: $it" } ?: exceptionFqName
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 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 {
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> {
@@ -9,14 +9,13 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
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.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.defaultType
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 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.isFunction
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.ReflectionState
import org.jetbrains.kotlin.ir.symbols.IrSymbol
@@ -22,18 +21,15 @@ import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.util.OperatorNameConventions
internal interface State {
val fields: MutableList<Variable>
val fields: MutableMap<IrSymbol, State>
val irClass: IrClass
fun getField(symbol: IrSymbol): State? {
return fields.firstOrNull { it.symbol == symbol }?.state
return fields[symbol]
}
fun setField(newVar: Variable) {
when (val oldState = fields.firstOrNull { it.symbol == newVar.symbol }) {
null -> fields.add(newVar) // newVar isn't present in value list
else -> fields[fields.indexOf(oldState)].state = newVar.state // newVar already present
}
fun setField(symbol: IrSymbol, state: State) {
fields[symbol] = state
}
fun getIrFunctionByIrCall(expression: IrCall): IrFunction?
@@ -103,9 +99,8 @@ internal fun State?.mustBeHandledAsReflection(call: IrCall): Boolean {
internal fun State.hasTheSameFieldsWith(other: State): Boolean {
if (this.fields.size != other.fields.size) return false
for (i in 0 until this.fields.size) {
val firstState = this.fields[i].state
val secondState = other.fields[i].state
// TODO prove that this will always work or find better solution
this.fields.values.zip(other.fields.values).forEach { (firstState, secondState) ->
when {
firstState is Primitive<*> && secondState is Primitive<*> -> if (firstState.value != secondState.value) return false
else -> if (firstState !== secondState) return false
@@ -6,7 +6,8 @@
package org.jetbrains.kotlin.ir.interpreter.state
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.symbols.IrSymbol
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.expressions.IrCall
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.IrSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
@@ -23,10 +23,10 @@ import kotlin.collections.HashMap
import kotlin.collections.LinkedHashMap
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 outerClass: Variable? = null
override var outerClass: Pair<IrSymbol, State>? = null
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.KTypeProxy
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.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.util.OperatorNameConventions
import kotlin.reflect.KParameter
import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter
@@ -33,9 +35,9 @@ internal class KFunctionState(
val irFunction: IrFunction,
override val irClass: IrClass,
environment: IrInterpreterEnvironment,
override val fields: MutableList<Variable> = mutableListOf()
override val fields: MutableMap<IrSymbol, State> = mutableMapOf()
) : ReflectionState(), StateWithClosure {
override val upValues: MutableList<Variable> = mutableListOf()
override val upValues: MutableMap<IrSymbol, Variable> = mutableMapOf()
var funInterface: IrType? = null
set(value) {
@@ -123,16 +125,18 @@ internal class KFunctionState(
constructor(
functionReference: IrFunctionReference,
environment: IrInterpreterEnvironment,
dispatchReceiver: Variable?,
extensionReceiver: Variable?
dispatchReceiver: Pair<IrSymbol, State>?,
extensionReceiver: Pair<IrSymbol, State>?
) : this(
functionReference.symbol.owner,
functionReference.type.classOrNull!!.owner,
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
upValues += fields
upValues += fields.map { it.key to Variable(it.value) }
}
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
@@ -5,25 +5,20 @@
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.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
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.types.IrSimpleType
import org.jetbrains.kotlin.ir.symbols.IrSymbol
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.nameForIrSerialization
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.ir.util.render
import kotlin.math.min
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