Place variables in interpreter's memory at the beginning
In case than in single SubFrame can appear several variables with the same symbol, it is important to get the latest one. It is relevant for local functions.
This commit is contained in:
committed by
TeamCityServer
parent
e5ca646de4
commit
d41c6e900a
+14
-12
@@ -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))
|
||||
|
||||
+5
-1
@@ -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) {
|
||||
|
||||
@@ -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 }
|
||||
|
||||
+15
-5
@@ -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 <T> List<T>.takeFromEndWhile(predicate: (T) -> Boolean): List<T> {
|
||||
val list = mutableListOf<T>()
|
||||
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) }
|
||||
|
||||
Reference in New Issue
Block a user