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 5df049130d7..46c183aeef1 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 @@ -187,27 +187,28 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal callStack.dropSubFrame() // drop intermediate frame that contains variables for default arg evaluation callStack.newFrame(irFunction) callStack.addInstruction(SimpleInstruction(irFunction)) + + // 3. load up values onto stack; do it at first to set low priority of these variables + if (dispatchReceiver is StateWithClosure) callStack.loadUpValues(dispatchReceiver) + if (extensionReceiver is StateWithClosure) callStack.loadUpValues(extensionReceiver) + if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame() + // TODO: if using KTypeState then it's class must be corresponding // `call.type` is used in check cast and emptyArray callStack.addVariable(Variable(irFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner))) - // 3. store arguments in memory (remap args on actual names) + // 4. store arguments in memory (remap args on actual names) irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> callStack.addVariable(Variable(it, receiver)) } } irFunction.getExtensionReceiver()?.let { callStack.addVariable(Variable(it, extensionReceiver ?: valueArguments.removeFirst())) } irFunction.valueParameters.forEach { callStack.addVariable(Variable(it.symbol, valueArguments.removeFirst())) } - // 4. store reified type parameters + // 5. store reified type parameters irFunction.typeParameters.filter { it.isReified } .forEach { callStack.addVariable(Variable(it.symbol, KTypeState(call.getTypeArgument(it.index)!!, irBuiltIns.anyClass.owner))) } - // 5. load outer class object + // 6. load outer class object if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) dispatchReceiver.loadOuterClassesInto(callStack) - // 6. load up values onto stack - if (dispatchReceiver is StateWithClosure) callStack.loadUpValues(dispatchReceiver) - if (extensionReceiver is StateWithClosure) callStack.loadUpValues(extensionReceiver) - if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame() - callInterceptor.interceptCall(call, irFunction, args) { callStack.addInstruction(CompoundInstruction(irFunction)) } @@ -259,6 +260,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal callStack.dropSubFrame() 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])) } @@ -274,16 +277,15 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal if (outerClass != null) { val outerClassVar = Variable(irClass.parentAsClass.thisReceiver!!.symbol, outerClass) (objectState as Complex).outerClass = outerClassVar - if (superReceiver != receiverSymbol) { + 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)) + // used to get information from outer class + objectState.loadOuterClassesInto(callStack, constructorCall.getThisReceiver()) } - // used to get information from outer class - objectState.loadOuterClassesInto(callStack) } - if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure) callInterceptor.interceptConstructor(constructorCall, valueArguments) { callStack.addInstruction(CompoundInstruction(constructor)) 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 d0f03115039..d9cc2bad7a2 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 @@ -183,7 +183,11 @@ internal class CallStack { fun storeUpValues(state: StateWithClosure) { // TODO save only necessary declarations - state.upValues.addAll(currentFrame.getAll().toMutableList()) + 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 + } } fun loadUpValues(state: StateWithClosure) { 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 11d9481f79b..a0da26b4ae2 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 @@ -123,7 +123,7 @@ internal class SubFrame(val owner: IrElement) { // Methods to work with memory fun addVariable(variable: Variable) { - memory += variable + memory.add(0, variable) } private fun getVariable(symbol: IrSymbol): Variable? = memory.firstOrNull { it.symbol == symbol } 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 7225e100960..9d8875a8be3 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,14 +5,12 @@ package org.jetbrains.kotlin.ir.interpreter.state -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.declarations.* import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.interpreter.stack.CallStack import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.overrides import org.jetbrains.kotlin.ir.util.resolveFakeOverride @@ -48,8 +46,20 @@ internal interface Complex : State { return (irFunction as IrSimpleFunction).resolveFakeOverride() } - fun loadOuterClassesInto(callStack: CallStack) { + fun loadOuterClassesInto(callStack: CallStack, receiver: IrValueSymbol? = null) { + fun List.takeFromEndWhile(predicate: (T) -> Boolean): List { + val list = mutableListOf() + for (i in this.lastIndex downTo 0) { + if (!predicate(this[i])) + break + list.add(this[i]) + } + return list + } + generateSequence(outerClass) { (it.state 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) }