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
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) {
// inline only methods are not presented in lookup table, so must be interpreted instead of execution
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
@@ -321,20 +325,24 @@ class IrInterpreter(irModule: IrModuleFragment) {
interpretValueParameters(constructorCall, owner, valueArguments).check { return it }
val parent = owner.parent as IrClass
val typeArguments = getTypeArguments(parent, constructorCall) { stack.getVariableState(it) } + stack.getAllTypeArguments()
if (parent.hasAnnotation(evaluateIntrinsicAnnotation)) {
val irClass = owner.parent as IrClass
val typeArguments = getTypeArguments(irClass, constructorCall) { stack.getVariableState(it) } + stack.getAllTypeArguments()
if (irClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
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
return stack.newFrame(initPool = valueArguments) { handleIntrinsicMethods(owner) }
}
val state = Common(parent).apply { this.typeArguments.addAll(typeArguments) }
if (parent.isLocal) state.fields.addAll(stack.getAll()) // TODO save only necessary declarations
val state = Common(irClass).apply { this.typeArguments.addAll(typeArguments) }
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
return stack.newFrame(initPool = valueArguments + state.typeArguments) {
val statements = constructorCall.getBody()!!.statements
@@ -5,22 +5,19 @@
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.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.isFakeOverride
import org.jetbrains.kotlin.ir.util.isInterface
class Common private constructor(
override val irClass: IrClass, override val fields: MutableList<Variable>, override val typeArguments: MutableList<Variable>,
superClass: Complex?, subClass: Complex?
) : Complex(irClass, fields, superClass, subClass) {
override val irClass: IrClass, override val fields: MutableList<Variable>
) : Complex(irClass, fields) {
constructor(irClass: IrClass) : this(irClass, mutableListOf(), mutableListOf(), null, null)
constructor(irClass: IrClass) : this(irClass, mutableListOf())
fun setSuperClassRecursive() {
var thisClass: Common? = this
@@ -51,9 +48,7 @@ class Common private constructor(
.let { getOverridden(it as IrSimpleFunction, this) }
}
override fun copy(): State {
return Common(irClass, fields, typeArguments, superClass, subClass ?: this)
}
override fun copy() = Common(irClass, fields).copyFrom(this)
override fun toString(): String {
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.isInterface
abstract class Complex(
override val irClass: IrClass, override val fields: MutableList<Variable>, var superClass: Complex?, var subClass: Complex?
) : State {
abstract val typeArguments: MutableList<Variable>
abstract class Complex(override val irClass: IrClass, override val fields: MutableList<Variable>) : State {
var superClass: Complex? = null
var subClass: Complex? = null
val typeArguments: MutableList<Variable> = mutableListOf()
var outerClass: Variable? = null
fun setSuperClassInstance(superClass: Complex) {
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? {
val propertyGetters = irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter }
val functions = irClass.declarations.filterIsInstance<IrFunction>()
@@ -16,9 +16,8 @@ import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import kotlin.math.min
class ExceptionState private constructor(
override val irClass: IrClass, override val fields: MutableList<Variable>, stackTrace: List<String>, subClass: Complex? = null
) : Complex(irClass, fields, null, subClass) {
override val typeArguments: MutableList<Variable> = mutableListOf()
override val irClass: IrClass, override val fields: MutableList<Variable>, stackTrace: List<String>
) : Complex(irClass, fields) {
private lateinit var exceptionFqName: String
private val exceptionHierarchy = mutableListOf<String>()
@@ -106,9 +105,7 @@ class ExceptionState private constructor(
fun getThisAsCauseForException() = ExceptionData(this)
override fun copy(): State {
return ExceptionState(irClass, fields, stackTrace, subClass ?: this)
}
override fun copy() = ExceptionState(irClass, fields, stackTrace).copyFrom(this)
companion object {
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.MethodType
class Wrapper private constructor(
val value: Any, override val irClass: IrClass, subClass: Complex?, override val typeArguments: MutableList<Variable>
) : Complex(irClass, mutableListOf(), null, subClass) {
class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, mutableListOf()) {
private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe()
private val receiverClass = irClass.defaultType.getClass(true)
constructor(value: Any, irClass: IrClass) : this(value, irClass, null, mutableListOf())
fun getMethod(irFunction: IrFunction): MethodHandle? {
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
@@ -198,9 +194,7 @@ class Wrapper private constructor(
}
}
override fun copy(): State {
return Wrapper(value, irClass, subClass ?: this, typeArguments)
}
override fun copy() = Wrapper(value, irClass).copyFrom(this)
override fun toString(): String {
return "Wrapper(obj='$typeFqName', value=$value)"