Implement List and MutableList interpretation
This commit is contained in:
+1
-24
@@ -198,28 +198,6 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO extract in Wrapper
|
|
||||||
private fun calculateIntrinsic(irFunction: IrFunction, data: Frame): Code {
|
|
||||||
val annotation = irFunction.getAnnotation(evaluateIntrinsicAnnotation)
|
|
||||||
val argsValues = data.getAll()
|
|
||||||
.map { it.state }
|
|
||||||
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
|
||||||
.map { it.value }
|
|
||||||
|
|
||||||
val textClass = Class.forName((annotation.getValueArgument(0) as IrConst<*>).value.toString())
|
|
||||||
val returnClass = irFunction.returnType.getFqName()!!.let { getPrimitiveClass(it) ?: Class.forName(it) }
|
|
||||||
val extensionClass = irFunction.extensionReceiverParameter?.type?.getFqName()?.let { getPrimitiveClass(it) ?: Class.forName(it) }
|
|
||||||
val argsClasses = irFunction.valueParameters.map {
|
|
||||||
it.descriptor.fqNameSafe.asString().let { getPrimitiveClass(it) ?: Class.forName(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val methodSignature = MethodType.methodType(returnClass, listOfNotNull(extensionClass) + argsClasses)
|
|
||||||
val method = MethodHandles.lookup().findStatic(textClass, irFunction.name.asString(), methodSignature)
|
|
||||||
val result = method.invokeWithArguments(argsValues)
|
|
||||||
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
|
||||||
return Code.NEXT
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): Code {
|
private fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): Code {
|
||||||
for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) {
|
for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) {
|
||||||
val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: Code.NEXT
|
val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: Code.NEXT
|
||||||
@@ -255,7 +233,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
(extensionReceiver is Wrapper && rawDispatchReceiver == null)
|
(extensionReceiver is Wrapper && rawDispatchReceiver == null)
|
||||||
val code = when {
|
val code = when {
|
||||||
isWrapper -> ((dispatchReceiver ?: extensionReceiver) as Wrapper).invoke(irFunction as IrFunctionImpl, newFrame)
|
isWrapper -> ((dispatchReceiver ?: extensionReceiver) as Wrapper).invoke(irFunction as IrFunctionImpl, newFrame)
|
||||||
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> calculateIntrinsic(irFunction, newFrame)
|
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.invokeStatic(irFunction as IrFunctionImpl, newFrame)
|
||||||
irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check
|
irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check
|
||||||
irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame)
|
irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame)
|
||||||
irFunction.body == null -> calculateBuiltIns(irFunction, newFrame)
|
irFunction.body == null -> calculateBuiltIns(irFunction, newFrame)
|
||||||
@@ -268,7 +246,6 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
private fun interpretConstructor(constructorCall: IrFunctionAccessExpression, data: Frame): Code {
|
private fun interpretConstructor(constructorCall: IrFunctionAccessExpression, data: Frame): Code {
|
||||||
interpretValueParameters(constructorCall, data).also { if (it != Code.NEXT) return it }
|
interpretValueParameters(constructorCall, data).also { if (it != Code.NEXT) return it }
|
||||||
val valueParameters = constructorCall.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList()
|
val valueParameters = constructorCall.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList()
|
||||||
|
|
||||||
val newFrame = InterpreterFrame(valueParameters)
|
val newFrame = InterpreterFrame(valueParameters)
|
||||||
val state = Complex(constructorCall.symbol.owner.parent as IrClass, mutableListOf())
|
val state = Complex(constructorCall.symbol.owner.parent as IrClass, mutableListOf())
|
||||||
newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
|
newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
|
||||||
|
|||||||
+7
@@ -18,8 +18,11 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.types.isArray
|
||||||
|
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||||
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.isFakeOverride
|
||||||
|
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||||
@@ -151,4 +154,8 @@ fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? {
|
|||||||
|
|
||||||
fun IrType.getFqName(): String? {
|
fun IrType.getFqName(): String? {
|
||||||
return this.classOrNull?.owner?.fqNameForIrSerialization?.asString()
|
return this.classOrNull?.owner?.fqNameForIrSerialization?.asString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrType?.isPrimitiveState(): Boolean {
|
||||||
|
return this?.isPrimitiveType() == true || this?.isArray() == true || this?.isPrimitiveArray() == true
|
||||||
}
|
}
|
||||||
+120
-47
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.common.interpreter.stack
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.*
|
import org.jetbrains.kotlin.backend.common.interpreter.*
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.evaluateIntrinsicAnnotation
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions
|
||||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
@@ -15,15 +16,12 @@ 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.IrProperty
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
|
||||||
import org.jetbrains.kotlin.ir.types.isNullable
|
|
||||||
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||||
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|
||||||
import java.lang.invoke.MethodHandles
|
import java.lang.invoke.MethodHandles
|
||||||
import java.lang.invoke.MethodType
|
import java.lang.invoke.MethodType
|
||||||
|
|
||||||
@@ -71,6 +69,26 @@ open class Primitive<T>(var value: T, val type: IrType) : State {
|
|||||||
.firstOrNull { it.descriptor.valueParameters.map { it.type } == descriptor.valueParameters.map { it.type } }
|
.firstOrNull { it.descriptor.valueParameters.map { it.type } == descriptor.valueParameters.map { it.type } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as Primitive<*>
|
||||||
|
|
||||||
|
if (value != other.value) return false
|
||||||
|
if (type != other.type) return false
|
||||||
|
if (fields != other.fields) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = value?.hashCode() ?: 0
|
||||||
|
result = 31 * result + type.hashCode()
|
||||||
|
result = 31 * result + fields.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Primitive(value=$value, type=${type.getName()})"
|
return "Primitive(value=$value, type=${type.getName()})"
|
||||||
}
|
}
|
||||||
@@ -121,63 +139,118 @@ class Wrapper(private val type: IrClass, private val wrapperValue: Any) : Comple
|
|||||||
?: Class.forName(typeFqName.toString())
|
?: Class.forName(typeFqName.toString())
|
||||||
|
|
||||||
fun invoke(irFunction: IrFunctionImpl, data: Frame): Code {
|
fun invoke(irFunction: IrFunctionImpl, data: Frame): Code {
|
||||||
val methodName = irFunction.name.toString()
|
val methodName = (irFunction.correspondingPropertySymbol?.owner?.name ?: irFunction.name).toString()
|
||||||
|
|
||||||
val returnClass = irFunction.returnType.getCorrespondingClass(irFunction.isReturnTypePrimitiveAsObject())
|
val methodType = irFunction.getMethodType()
|
||||||
val argsClasses = irFunction.valueParameters.map { it.type.getCorrespondingClass(irFunction.isValueParameterPrimitiveAsObject(it.index)) }
|
|
||||||
val argsValues = data.getAll().map { (it.state as? Wrapper)?.wrapperValue ?: (it.state as? Primitive<*>)?.value }
|
|
||||||
|
|
||||||
val methodType = MethodType.methodType(returnClass, argsClasses)
|
|
||||||
val method = MethodHandles.lookup().findVirtual(receiverClass, methodName, methodType)
|
val method = MethodHandles.lookup().findVirtual(receiverClass, methodName, methodType)
|
||||||
|
|
||||||
val result = method.invokeWithArguments(argsValues)
|
val result = method.invokeWithArguments(irFunction.getArgs(data))
|
||||||
data.pushReturnValue(result.toState(irFunction.returnType))
|
data.pushReturnValue(result.toState(irFunction.returnType))
|
||||||
|
|
||||||
return Code.NEXT
|
return Code.NEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrType.getCorrespondingClass(asObject: Boolean): Class<out Any> {
|
companion object {
|
||||||
val fqName = this.getFqName()
|
fun invokeStatic(irFunction: IrFunctionImpl, data: Frame): Code {
|
||||||
return when {
|
val annotation = irFunction.getAnnotation(evaluateIntrinsicAnnotation)
|
||||||
this.isPrimitiveType() -> getPrimitiveClass(fqName!!, asObject)
|
val jvmFileName = Class.forName((annotation.getValueArgument(0) as IrConst<*>).value.toString())
|
||||||
this.isTypeParameter() -> Any::class.java
|
|
||||||
else -> JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(fqName!!))?.let { Class.forName(it.asSingleFqName().toString()) }
|
|
||||||
} ?: Class.forName(fqName)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrFunctionImpl.getOriginalOverriddenSymbols(): MutableList<IrSimpleFunctionSymbol> {
|
val methodType = irFunction.getMethodType(withExtensionReceiver = true)
|
||||||
val overriddenSymbols = mutableListOf<IrSimpleFunctionSymbol>()
|
val method = MethodHandles.lookup().findStatic(jvmFileName, irFunction.name.asString(), methodType)
|
||||||
val pool = this.overriddenSymbols.toMutableList()
|
|
||||||
val iterator = pool.listIterator()
|
val result = method.invokeWithArguments(irFunction.getArgs(data))
|
||||||
for (symbol in iterator) {
|
data.pushReturnValue(result.toState(irFunction.returnType))
|
||||||
if (symbol.owner.overriddenSymbols.isEmpty()) {
|
|
||||||
overriddenSymbols += symbol
|
return Code.NEXT
|
||||||
iterator.remove()
|
|
||||||
} else {
|
|
||||||
symbol.owner.overriddenSymbols.forEach { iterator.add(it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overriddenSymbols.isEmpty()) overriddenSymbols.add(this.symbol)
|
private fun IrFunctionImpl.getMethodType(withExtensionReceiver: Boolean = false): MethodType {
|
||||||
return overriddenSymbols
|
val returnClass = this.returnType.getClass(this.isReturnTypePrimitiveAsObject())
|
||||||
}
|
val argsClasses = this.valueParameters.map { it.type.getClass(this.isValueParameterPrimitiveAsObject(it.index)) }
|
||||||
|
|
||||||
private fun IrFunctionImpl.isReturnTypePrimitiveAsObject(): Boolean {
|
val extensionClass = when {
|
||||||
for (symbol in getOriginalOverriddenSymbols()) {
|
withExtensionReceiver -> this.extensionReceiverParameter?.type?.getClass(this.isExtensionReceiverPrimitiveAsObject())
|
||||||
if (!symbol.owner.returnType.isTypeParameter() && !symbol.owner.returnType.isNullable()) {
|
else -> null
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrFunctionImpl.isValueParameterPrimitiveAsObject(index: Int): Boolean {
|
return MethodType.methodType(returnClass, listOfNotNull(extensionClass) + argsClasses)
|
||||||
for (symbol in getOriginalOverriddenSymbols()) {
|
}
|
||||||
if (!symbol.owner.valueParameters[index].type.isTypeParameter() && !symbol.owner.valueParameters[index].type.isNullable()) {
|
|
||||||
return false
|
private fun IrFunctionImpl.getArgs(data: Frame): List<Any?> {
|
||||||
}
|
val argsValues = data.getAll().map { (it.state as? Wrapper)?.wrapperValue ?: (it.state as? Any) }.toMutableList()
|
||||||
|
|
||||||
|
if (this.extensionReceiverParameter?.type.isPrimitiveState()) {
|
||||||
|
val varargState = data.getVariableState(this.symbol.getExtensionReceiver()!!)
|
||||||
|
argsValues[0] = (varargState as Primitive<*>).value
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((index, valueParameter) in this.valueParameters.withIndex().reversed()) {
|
||||||
|
if (valueParameter.type.isPrimitiveState()) {
|
||||||
|
argsValues[argsValues.size - 1 - index] = (argsValues[argsValues.size - 1 - index] as Primitive<*>).value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO if vararg isn't last parameter
|
||||||
|
// must convert vararg array into separated elements for correct invoke
|
||||||
|
if (this.valueParameters.lastOrNull()?.varargElementType != null) {
|
||||||
|
argsValues.removeAt(argsValues.size - 1)
|
||||||
|
val varargState = data.getVariableState(this.valueParameters.last().descriptor)
|
||||||
|
val varargValue = (varargState as? Wrapper)?.wrapperValue ?: (varargState as Primitive<*>).value
|
||||||
|
argsValues.addAll(varargValue as Array<out Any?>)
|
||||||
|
}
|
||||||
|
|
||||||
|
return argsValues
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrType.getClass(asObject: Boolean): Class<out Any> {
|
||||||
|
val fqName = this.getFqName()
|
||||||
|
return when {
|
||||||
|
this.isPrimitiveType() -> getPrimitiveClass(fqName!!, asObject)
|
||||||
|
this.isArray() -> if (asObject) Array<Any?>::class.javaObjectType else Array<Any?>::class.java
|
||||||
|
//TODO primitive array
|
||||||
|
this.isTypeParameter() -> Any::class.java
|
||||||
|
else -> JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(fqName!!))?.let { Class.forName(it.asSingleFqName().toString()) }
|
||||||
|
} ?: Class.forName(fqName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunctionImpl.getOriginalOverriddenSymbols(): MutableList<IrSimpleFunctionSymbol> {
|
||||||
|
val overriddenSymbols = mutableListOf<IrSimpleFunctionSymbol>()
|
||||||
|
val pool = this.overriddenSymbols.toMutableList()
|
||||||
|
val iterator = pool.listIterator()
|
||||||
|
for (symbol in iterator) {
|
||||||
|
if (symbol.owner.overriddenSymbols.isEmpty()) {
|
||||||
|
overriddenSymbols += symbol
|
||||||
|
iterator.remove()
|
||||||
|
} else {
|
||||||
|
symbol.owner.overriddenSymbols.forEach { iterator.add(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overriddenSymbols.isEmpty()) overriddenSymbols.add(this.symbol)
|
||||||
|
return overriddenSymbols
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunctionImpl.isExtensionReceiverPrimitiveAsObject(): Boolean {
|
||||||
|
return this.extensionReceiverParameter?.type?.isPrimitiveType() == false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunctionImpl.isReturnTypePrimitiveAsObject(): Boolean {
|
||||||
|
for (symbol in getOriginalOverriddenSymbols()) {
|
||||||
|
if (!symbol.owner.returnType.isTypeParameter() && !symbol.owner.returnType.isNullable()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunctionImpl.isValueParameterPrimitiveAsObject(index: Int): Boolean {
|
||||||
|
for (symbol in getOriginalOverriddenSymbols()) {
|
||||||
|
if (!symbol.owner.valueParameters[index].type.isTypeParameter() && !symbol.owner.valueParameters[index].type.isNullable()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun copy(): State {
|
override fun copy(): State {
|
||||||
|
|||||||
Reference in New Issue
Block a user