Support interpretation for inner class

This commit is contained in:
Ivan Kylchik
2020-06-10 23:01:02 +03:00
parent 0c1f2edbf2
commit 94e36411fa
5 changed files with 37 additions and 34 deletions
@@ -281,6 +281,10 @@ class IrInterpreter(irModule: IrModuleFragment) {
val isLocal = (dispatchReceiver as? Complex)?.getOriginal()?.irClass?.isLocal ?: irFunction.isLocal val isLocal = (dispatchReceiver as? Complex)?.getOriginal()?.irClass?.isLocal ?: irFunction.isLocal
if (isLocal) valueArguments.addAll(dispatchReceiver.extractNonLocalDeclarations()) if (isLocal) valueArguments.addAll(dispatchReceiver.extractNonLocalDeclarations())
if (functionReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) {
generateSequence(functionReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { valueArguments.add(it) }
}
return stack.newFrame(asSubFrame = irFunction.isInline || irFunction.isLocal, initPool = valueArguments) { return stack.newFrame(asSubFrame = irFunction.isInline || irFunction.isLocal, initPool = valueArguments) {
// inline only methods are not presented in lookup table, so must be interpreted instead of execution // inline only methods are not presented in lookup table, so must be interpreted instead of execution
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly")) val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
@@ -321,20 +325,24 @@ class IrInterpreter(irModule: IrModuleFragment) {
interpretValueParameters(constructorCall, owner, valueArguments).check { return it } interpretValueParameters(constructorCall, owner, valueArguments).check { return it }
val parent = owner.parent as IrClass val irClass = owner.parent as IrClass
val typeArguments = getTypeArguments(parent, constructorCall) { stack.getVariableState(it) } + stack.getAllTypeArguments() val typeArguments = getTypeArguments(irClass, constructorCall) { stack.getVariableState(it) } + stack.getAllTypeArguments()
if (parent.hasAnnotation(evaluateIntrinsicAnnotation)) { if (irClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
return stack.newFrame(initPool = valueArguments) { Wrapper.getConstructorMethod(owner).invokeMethod(owner) } return stack.newFrame(initPool = valueArguments) { Wrapper.getConstructorMethod(owner).invokeMethod(owner) }
.apply { (stack.peekReturnValue() as? Wrapper)?.typeArguments?.addAll(typeArguments) } // can be exception .apply { (stack.peekReturnValue() as? Wrapper)?.typeArguments?.addAll(typeArguments) } // 'as?' because can be exception
} }
if (parent.defaultType.isArray() || parent.defaultType.isPrimitiveArray()) { if (irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray()) {
// array constructor doesn't have body so must be treated separately // array constructor doesn't have body so must be treated separately
return stack.newFrame(initPool = valueArguments) { handleIntrinsicMethods(owner) } return stack.newFrame(initPool = valueArguments) { handleIntrinsicMethods(owner) }
} }
val state = Common(parent).apply { this.typeArguments.addAll(typeArguments) } val state = Common(irClass).apply { this.typeArguments.addAll(typeArguments) }
if (parent.isLocal) state.fields.addAll(stack.getAll()) // TODO save only necessary declarations if (irClass.isLocal) state.fields.addAll(stack.getAll()) // TODO save only necessary declarations
if (irClass.isInner) {
constructorCall.dispatchReceiver!!.interpret().check { return it }
state.outerClass = Variable(constructorCall.symbol.owner.dispatchReceiverParameter!!.descriptor, stack.popReturnValue())
}
valueArguments.add(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body valueArguments.add(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
return stack.newFrame(initPool = valueArguments + state.typeArguments) { return stack.newFrame(initPool = valueArguments + state.typeArguments) {
val statements = constructorCall.getBody()!!.statements val statements = constructorCall.getBody()!!.statements
@@ -5,22 +5,19 @@
package org.jetbrains.kotlin.backend.common.interpreter.state package org.jetbrains.kotlin.backend.common.interpreter.state
import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden
import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.isFakeOverride
import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.isInterface
class Common private constructor( class Common private constructor(
override val irClass: IrClass, override val fields: MutableList<Variable>, override val typeArguments: MutableList<Variable>, override val irClass: IrClass, override val fields: MutableList<Variable>
superClass: Complex?, subClass: Complex? ) : Complex(irClass, fields) {
) : Complex(irClass, fields, superClass, subClass) {
constructor(irClass: IrClass) : this(irClass, mutableListOf(), mutableListOf(), null, null) constructor(irClass: IrClass) : this(irClass, mutableListOf())
fun setSuperClassRecursive() { fun setSuperClassRecursive() {
var thisClass: Common? = this var thisClass: Common? = this
@@ -51,9 +48,7 @@ class Common private constructor(
.let { getOverridden(it as IrSimpleFunction, this) } .let { getOverridden(it as IrSimpleFunction, this) }
} }
override fun copy(): State { override fun copy() = Common(irClass, fields).copyFrom(this)
return Common(irClass, fields, typeArguments, superClass, subClass ?: this)
}
override fun toString(): String { override fun toString(): String {
return "Common(obj='${irClass.fqNameForIrSerialization}', super=$superClass, values=$fields)" return "Common(obj='${irClass.fqNameForIrSerialization}', super=$superClass, values=$fields)"
@@ -18,10 +18,11 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.isInterface
abstract class Complex( abstract class Complex(override val irClass: IrClass, override val fields: MutableList<Variable>) : State {
override val irClass: IrClass, override val fields: MutableList<Variable>, var superClass: Complex?, var subClass: Complex? var superClass: Complex? = null
) : State { var subClass: Complex? = null
abstract val typeArguments: MutableList<Variable> val typeArguments: MutableList<Variable> = mutableListOf()
var outerClass: Variable? = null
fun setSuperClassInstance(superClass: Complex) { fun setSuperClassInstance(superClass: Complex) {
if (this.irClass == superClass.irClass) { if (this.irClass == superClass.irClass) {
@@ -52,6 +53,14 @@ abstract class Complex(
} }
} }
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? { private fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? {
val propertyGetters = irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter } val propertyGetters = irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter }
val functions = irClass.declarations.filterIsInstance<IrFunction>() val functions = irClass.declarations.filterIsInstance<IrFunction>()
@@ -16,9 +16,8 @@ import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import kotlin.math.min import kotlin.math.min
class ExceptionState private constructor( class ExceptionState private constructor(
override val irClass: IrClass, override val fields: MutableList<Variable>, stackTrace: List<String>, subClass: Complex? = null override val irClass: IrClass, override val fields: MutableList<Variable>, stackTrace: List<String>
) : Complex(irClass, fields, null, subClass) { ) : Complex(irClass, fields) {
override val typeArguments: MutableList<Variable> = mutableListOf()
private lateinit var exceptionFqName: String private lateinit var exceptionFqName: String
private val exceptionHierarchy = mutableListOf<String>() private val exceptionHierarchy = mutableListOf<String>()
@@ -106,9 +105,7 @@ class ExceptionState private constructor(
fun getThisAsCauseForException() = ExceptionData(this) fun getThisAsCauseForException() = ExceptionData(this)
override fun copy(): State { override fun copy() = ExceptionState(irClass, fields, stackTrace).copyFrom(this)
return ExceptionState(irClass, fields, stackTrace, subClass ?: this)
}
companion object { companion object {
private fun IrClass.getPropertyByName(name: String): IrProperty { private fun IrClass.getPropertyByName(name: String): IrProperty {
@@ -34,15 +34,11 @@ import java.lang.invoke.MethodHandle
import java.lang.invoke.MethodHandles import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType import java.lang.invoke.MethodType
class Wrapper private constructor( class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, mutableListOf()) {
val value: Any, override val irClass: IrClass, subClass: Complex?, override val typeArguments: MutableList<Variable>
) : Complex(irClass, mutableListOf(), null, subClass) {
private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe() private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe()
private val receiverClass = irClass.defaultType.getClass(true) private val receiverClass = irClass.defaultType.getClass(true)
constructor(value: Any, irClass: IrClass) : this(value, irClass, null, mutableListOf())
fun getMethod(irFunction: IrFunction): MethodHandle? { fun getMethod(irFunction: IrFunction): MethodHandle? {
if (irFunction.getEvaluateIntrinsicValue()?.isEmpty() == true) return null // this method will handle IntrinsicEvaluator if (irFunction.getEvaluateIntrinsicValue()?.isEmpty() == true) return null // this method will handle IntrinsicEvaluator
// if function is actually a getter, then use "get${property.name.capitalize()}" as method name // if function is actually a getter, then use "get${property.name.capitalize()}" as method name
@@ -198,9 +194,7 @@ class Wrapper private constructor(
} }
} }
override fun copy(): State { override fun copy() = Wrapper(value, irClass).copyFrom(this)
return Wrapper(value, irClass, subClass ?: this, typeArguments)
}
override fun toString(): String { override fun toString(): String {
return "Wrapper(obj='$typeFqName', value=$value)" return "Wrapper(obj='$typeFqName', value=$value)"