diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt index ae4f14f30a9..0cc17b9fe02 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt @@ -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, expectedResultClass: Class<*> = Any::class.java): Any? + fun interceptProxy(irFunction: IrFunction, valueArguments: List, expectedResultClass: Class<*> = Any::class.java): Any? fun interceptCall(call: IrCall, irFunction: IrFunction, args: List, defaultAction: () -> Unit) fun interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List, 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 = interpreter.bodyMap - override fun interceptProxy(irFunction: IrFunction, valueArguments: List, expectedResultClass: Class<*>): Any? { + override fun interceptProxy(irFunction: IrFunction, valueArguments: List, 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() } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt index 86df2dc9113..ca808758894 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt @@ -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().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() diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 06ed76ad4ce..8798659a45c 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -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().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.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() diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt index e1c20d58e02..aa9bbcd5471 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt @@ -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 } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index 0287f9931e5..2ac39d39e20 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -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 { + 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 diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt index 8b5ae74b64f..3d78276872f 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt @@ -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)) } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt index bdd94d15749..afa66036b9c 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt @@ -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() + val valueArguments = mutableListOf() 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() + val valueArguments = mutableListOf() 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() + val valueArguments = mutableListOf() 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() - valueArguments += Variable(irFunction.getDispatchReceiver()!!, commonProxy.state) + val valueArguments = mutableListOf(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) } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt index 2fb753510b3..4954799b46a 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KFunctionProxy.kt @@ -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) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt index 28997e8fbcf..75c257b72b2 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt @@ -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) { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt index e833b4b9707..a5b5efdbb3b 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty1Proxy.kt @@ -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)) } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty2Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty2Proxy.kt index 3e7a78c0a10..0cee496d461 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty2Proxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty2Proxy.kt @@ -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)) } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/CallStack.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/CallStack.kt index f63a575220d..7bec64dff7e 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/CallStack.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/CallStack.kt @@ -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 { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Frame.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Frame.kt index a0da26b4ae2..5b2154c9101 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Frame.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Frame.kt @@ -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 = 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> = 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() private val dataStack = DataStack() - private val memory = mutableListOf() + private val memory = mutableMapOf() // 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 = memory + fun getAll(): List> = memory.toList() } private class DataStack { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Variable.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Variable.kt index 6780cd20060..e0cb2774d4c 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Variable.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Variable.kt @@ -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)" - } -} \ No newline at end of file +internal data class Variable(var state: State?) \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt index 076bf3cfed3..62f491c562d 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt @@ -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) : Complex, StateWithClosure { - override val upValues: MutableList = mutableListOf() +internal class Common private constructor( + override val irClass: IrClass, override val fields: MutableMap +) : Complex, StateWithClosure { + override val upValues: MutableMap = mutableMapOf() override var superWrapperClass: Wrapper? = null - override var outerClass: Variable? = null + override var outerClass: Pair? = 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 { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt index 6c46e0372e7..f66061a3cd9 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt @@ -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? 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) } } } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt index ebd22cdc877..a105bfd6d66 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt @@ -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, stackTrace: List + override val irClass: IrClass, override val fields: MutableMap, stackTrace: List ) : Complex, StateWithClosure, Throwable() { - override val upValues: MutableList = mutableListOf() + override val upValues: MutableMap = mutableMapOf() override var superWrapperClass: Wrapper? = null - override var outerClass: Variable? = null + override var outerClass: Pair? = 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) : this(irClass, mutableListOf(), stackTrace) + constructor(irClass: IrClass, stackTrace: List) : this(irClass, mutableMapOf(), stackTrace) constructor( exception: Throwable, irClass: IrClass, stackTrace: List @@ -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): MutableList { + private fun evaluateFields(exception: Throwable, irClass: IrClass, stackTrace: List): MutableMap { 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 { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Primitive.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Primitive.kt index 2f55328a2a6..7265ae406b9 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Primitive.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Primitive.kt @@ -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(val value: T, val type: IrType) : State { - override val fields: MutableList = mutableListOf() + override val fields: MutableMap = mutableMapOf() override val irClass: IrClass = type.classOrNull!!.owner override fun getField(symbol: IrSymbol): State? = null diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt index 5f832fb8285..87a9d59c6d6 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt @@ -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 + val fields: MutableMap 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 diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/StateWithClosure.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/StateWithClosure.kt index 3f7e012b40f..0bd8e06eb04 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/StateWithClosure.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/StateWithClosure.kt @@ -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 + val upValues: MutableMap } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Wrapper.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Wrapper.kt index 6c952d83041..1bfe1629007 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Wrapper.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Wrapper.kt @@ -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 = mutableListOf() + override val fields: MutableMap = mutableMapOf() override var superWrapperClass: Wrapper? = null - override var outerClass: Variable? = null + override var outerClass: Pair? = null private val receiverClass = irClass.defaultType.getClass(true) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt index 8944dc78bfe..7c21460cdab 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/KFunctionState.kt @@ -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 = mutableListOf() + override val fields: MutableMap = mutableMapOf() ) : ReflectionState(), StateWithClosure { - override val upValues: MutableList = mutableListOf() + override val upValues: MutableMap = 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?, + extensionReceiver: Pair? ) : 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? { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/ReflectionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/ReflectionState.kt index e61e298fa5f..79efd5703a4 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/ReflectionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/reflection/ReflectionState.kt @@ -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 = mutableListOf() + override val fields: MutableMap = mutableMapOf() override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null