Implement vararg interpretation
This commit is contained in:
@@ -4,6 +4,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compile(project(":core:descriptors.jvm")) //used to get java classes fq names by kotlin names
|
||||||
compile(project(":compiler:util"))
|
compile(project(":compiler:util"))
|
||||||
compile(project(":compiler:frontend"))
|
compile(project(":compiler:frontend"))
|
||||||
compile(project(":compiler:backend-common"))
|
compile(project(":compiler:backend-common"))
|
||||||
|
|||||||
+61
-16
@@ -12,18 +12,16 @@ import org.jetbrains.kotlin.ir.IrElement
|
|||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
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.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||||
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.util.constructors
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
|
||||||
import org.jetbrains.kotlin.ir.util.statements
|
import org.jetbrains.kotlin.ir.util.statements
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
|
||||||
import java.lang.invoke.MethodHandles
|
import java.lang.invoke.MethodHandles
|
||||||
import java.lang.invoke.MethodType
|
import java.lang.invoke.MethodType
|
||||||
|
|
||||||
@@ -31,10 +29,27 @@ enum class Code(var info: String = "") {
|
|||||||
NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
|
NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
class IrInterpreter(irModule: IrModuleFragment) {
|
||||||
|
private val irBuiltIns = irModule.irBuiltins
|
||||||
|
|
||||||
|
private fun Any?.getType(defaultType: IrType): IrType {
|
||||||
|
return when (this) {
|
||||||
|
is Boolean -> irBuiltIns.booleanType
|
||||||
|
is Char -> irBuiltIns.charType
|
||||||
|
is Byte -> irBuiltIns.byteType
|
||||||
|
is Short -> irBuiltIns.shortType
|
||||||
|
is Int -> irBuiltIns.intType
|
||||||
|
is Long -> irBuiltIns.longType
|
||||||
|
is String -> irBuiltIns.stringType
|
||||||
|
is Float -> irBuiltIns.floatType
|
||||||
|
is Double -> irBuiltIns.doubleType
|
||||||
|
null -> irBuiltIns.nothingType
|
||||||
|
else -> defaultType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun interpret(expression: IrExpression): IrExpression {
|
fun interpret(expression: IrExpression): IrExpression {
|
||||||
return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(irBuiltIns, expression)
|
return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrElement.interpret(data: Frame): Code {
|
private fun IrElement.interpret(data: Frame): Code {
|
||||||
@@ -60,6 +75,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
is IrWhen -> interpretWhen(this, data)
|
is IrWhen -> interpretWhen(this, data)
|
||||||
is IrBreak -> interpretBreak(this, data)
|
is IrBreak -> interpretBreak(this, data)
|
||||||
is IrContinue -> interpretContinue(this, data)
|
is IrContinue -> interpretContinue(this, data)
|
||||||
|
is IrVararg -> interpretVararg(this, data)
|
||||||
|
|
||||||
else -> TODO("${this.javaClass} not supported")
|
else -> TODO("${this.javaClass} not supported")
|
||||||
}
|
}
|
||||||
@@ -133,11 +149,11 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
val descriptor = irFunction.descriptor
|
val descriptor = irFunction.descriptor
|
||||||
val methodName = descriptor.name.asString()
|
val methodName = descriptor.name.asString()
|
||||||
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
||||||
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) }
|
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { it.original.type }
|
||||||
val argsValues = data.getAll()
|
val argsValues = data.getAll()
|
||||||
.map { it.state }
|
.map { it.state }
|
||||||
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
||||||
.map { it.getValue() }
|
.map { it.value }
|
||||||
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
|
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
|
||||||
//todo try catch
|
//todo try catch
|
||||||
val result = when (argsType.size) {
|
val result = when (argsType.size) {
|
||||||
@@ -161,7 +177,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
}
|
}
|
||||||
else -> throw UnsupportedOperationException("Unsupported number of arguments")
|
else -> throw UnsupportedOperationException("Unsupported number of arguments")
|
||||||
}
|
}
|
||||||
data.pushReturnValue(result.toState(irBuiltIns))
|
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
||||||
return Code.NEXT
|
return Code.NEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +186,9 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
||||||
|
|
||||||
val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> }
|
val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> }
|
||||||
primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getValue().toIrConst(irBuiltIns)) }
|
primitiveValueParameters.forEachIndexed { index, primitive ->
|
||||||
|
constructorCall.putValueArgument(index, primitive.value.toIrConst(primitive.type))
|
||||||
|
}
|
||||||
|
|
||||||
val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters)
|
val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters)
|
||||||
val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList())
|
val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList())
|
||||||
@@ -180,12 +198,13 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO extract in Wrapper
|
||||||
private fun calculateIntrinsic(irFunction: IrFunction, data: Frame): Code {
|
private fun calculateIntrinsic(irFunction: IrFunction, data: Frame): Code {
|
||||||
val annotation = irFunction.getAnnotation(evaluateIntrinsicAnnotation)
|
val annotation = irFunction.getAnnotation(evaluateIntrinsicAnnotation)
|
||||||
val argsValues = data.getAll()
|
val argsValues = data.getAll()
|
||||||
.map { it.state }
|
.map { it.state }
|
||||||
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
||||||
.map { it.getValue() }
|
.map { it.value }
|
||||||
|
|
||||||
val textClass = Class.forName((annotation.getValueArgument(0) as IrConst<*>).value.toString())
|
val textClass = Class.forName((annotation.getValueArgument(0) as IrConst<*>).value.toString())
|
||||||
val returnClass = irFunction.returnType.getFqName()!!.let { getPrimitiveClass(it) ?: Class.forName(it) }
|
val returnClass = irFunction.returnType.getFqName()!!.let { getPrimitiveClass(it) ?: Class.forName(it) }
|
||||||
@@ -197,7 +216,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
val methodSignature = MethodType.methodType(returnClass, listOfNotNull(extensionClass) + argsClasses)
|
val methodSignature = MethodType.methodType(returnClass, listOfNotNull(extensionClass) + argsClasses)
|
||||||
val method = MethodHandles.lookup().findStatic(textClass, irFunction.name.asString(), methodSignature)
|
val method = MethodHandles.lookup().findStatic(textClass, irFunction.name.asString(), methodSignature)
|
||||||
val result = method.invokeWithArguments(argsValues)
|
val result = method.invokeWithArguments(argsValues)
|
||||||
data.pushReturnValue(result.toState(irBuiltIns))
|
data.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
||||||
return Code.NEXT
|
return Code.NEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,8 +237,8 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
// dispatch receiver processing
|
// dispatch receiver processing
|
||||||
val rawDispatchReceiver = expression.dispatchReceiver
|
val rawDispatchReceiver = expression.dispatchReceiver
|
||||||
rawDispatchReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it }
|
rawDispatchReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it }
|
||||||
val irCallReceiver = rawDispatchReceiver?.let { data.popReturnValue() }
|
val dispatchReceiver = rawDispatchReceiver?.let { data.popReturnValue() }
|
||||||
val irFunctionReceiver = if (expression.superQualifierSymbol == null) irCallReceiver else (irCallReceiver as Complex).superType
|
val irFunctionReceiver = if (expression.superQualifierSymbol == null) dispatchReceiver else (dispatchReceiver as Complex).superType
|
||||||
// it is important firstly to add receiver, then arguments; this order is used in builtin method call
|
// it is important firstly to add receiver, then arguments; this order is used in builtin method call
|
||||||
val irFunction = irFunctionReceiver?.getIrFunction(expression.symbol.descriptor) ?: expression.symbol.owner
|
val irFunction = irFunctionReceiver?.getIrFunction(expression.symbol.descriptor) ?: expression.symbol.owner
|
||||||
irFunctionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getDispatchReceiver()!!, it)) }
|
irFunctionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getDispatchReceiver()!!, it)) }
|
||||||
@@ -227,11 +246,15 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
// extension receiver processing
|
// extension receiver processing
|
||||||
val rawExtensionReceiver = expression.extensionReceiver
|
val rawExtensionReceiver = expression.extensionReceiver
|
||||||
rawExtensionReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it }
|
rawExtensionReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it }
|
||||||
rawExtensionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getExtensionReceiver()!!, data.popReturnValue())) }
|
val extensionReceiver = rawExtensionReceiver?.let { data.popReturnValue() }
|
||||||
|
extensionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getExtensionReceiver()!!, it)) }
|
||||||
|
|
||||||
newFrame.addAll(valueParameters)
|
newFrame.addAll(valueParameters)
|
||||||
|
|
||||||
|
val isWrapper = (dispatchReceiver is Wrapper && rawExtensionReceiver == null) ||
|
||||||
|
(extensionReceiver is Wrapper && rawDispatchReceiver == null)
|
||||||
val code = when {
|
val code = when {
|
||||||
|
isWrapper -> ((dispatchReceiver ?: extensionReceiver) as Wrapper).invoke(irFunction as IrFunctionImpl, newFrame)
|
||||||
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> calculateIntrinsic(irFunction, newFrame)
|
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> calculateIntrinsic(irFunction, 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)
|
||||||
@@ -307,7 +330,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
var code = Code.NEXT
|
var code = Code.NEXT
|
||||||
while (code == Code.NEXT) {
|
while (code == Code.NEXT) {
|
||||||
code = expression.condition.interpret(data)
|
code = expression.condition.interpret(data)
|
||||||
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getValue() as? Boolean == true) {
|
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.value as? Boolean == true) {
|
||||||
code = expression.body?.interpret(data) ?: Code.NEXT
|
code = expression.body?.interpret(data) ?: Code.NEXT
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
@@ -327,7 +350,7 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
|
|
||||||
private fun interpretBranch(expression: IrBranch, data: Frame): Code {
|
private fun interpretBranch(expression: IrBranch, data: Frame): Code {
|
||||||
var code = expression.condition.interpret(data)
|
var code = expression.condition.interpret(data)
|
||||||
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getValue() as? Boolean == true) {
|
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.value as? Boolean == true) {
|
||||||
code = expression.result.interpret(data)
|
code = expression.result.interpret(data)
|
||||||
if (code == Code.NEXT) return Code.BREAK_WHEN
|
if (code == Code.NEXT) return Code.BREAK_WHEN
|
||||||
}
|
}
|
||||||
@@ -403,4 +426,26 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun interpretVararg(expression: IrVararg, data: Frame): Code {
|
||||||
|
val args = expression.elements.map {
|
||||||
|
it.interpret(data).apply { if (this != Code.NEXT) return this }
|
||||||
|
data.popReturnValue()
|
||||||
|
}
|
||||||
|
val type = expression.type
|
||||||
|
val array = when (type.getFqName()) {
|
||||||
|
"kotlin.ByteArray" -> Primitive(args.map { (it as Primitive<Byte>).value }.toByteArray(), type)
|
||||||
|
"kotlin.CharArray" -> Primitive(args.map { (it as Primitive<Char>).value }.toCharArray(), type)
|
||||||
|
"kotlin.ShortArray" -> Primitive(args.map { (it as Primitive<Short>).value }.toShortArray(), type)
|
||||||
|
"kotlin.IntArray" -> Primitive(args.map { (it as Primitive<Int>).value }.toIntArray(), type)
|
||||||
|
"kotlin.LongArray" -> Primitive(args.map { (it as Primitive<Long>).value }.toLongArray(), type)
|
||||||
|
"kotlin.FloatArray" -> Primitive(args.map { (it as Primitive<Float>).value }.toFloatArray(), type)
|
||||||
|
"kotlin.DoubleArray" -> Primitive(args.map { (it as Primitive<Double>).value }.toDoubleArray(), type)
|
||||||
|
"kotlin.BooleanArray" -> Primitive(args.map { (it as Primitive<Boolean>).value }.toBooleanArray(), type)
|
||||||
|
else -> Primitive<Array<*>>(args.toTypedArray(), type)
|
||||||
|
}
|
||||||
|
data.pushReturnValue(array)
|
||||||
|
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+31
-30
@@ -5,15 +5,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.interpreter
|
package org.jetbrains.kotlin.backend.common.interpreter
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.Complex
|
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.State
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.State
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Wrapper
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
||||||
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.descriptors.IrBuiltIns
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
@@ -81,35 +80,37 @@ fun IrFunction.isFakeOverridden(): Boolean {
|
|||||||
return this.symbol.owner.isFakeOverride
|
return this.symbol.owner.isFakeOverride
|
||||||
}
|
}
|
||||||
|
|
||||||
fun State.toIrExpression(irBuiltIns: IrBuiltIns, expression: IrExpression): IrExpression {
|
fun State.toIrExpression(expression: IrExpression): IrExpression {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Primitive<*> -> this.getValue().toIrConst( // this is necessary to replace ir offsets
|
is Primitive<*> -> this.value.toIrConst( // this is necessary to replace ir offsets
|
||||||
irBuiltIns, expression.startOffset, expression.endOffset
|
this.type, expression.startOffset, expression.endOffset
|
||||||
)
|
)
|
||||||
else -> TODO("not supported")
|
else -> TODO("not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Any?.toState(irBuiltIns: IrBuiltIns): State {
|
fun Any?.toState(irType: IrType): State {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Complex -> this
|
is State -> this
|
||||||
else -> this.toIrConst(irBuiltIns).toPrimitive()
|
is Boolean, is Char, is Byte, is Short, is Int, is Long, is String, is Float, is Double -> Primitive(this, irType)
|
||||||
|
null -> Primitive(this, irType)
|
||||||
|
else -> Wrapper(irType.classOrNull!!.owner, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Any?.toIrConst(irBuiltIns: IrBuiltIns, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> {
|
fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Boolean -> IrConstImpl(startOffset, endOffset, irBuiltIns.booleanType, IrConstKind.Boolean, this)
|
is Boolean -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Boolean, this)
|
||||||
is Char -> IrConstImpl(startOffset, endOffset, irBuiltIns.charType, IrConstKind.Char, this)
|
is Char -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Char, this)
|
||||||
is Byte -> IrConstImpl(startOffset, endOffset, irBuiltIns.byteType, IrConstKind.Byte, this)
|
is Byte -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Byte, this)
|
||||||
is Short -> IrConstImpl(startOffset, endOffset, irBuiltIns.shortType, IrConstKind.Short, this)
|
is Short -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Short, this)
|
||||||
is Int -> IrConstImpl(startOffset, endOffset, irBuiltIns.intType, IrConstKind.Int, this)
|
is Int -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Int, this)
|
||||||
is Long -> IrConstImpl(startOffset, endOffset, irBuiltIns.longType, IrConstKind.Long, this)
|
is Long -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Long, this)
|
||||||
is String -> IrConstImpl(startOffset, endOffset, irBuiltIns.stringType, IrConstKind.String, this)
|
is String -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.String, this)
|
||||||
is Float -> IrConstImpl(startOffset, endOffset, irBuiltIns.floatType, IrConstKind.Float, this)
|
is Float -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Float, this)
|
||||||
is Double -> IrConstImpl(startOffset, endOffset, irBuiltIns.doubleType, IrConstKind.Double, this)
|
is Double -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Double, this)
|
||||||
null -> IrConstImpl(startOffset, endOffset, irBuiltIns.nothingType, IrConstKind.Null, this)
|
null -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Null, this)
|
||||||
else -> throw UnsupportedOperationException("Unsupported const element type $this")
|
else -> throw UnsupportedOperationException("Unsupported const element type ${this::class}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,17 +129,17 @@ fun IrAnnotationContainer.getAnnotation(annotation: FqName): IrConstructorCall {
|
|||||||
return this.annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation }
|
return this.annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPrimitiveClass(fqName: String): Class<*>? {
|
fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? {
|
||||||
return when (fqName) {
|
return when (fqName) {
|
||||||
"kotlin.Boolean" -> Boolean::class.java
|
"kotlin.Boolean" -> if (asObject) Boolean::class.javaObjectType else Boolean::class.java
|
||||||
"kotlin.Char" -> Char::class.java
|
"kotlin.Char" -> if (asObject) Char::class.javaObjectType else Char::class.java
|
||||||
"kotlin.Byte" -> Byte::class.java
|
"kotlin.Byte" -> if (asObject) Byte::class.javaObjectType else Byte::class.java
|
||||||
"kotlin.Short" -> Short::class.java
|
"kotlin.Short" -> if (asObject) Short::class.javaObjectType else Short::class.java
|
||||||
"kotlin.Int" -> Int::class.java
|
"kotlin.Int" -> if (asObject) Int::class.javaObjectType else Int::class.java
|
||||||
"kotlin.Long" -> Long::class.java
|
"kotlin.Long" -> if (asObject) Long::class.javaObjectType else Long::class.java
|
||||||
"kotlin.String" -> String::class.java
|
"kotlin.String" -> if (asObject) String::class.javaObjectType else String::class.java
|
||||||
"kotlin.Float" -> Float::class.java
|
"kotlin.Float" -> if (asObject) Float::class.javaObjectType else Float::class.java
|
||||||
"kotlin.Double" -> Double::class.java
|
"kotlin.Double" -> if (asObject) Double::class.javaObjectType else Double::class.java
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+97
-19
@@ -5,17 +5,27 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.interpreter.stack
|
package org.jetbrains.kotlin.backend.common.interpreter.stack
|
||||||
|
|
||||||
|
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.unaryFunctions
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.equalTo
|
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
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.IrProperty
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
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.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.name.FqNameUnsafe
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import java.lang.invoke.MethodHandles
|
||||||
|
import java.lang.invoke.MethodType
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
val fields: MutableList<Variable>
|
val fields: MutableList<Variable>
|
||||||
@@ -29,26 +39,20 @@ interface State {
|
|||||||
fun getIrFunction(descriptor: FunctionDescriptor): IrFunction?
|
fun getIrFunction(descriptor: FunctionDescriptor): IrFunction?
|
||||||
}
|
}
|
||||||
|
|
||||||
class Primitive<T>(private var value: T, private val type: IrType?) : State {
|
open class Primitive<T>(var value: T, val type: IrType) : State {
|
||||||
override val fields: MutableList<Variable> = mutableListOf()
|
final override val fields: MutableList<Variable> = mutableListOf()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (type != null) {
|
val properties = type.classOrNull!!.owner.declarations.filterIsInstance<IrProperty>()
|
||||||
val properties = type.classOrNull!!.owner.declarations.filterIsInstance<IrProperty>()
|
for (property in properties) {
|
||||||
for (property in properties) {
|
val propertySignature = CompileTimeFunction(property.name.asString(), listOf(type.getName()))
|
||||||
val propertySignature = CompileTimeFunction(property.name.asString(), listOf(type.getName()))
|
val propertyValue = unaryFunctions[propertySignature]?.invoke(value)
|
||||||
val propertyValue = unaryFunctions[propertySignature]?.invoke(value)
|
?: throw NoSuchMethodException("For given property $propertySignature there is no entry in unary map")
|
||||||
?: throw NoSuchMethodException("For given property $propertySignature there is no entry in unary map")
|
fields.add(Variable(property.descriptor, Primitive(propertyValue, property.backingField!!.type)))
|
||||||
fields.add(Variable(property.descriptor, Primitive(propertyValue, null)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrType?.getName() = this?.classOrNull!!.owner.name.asString()
|
private fun IrType.getName() = this.classOrNull!!.descriptor.defaultType.toString()
|
||||||
|
|
||||||
fun getValue(): T {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setState(newVar: Variable) {
|
override fun setState(newVar: Variable) {
|
||||||
newVar.state as? Primitive<T> ?: throw IllegalArgumentException("Cannot set $newVar in current $this")
|
newVar.state as? Primitive<T> ?: throw IllegalArgumentException("Cannot set $newVar in current $this")
|
||||||
@@ -60,7 +64,6 @@ class Primitive<T>(private var value: T, private val type: IrType?) : State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? {
|
override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? {
|
||||||
if (type == null) return null
|
|
||||||
// must add property's getter to declaration's list because they are not present in ir class for primitives
|
// must add property's getter to declaration's list because they are not present in ir class for primitives
|
||||||
val declarations = type.classOrNull!!.owner.declarations.map { if (it is IrProperty) it.getter else it }
|
val declarations = type.classOrNull!!.owner.declarations.map { if (it is IrProperty) it.getter else it }
|
||||||
return declarations.filterIsInstance<IrFunction>()
|
return declarations.filterIsInstance<IrFunction>()
|
||||||
@@ -69,11 +72,11 @@ class Primitive<T>(private var value: T, private val type: IrType?) : State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Primitive(value=$value, type=${type?.getName()})"
|
return "Primitive(value=$value, type=${type.getName()})"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Complex(private var type: IrClass, override val fields: MutableList<Variable>) : State {
|
open class Complex(private var type: IrClass, override val fields: MutableList<Variable>) : State {
|
||||||
var superType: Complex? = null
|
var superType: Complex? = null
|
||||||
var instance: Complex? = null
|
var instance: Complex? = null
|
||||||
|
|
||||||
@@ -110,3 +113,78 @@ class Complex(private var type: IrClass, override val fields: MutableList<Variab
|
|||||||
return "Complex(obj='${type.fqNameForIrSerialization}', super=$superType, values=$fields)"
|
return "Complex(obj='${type.fqNameForIrSerialization}', super=$superType, values=$fields)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Wrapper(private val type: IrClass, private val wrapperValue: Any) : Complex(type, mutableListOf()) {
|
||||||
|
private val typeFqName = type.fqNameForIrSerialization.toUnsafe()
|
||||||
|
private val receiverClass = getPrimitiveClass(typeFqName.toString(), asObject = true)
|
||||||
|
?: JavaToKotlinClassMap.mapKotlinToJava(typeFqName)?.let { Class.forName(it.asSingleFqName().toString()) }
|
||||||
|
?: Class.forName(typeFqName.toString())
|
||||||
|
|
||||||
|
fun invoke(irFunction: IrFunctionImpl, data: Frame): Code {
|
||||||
|
val methodName = irFunction.name.toString()
|
||||||
|
|
||||||
|
val returnClass = irFunction.returnType.getCorrespondingClass(irFunction.isReturnTypePrimitiveAsObject())
|
||||||
|
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 result = method.invokeWithArguments(argsValues)
|
||||||
|
data.pushReturnValue(result.toState(irFunction.returnType))
|
||||||
|
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrType.getCorrespondingClass(asObject: Boolean): Class<out Any> {
|
||||||
|
val fqName = this.getFqName()
|
||||||
|
return when {
|
||||||
|
this.isPrimitiveType() -> getPrimitiveClass(fqName!!, asObject)
|
||||||
|
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.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
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copy(): State {
|
||||||
|
return Wrapper(type, wrapperValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Wrapper(obj='$typeFqName', value=$wrapperValue)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user