Make state property mutable in Variable class
This change allow to remove copy method from State interface
This commit is contained in:
+11
-12
@@ -59,7 +59,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
||||
is Double -> irBuiltIns.doubleType
|
||||
null -> irBuiltIns.nothingType
|
||||
else -> when (defaultType.classifierOrNull?.owner) {
|
||||
is IrTypeParameter -> stack.getVariableState(defaultType.classifierOrFail.descriptor).irClass.defaultType
|
||||
is IrTypeParameter -> stack.getVariable(defaultType.classifierOrFail.descriptor).state.irClass.defaultType
|
||||
else -> defaultType
|
||||
}
|
||||
}
|
||||
@@ -284,7 +284,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
||||
|
||||
interpretValueParameters(expression, irFunction, valueArguments).check { return it }
|
||||
|
||||
valueArguments.addAll(getTypeArguments(irFunction, expression) { stack.getVariableState(it) })
|
||||
valueArguments.addAll(getTypeArguments(irFunction, expression) { stack.getVariable(it).state })
|
||||
if (dispatchReceiver is Complex) valueArguments.addAll(dispatchReceiver.typeArguments)
|
||||
if (extensionReceiver is Complex) valueArguments.addAll(extensionReceiver.typeArguments)
|
||||
|
||||
@@ -331,9 +331,9 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
||||
property.backingField?.initializer?.expression?.interpret()?.check { return it }
|
||||
val receiver = irClass.descriptor.thisAsReceiverParameter
|
||||
if (property.backingField?.initializer != null) {
|
||||
val receiverState = stack.getVariableState(receiver)
|
||||
val propertyState = Variable(property.backingField!!.descriptor, stack.popReturnValue())
|
||||
receiverState.setState(propertyState)
|
||||
val receiverState = stack.getVariable(receiver).state
|
||||
val property = Variable(property.backingField!!.descriptor, stack.popReturnValue())
|
||||
receiverState.setField(property)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
||||
interpretValueParameters(constructorCall, owner, valueArguments).check { return it }
|
||||
|
||||
val irClass = owner.parent as IrClass
|
||||
val typeArguments = getTypeArguments(irClass, constructorCall) { stack.getVariableState(it) }
|
||||
val typeArguments = getTypeArguments(irClass, constructorCall) { stack.getVariable(it).state }
|
||||
if (irClass.hasAnnotation(evaluateIntrinsicAnnotation) || irClass.fqNameWhenAvailable!!.startsWith(Name.identifier("java"))) {
|
||||
return stack.newFrame(initPool = valueArguments) { Wrapper.getConstructorMethod(owner).invokeMethod(owner) }
|
||||
.apply { (stack.peekReturnValue() as? Wrapper)?.typeArguments?.addAll(typeArguments) } // 'as?' because can be exception
|
||||
@@ -502,14 +502,14 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
||||
|
||||
// receiver is null only for top level var, but it cannot be used in constexpr; corresponding check is on frontend
|
||||
val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor
|
||||
stack.getVariableState(receiver).setState(Variable(expression.symbol.owner.descriptor, stack.popReturnValue()))
|
||||
stack.getVariable(receiver).apply { this.state.setField(Variable(expression.symbol.owner.descriptor, stack.popReturnValue())) }
|
||||
return Next
|
||||
}
|
||||
|
||||
private suspend fun interpretGetField(expression: IrGetField): ExecutionResult {
|
||||
val receiver = (expression.receiver as? IrDeclarationReference)?.symbol?.descriptor
|
||||
// receiver is null, for example, for top level fields
|
||||
val result = receiver?.let { stack.getVariableState(receiver).getState(expression.symbol.descriptor)?.copy() }
|
||||
val result = receiver?.let { stack.getVariable(receiver).state.getState(expression.symbol.descriptor) }
|
||||
?: return (expression.symbol.owner.initializer?.expression?.interpret() ?: Next)
|
||||
stack.pushReturnValue(result)
|
||||
return Next
|
||||
@@ -519,7 +519,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
||||
val owner = expression.type.classOrNull?.owner
|
||||
// used to evaluate constants inside object
|
||||
if (owner != null && owner.isObject) return getOrCreateObjectValue(owner) // TODO is this correct behaviour?
|
||||
stack.pushReturnValue(stack.getVariableState(expression.symbol.descriptor).copy())
|
||||
stack.pushReturnValue(stack.getVariable(expression.symbol.descriptor).state)
|
||||
return Next
|
||||
}
|
||||
|
||||
@@ -533,8 +533,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
||||
expression.value.interpret().check { return it }
|
||||
|
||||
if (stack.contains(expression.symbol.descriptor)) {
|
||||
val variable = stack.getVariableState(expression.symbol.descriptor)
|
||||
variable.setState(Variable(expression.symbol.descriptor, stack.popReturnValue()))
|
||||
stack.getVariable(expression.symbol.descriptor).apply { this.state = stack.popReturnValue() }
|
||||
} else {
|
||||
stack.addVar(Variable(expression.symbol.descriptor, stack.popReturnValue()))
|
||||
}
|
||||
@@ -600,7 +599,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
|
||||
private suspend fun interpretTypeOperatorCall(expression: IrTypeOperatorCall): ExecutionResult {
|
||||
val executionResult = expression.argument.interpret().check { return it }
|
||||
val typeOperandDescriptor = expression.typeOperand.classifierOrFail.descriptor
|
||||
val typeOperandClass = expression.typeOperand.classOrNull?.owner ?: stack.getVariableState(typeOperandDescriptor).irClass
|
||||
val typeOperandClass = expression.typeOperand.classOrNull?.owner ?: stack.getVariable(typeOperandDescriptor).state.irClass
|
||||
|
||||
when (expression.operator) {
|
||||
// coercion to unit means that return value isn't used
|
||||
|
||||
+9
-9
@@ -60,7 +60,7 @@ object ArrayOfNulls : IntrinsicBase() {
|
||||
override suspend fun evaluate(
|
||||
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||
): ExecutionResult {
|
||||
val size = stack.getVariableState(irFunction.valueParameters.first().descriptor).asInt()
|
||||
val size = stack.getVariable(irFunction.valueParameters.first().descriptor).state.asInt()
|
||||
val array = arrayOfNulls<Any?>(size)
|
||||
stack.pushReturnValue(array.toState(irFunction.returnType))
|
||||
return Next
|
||||
@@ -77,7 +77,7 @@ object EnumValues : IntrinsicBase() {
|
||||
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||
): ExecutionResult {
|
||||
val enumClass = when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.enumValues" -> stack.getVariableState(irFunction.typeParameters.first().descriptor).irClass
|
||||
"kotlin.enumValues" -> stack.getVariable(irFunction.typeParameters.first().descriptor).state.irClass
|
||||
else -> irFunction.parent as IrClass
|
||||
}
|
||||
|
||||
@@ -98,10 +98,10 @@ object EnumValueOf : IntrinsicBase() {
|
||||
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||
): ExecutionResult {
|
||||
val enumClass = when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.enumValueOf" -> stack.getVariableState(irFunction.typeParameters.first().descriptor).irClass
|
||||
"kotlin.enumValueOf" -> stack.getVariable(irFunction.typeParameters.first().descriptor).state.irClass
|
||||
else -> irFunction.parent as IrClass
|
||||
}
|
||||
val enumEntryName = stack.getVariableState(irFunction.valueParameters.first().descriptor).asString()
|
||||
val enumEntryName = stack.getVariable(irFunction.valueParameters.first().descriptor).state.asString()
|
||||
val enumEntry = enumClass.declarations.filterIsInstance<IrEnumEntry>().singleOrNull { it.name.asString() == enumEntryName }
|
||||
enumEntry?.interpret()?.check { return it }
|
||||
?: throw IllegalArgumentException("No enum constant ${enumClass.fqNameWhenAvailable}.$enumEntryName")
|
||||
@@ -160,12 +160,12 @@ object JsPrimitives : IntrinsicBase() {
|
||||
): ExecutionResult {
|
||||
when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.Long.<init>" -> {
|
||||
val low = stack.getVariableState(irFunction.valueParameters[0].descriptor).asInt()
|
||||
val high = stack.getVariableState(irFunction.valueParameters[1].descriptor).asInt()
|
||||
val low = stack.getVariable(irFunction.valueParameters[0].descriptor).state.asInt()
|
||||
val high = stack.getVariable(irFunction.valueParameters[1].descriptor).state.asInt()
|
||||
stack.pushReturnValue((high.toLong().shl(32) + low).toState(irFunction.returnType))
|
||||
}
|
||||
"kotlin.Char.<init>" -> {
|
||||
val value = stack.getVariableState(irFunction.valueParameters[0].descriptor).asInt()
|
||||
val value = stack.getVariable(irFunction.valueParameters[0].descriptor).state.asInt()
|
||||
stack.pushReturnValue(value.toChar().toState(irFunction.returnType))
|
||||
}
|
||||
}
|
||||
@@ -183,12 +183,12 @@ object ArrayConstructor : IntrinsicBase() {
|
||||
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||
): ExecutionResult {
|
||||
val sizeDescriptor = irFunction.valueParameters[0].descriptor
|
||||
val size = stack.getVariableState(sizeDescriptor).asInt()
|
||||
val size = stack.getVariable(sizeDescriptor).state.asInt()
|
||||
val arrayValue = MutableList<Any>(size) { 0 }
|
||||
|
||||
if (irFunction.valueParameters.size == 2) {
|
||||
val initDescriptor = irFunction.valueParameters[1].descriptor
|
||||
val initLambda = stack.getVariableState(initDescriptor) as Lambda
|
||||
val initLambda = stack.getVariable(initDescriptor).state as Lambda
|
||||
val index = initLambda.irFunction.valueParameters.single()
|
||||
for (i in 0 until size) {
|
||||
val indexVar = listOf(Variable(index.descriptor, i.toState(index.type)))
|
||||
|
||||
+3
-9
@@ -14,8 +14,7 @@ import kotlin.NoSuchElementException
|
||||
interface Frame {
|
||||
fun addVar(variable: Variable)
|
||||
fun addAll(variables: List<Variable>)
|
||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
||||
fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State?
|
||||
fun getVariable(variableDescriptor: DeclarationDescriptor): Variable?
|
||||
fun getAll(): List<Variable>
|
||||
fun contains(descriptor: DeclarationDescriptor): Boolean
|
||||
fun pushReturnValue(state: State)
|
||||
@@ -40,14 +39,9 @@ class InterpreterFrame(
|
||||
pool.addAll(variables)
|
||||
}
|
||||
|
||||
override fun tryGetVariableState(variableDescriptor: DeclarationDescriptor): State? {
|
||||
override fun getVariable(variableDescriptor: DeclarationDescriptor): Variable? {
|
||||
return (if (variableDescriptor is TypeParameterDescriptor) typeArguments else pool)
|
||||
.firstOrNull { it.descriptor.equalTo(variableDescriptor) }?.state
|
||||
}
|
||||
|
||||
override fun getVariableState(variableDescriptor: DeclarationDescriptor): State {
|
||||
return tryGetVariableState(variableDescriptor)
|
||||
?: throw NoSuchElementException("Frame pool doesn't contains variable with descriptor $variableDescriptor")
|
||||
.firstOrNull { it.descriptor.equalTo(variableDescriptor) }
|
||||
}
|
||||
|
||||
override fun getAll(): List<Variable> {
|
||||
|
||||
+5
-5
@@ -28,7 +28,7 @@ interface Stack {
|
||||
fun clean()
|
||||
fun addVar(variable: Variable)
|
||||
fun addAll(variables: List<Variable>)
|
||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State
|
||||
fun getVariable(variableDescriptor: DeclarationDescriptor): Variable
|
||||
fun getAll(): List<Variable>
|
||||
|
||||
fun contains(descriptor: DeclarationDescriptor): Boolean
|
||||
@@ -86,8 +86,8 @@ class StackImpl : Stack {
|
||||
getCurrentFrame().addAll(variables)
|
||||
}
|
||||
|
||||
override fun getVariableState(variableDescriptor: DeclarationDescriptor): State {
|
||||
return getCurrentFrame().getVariableState(variableDescriptor)
|
||||
override fun getVariable(variableDescriptor: DeclarationDescriptor): Variable {
|
||||
return getCurrentFrame().getVariable(variableDescriptor)
|
||||
}
|
||||
|
||||
override fun getAll(): List<Variable> {
|
||||
@@ -132,8 +132,8 @@ private class FrameContainer(current: Frame = InterpreterFrame()) {
|
||||
fun addVar(variable: Variable) = getTopFrame().addVar(variable)
|
||||
fun addAll(variables: List<Variable>) = getTopFrame().addAll(variables)
|
||||
fun getAll() = innerStack.flatMap { it.getAll() }
|
||||
fun getVariableState(variableDescriptor: DeclarationDescriptor): State {
|
||||
return innerStack.firstNotNullResult { it.tryGetVariableState(variableDescriptor) }
|
||||
fun getVariable(variableDescriptor: DeclarationDescriptor): Variable {
|
||||
return innerStack.firstNotNullResult { it.getVariable(variableDescriptor) }
|
||||
?: throw InterpreterException("$variableDescriptor not found") // TODO better message
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.backend.common.interpreter.state.State
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
|
||||
data class Variable(val descriptor: DeclarationDescriptor, val state: State) {
|
||||
data class Variable(val descriptor: DeclarationDescriptor, var state: State) {
|
||||
override fun toString(): String {
|
||||
val descriptorName = when (descriptor) {
|
||||
is ReceiverParameterDescriptor -> descriptor.containingDeclaration.name.toString() + "::this"
|
||||
|
||||
-2
@@ -48,8 +48,6 @@ class Common private constructor(
|
||||
.let { getOverridden(it as IrSimpleFunction, this) }
|
||||
}
|
||||
|
||||
override fun copy() = Common(irClass, fields).copyFrom(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return "Common(obj='${irClass.fqNameForIrSerialization}', super=$superClass, values=$fields)"
|
||||
}
|
||||
|
||||
+4
-19
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.util.isInterface
|
||||
abstract class Complex(override val irClass: IrClass, override val fields: MutableList<Variable>) : State {
|
||||
var superClass: Complex? = null
|
||||
var subClass: Complex? = null
|
||||
val interfaces: MutableList<Complex> = mutableListOf() // filled lazily, as needed
|
||||
val typeArguments: MutableList<Variable> = mutableListOf()
|
||||
var outerClass: Variable? = null
|
||||
|
||||
@@ -46,21 +47,6 @@ abstract class Complex(override val irClass: IrClass, override val fields: Mutab
|
||||
|
||||
private fun contains(variable: Variable) = fields.any { it.descriptor == variable.descriptor }
|
||||
|
||||
override fun setState(newVar: Variable) {
|
||||
when (val oldState = fields.firstOrNull { it.descriptor == newVar.descriptor }) {
|
||||
null -> fields.add(newVar) // newVar isn't present in value list
|
||||
else -> fields[fields.indexOf(oldState)] = newVar // newVar already present
|
||||
}
|
||||
}
|
||||
|
||||
protected fun copyFrom(other: Complex): State {
|
||||
this.superClass = other.superClass
|
||||
this.subClass = other.subClass ?: other
|
||||
this.typeArguments.addAll(other.typeArguments)
|
||||
this.outerClass = other.outerClass
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? {
|
||||
val propertyGetters = irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter }
|
||||
val functions = irClass.declarations.filterIsInstance<IrFunction>()
|
||||
@@ -70,10 +56,9 @@ abstract class Complex(override val irClass: IrClass, override val fields: Mutab
|
||||
private fun getThisOrSuperReceiver(superIrClass: IrClass?): Complex? {
|
||||
return when {
|
||||
superIrClass == null -> this.getOriginal()
|
||||
superIrClass.isInterface -> {
|
||||
val interfaceState = Common(superIrClass)
|
||||
(this.copy() as Complex).setSuperClassInstance(interfaceState)
|
||||
interfaceState
|
||||
superIrClass.isInterface -> Common(superIrClass).apply {
|
||||
interfaces.add(this)
|
||||
this.subClass = this@Complex
|
||||
}
|
||||
else -> this.superClass
|
||||
}
|
||||
|
||||
+2
-4
@@ -80,11 +80,11 @@ class ExceptionState private constructor(
|
||||
}
|
||||
|
||||
private fun setMessage(messageValue: String? = null) {
|
||||
setState(Variable(messageProperty.descriptor, Primitive(messageValue, messageProperty.getter!!.returnType)))
|
||||
setField(Variable(messageProperty.descriptor, Primitive(messageValue, messageProperty.getter!!.returnType)))
|
||||
}
|
||||
|
||||
private fun setCause(causeValue: State?) {
|
||||
setState(Variable(causeProperty.descriptor, causeValue ?: Primitive<Throwable?>(null, causeProperty.getter!!.returnType)))
|
||||
setField(Variable(causeProperty.descriptor, causeValue ?: Primitive<Throwable?>(null, causeProperty.getter!!.returnType)))
|
||||
}
|
||||
|
||||
fun getMessage(): Primitive<String?> = getState(messageProperty.descriptor) as Primitive<String?>
|
||||
@@ -105,8 +105,6 @@ class ExceptionState private constructor(
|
||||
|
||||
fun getThisAsCauseForException() = ExceptionData(this)
|
||||
|
||||
override fun copy() = ExceptionState(irClass, fields, stackTrace).copyFrom(this)
|
||||
|
||||
companion object {
|
||||
private fun IrClass.getPropertyByName(name: String): IrProperty {
|
||||
val getPropertyFun = this.declarations.firstOrNull { it.nameForIrSerialization.asString().contains("get-$name") }
|
||||
|
||||
-8
@@ -19,18 +19,10 @@ class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State
|
||||
// irFunction is anonymous declaration, but irCall will contain descriptor of invoke method from Function interface
|
||||
private val invokeDescriptor = irClass.declarations.single { it.nameForIrSerialization.asString() == "invoke" }.descriptor
|
||||
|
||||
override fun setState(newVar: Variable) {
|
||||
throw UnsupportedOperationException("Method setState is not supported in Lambda class")
|
||||
}
|
||||
|
||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
|
||||
return if (invokeDescriptor.equalTo(expression.symbol.descriptor)) irFunction else null
|
||||
}
|
||||
|
||||
override fun copy(): State {
|
||||
return Lambda(irFunction, irClass).apply { this.fields.addAll(this@Lambda.fields) }
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.getFqName(true)
|
||||
val arguments = irFunction.valueParameters.map { it.type.getFqName(true) }.joinToString(prefix = "(", postfix = ")")
|
||||
|
||||
-9
@@ -24,15 +24,6 @@ class Primitive<T>(var value: T, val type: IrType) : State {
|
||||
return super.getState(descriptor) ?: this
|
||||
}
|
||||
|
||||
override fun setState(newVar: Variable) {
|
||||
newVar.state as? Primitive<T> ?: throw IllegalArgumentException("Cannot set $newVar in current $this")
|
||||
value = newVar.state.value
|
||||
}
|
||||
|
||||
override fun copy(): State {
|
||||
return Primitive(value, type)
|
||||
}
|
||||
|
||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
|
||||
val descriptor = expression.symbol.descriptor
|
||||
// must add property's getter to declaration's list because they are not present in ir class for primitives
|
||||
|
||||
+6
-10
@@ -20,16 +20,12 @@ interface State {
|
||||
return fields.firstOrNull { it.descriptor.equalTo(descriptor) }?.state
|
||||
}
|
||||
|
||||
fun setState(newVar: Variable)
|
||||
|
||||
/**
|
||||
* This method is used for passing a copy of a state.
|
||||
* It is necessary then copy change its state's value, but the original one must remain the same.
|
||||
*
|
||||
* @see copyReceivedValue.kt
|
||||
* @see tryFinally.kt
|
||||
*/
|
||||
fun copy(): State
|
||||
fun setField(newVar: Variable) {
|
||||
when (val oldState = fields.firstOrNull { it.descriptor == newVar.descriptor }) {
|
||||
null -> fields.add(newVar) // newVar isn't present in value list
|
||||
else -> fields[fields.indexOf(oldState)].state = newVar.state // newVar already present
|
||||
}
|
||||
}
|
||||
|
||||
fun getIrFunctionByIrCall(expression: IrCall): IrFunction?
|
||||
}
|
||||
|
||||
-6
@@ -52,10 +52,6 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass,
|
||||
return MethodHandles.lookup().findVirtual(receiverClass, methodName, methodType)
|
||||
}
|
||||
|
||||
override fun setState(newVar: Variable) {
|
||||
throw UnsupportedOperationException("Method setState is not supported in Wrapper class")
|
||||
}
|
||||
|
||||
// this method is used to get correct java method name
|
||||
// for example: - method 'get' in kotlin StringBuilder is actually 'charAt' in java StringBuilder
|
||||
// - method 'keys' in kotlin Map is actually 'keySet' in java
|
||||
@@ -194,8 +190,6 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass,
|
||||
}
|
||||
}
|
||||
|
||||
override fun copy() = Wrapper(value, irClass).copyFrom(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return "Wrapper(obj='$typeFqName', value=$value)"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user