Implement interpreter that can evaluate simple fun
For now working cases are: create simple object using primary constructor, invoke its method, invoke superclass method, load/save fields. Return values from compile time function can be only primitives for now.
This commit is contained in:
+139
-23
@@ -8,26 +8,75 @@ package org.jetbrains.kotlin.backend.common.interpreter
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.binaryFunctions
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions
|
||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||
import org.jetbrains.kotlin.ir.util.statements
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
class IrInterpreter : IrElementVisitor<IrExpression, Nothing?> {
|
||||
class IrInterpreter : IrElementVisitor<State, Frame> {
|
||||
private val unit = Complex(null, emptyList())
|
||||
|
||||
fun interpret(expression: IrExpression): IrExpression {
|
||||
return visitExpression(expression, null)
|
||||
return visitExpression(expression, InterpreterFrame()).toIrExpression()
|
||||
}
|
||||
|
||||
private fun calculateBuiltIns(descriptor: FunctionDescriptor, args: List<IrExpression>): Any {
|
||||
private fun State.toIrExpression(): IrExpression {
|
||||
return when (this) {
|
||||
is Primitive<*> -> this.getIrConst()
|
||||
else -> TODO("not supported")
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrElement?.getState(descriptor: DeclarationDescriptor, data: Frame): State? {
|
||||
val arg = this?.accept(this@IrInterpreter, data) ?: return null
|
||||
return arg.setDescriptor(descriptor)
|
||||
}
|
||||
|
||||
private fun IrMemberAccessExpression.convertValueParameters(data: Frame): MutableList<State> {
|
||||
val state = mutableListOf<State>()
|
||||
for (i in 0 until this.valueArgumentsCount) {
|
||||
this.getValueArgument(i).getState(this.symbol.descriptor.valueParameters[i], data)?.let { state += it }
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
private fun IrFunctionSymbol.caclOverridden(states: List<State>): State {
|
||||
val owner = this.owner as IrFunctionImpl
|
||||
val overridden = owner.overriddenSymbols.first()
|
||||
val newStates = states.first { it.getDescriptor() == this.descriptor.containingDeclaration }.getState().toMutableList()
|
||||
|
||||
return if (overridden.owner.body != null) {
|
||||
val temp = newStates.first { it.getDescriptor() == overridden.descriptor.containingDeclaration }
|
||||
overridden.owner.body!!.accept(this@IrInterpreter, InterpreterFrame(mutableListOf(temp)))
|
||||
} else {
|
||||
overridden.caclOverridden(newStates)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunctionAccessExpression.getBody(): IrBody? {
|
||||
return this.symbol.owner.body
|
||||
}
|
||||
|
||||
private fun calculateBuiltIns(descriptor: FunctionDescriptor, frame: Frame): Any {
|
||||
val methodName = descriptor.name.asString()
|
||||
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
||||
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) }
|
||||
val argsValues = args.map { (it as? IrConst<*>)?.value ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
||||
val argsValues = frame.getAll()
|
||||
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
||||
.map { it.getIrConst().value }
|
||||
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
|
||||
return when (argsType.size) {
|
||||
1 -> {
|
||||
@@ -59,30 +108,97 @@ class IrInterpreter : IrElementVisitor<IrExpression, Nothing?> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement, data: Nothing?): IrExpression {
|
||||
private fun <T> IrConst<T>.toPrimitive(): Primitive<T> {
|
||||
return Primitive(this)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement, data: Frame): State {
|
||||
return when (element) {
|
||||
is IrCall -> visitCall(element, data)
|
||||
else -> TODO("not supported")
|
||||
is IrConstructor -> visitConstructor(element, data)
|
||||
is IrDelegatingConstructorCall -> visitDelegatingConstructorCall(element, data)
|
||||
is IrBody -> visitStatements(element.statements, data)
|
||||
is IrBlock -> visitStatements(element.statements, data)
|
||||
is IrSetField -> visitSetField(element, data)
|
||||
is IrGetField -> visitGetField(element, data)
|
||||
is IrGetValue -> visitGetValue(element, data)
|
||||
else -> TODO("${element.javaClass} not supported")
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: Nothing?): IrExpression {
|
||||
override fun visitCall(expression: IrCall, data: Frame): State {
|
||||
val dispatchReceiver = expression.dispatchReceiver?.accept(this, data)
|
||||
val extensionReceiver = expression.extensionReceiver?.accept(this, data)
|
||||
val receiverValue = dispatchReceiver ?: extensionReceiver
|
||||
val args = mutableListOf<IrExpression>()
|
||||
for (i in 0 until expression.valueArgumentsCount) {
|
||||
expression.getValueArgument(i)?.accept(this, data)?.also { args += it }
|
||||
}
|
||||
val newFrame = InterpreterFrame(expression.convertValueParameters(data))
|
||||
(dispatchReceiver ?: extensionReceiver)?.also { newFrame.addVar(it) }
|
||||
|
||||
if (expression.symbol.owner.body == null) {
|
||||
return calculateBuiltIns(expression.symbol.descriptor, args + listOfNotNull(receiverValue)).toIrConst(expression)
|
||||
return if (expression.getBody() == null) {
|
||||
if (expression.symbol.owner.isFakeOverride) {
|
||||
return expression.symbol.caclOverridden(newFrame.getAll())
|
||||
}
|
||||
calculateBuiltIns(expression.symbol.descriptor, newFrame).toIrConst(expression).toPrimitive()
|
||||
} else {
|
||||
expression.getBody()!!.accept(this, newFrame)
|
||||
}
|
||||
|
||||
return super.visitCall(expression, data)
|
||||
}
|
||||
|
||||
override fun <T> visitConst(expression: IrConst<T>, data: Nothing?): IrExpression {
|
||||
return expression
|
||||
override fun <T> visitConst(expression: IrConst<T>, data: Frame): State {
|
||||
return Primitive(expression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall, data: Frame): State {
|
||||
val newFrame = InterpreterFrame(expression.convertValueParameters(data))
|
||||
val state = expression.getBody()?.accept(this, newFrame) ?: unit
|
||||
return Complex(expression.symbol.descriptor.containingDeclaration, state.getState())
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Frame): State {
|
||||
if (expression.symbol.descriptor.containingDeclaration.classId?.asString() == "kotlin/Any") {
|
||||
return unit
|
||||
}
|
||||
|
||||
val newFrame = InterpreterFrame(expression.convertValueParameters(data))
|
||||
val state = expression.getBody()?.accept(this, newFrame) ?: unit
|
||||
return Complex(expression.symbol.descriptor.containingDeclaration, state.getState())
|
||||
}
|
||||
|
||||
private fun visitStatements(statements: List<IrStatement>, data: Frame): State {
|
||||
val state = mutableListOf<State>()
|
||||
statements.forEach {
|
||||
when (it) {
|
||||
is IrReturn -> return visitReturn(it, data)
|
||||
else -> state += it.accept(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
state.removeIf { it == unit }
|
||||
return when (state.size) {
|
||||
0 -> unit
|
||||
1 -> state.first()
|
||||
else -> Complex(null, state)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn, data: Frame): State {
|
||||
return expression.value.accept(this, data)
|
||||
}
|
||||
|
||||
override fun visitSetField(expression: IrSetField, data: Frame): State {
|
||||
val value = expression.value.accept(this, data)
|
||||
return value.setDescriptor(expression.symbol.owner.descriptor)
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField, data: Frame): State {
|
||||
return data.getVar(expression.symbol.descriptor.containingDeclaration)
|
||||
.getState()
|
||||
.first { it.getDescriptor() == expression.descriptor }
|
||||
.copy()
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue, data: Frame): State {
|
||||
if (expression.symbol.descriptor is ReceiverParameterDescriptor) {
|
||||
return data.getVar(expression.symbol.descriptor.containingDeclaration).copy()
|
||||
}
|
||||
return data.getVar(expression.symbol.descriptor).copy()
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.interpreter.stack
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import java.util.NoSuchElementException
|
||||
|
||||
interface Frame {
|
||||
fun addVar(state: State)
|
||||
fun getVar(descriptor: DeclarationDescriptor): State
|
||||
fun getAll(): List<State>
|
||||
}
|
||||
|
||||
class InterpreterFrame(val pool: MutableList<State> = mutableListOf()) : Frame {
|
||||
override fun addVar(state: State) {
|
||||
pool.add(state)
|
||||
}
|
||||
|
||||
override fun getVar(descriptor: DeclarationDescriptor): State {
|
||||
return pool.firstOrNull { it.getDescriptor() == descriptor }
|
||||
?: throw NoSuchElementException("Frame pool doesn't contains variable with descriptor $descriptor")
|
||||
}
|
||||
|
||||
override fun getAll(): List<State> {
|
||||
return pool
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.interpreter.stack
|
||||
|
||||
interface Stack {
|
||||
fun pushFrame(frame: Frame)
|
||||
fun popFrame(): Frame
|
||||
fun peekFrame(): Frame
|
||||
}
|
||||
|
||||
interface Frame {
|
||||
fun addVar(state: State)
|
||||
fun getVar(name: String): State
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.interpreter.stack
|
||||
|
||||
import java.util.NoSuchElementException
|
||||
|
||||
class StackImpl : Stack {
|
||||
private val stack: MutableList<Frame> = mutableListOf()
|
||||
|
||||
override fun pushFrame(frame: Frame) {
|
||||
stack.add(frame)
|
||||
}
|
||||
|
||||
override fun popFrame(): Frame {
|
||||
if (stack.isEmpty()) {
|
||||
throw IndexOutOfBoundsException("Stack is empty")
|
||||
}
|
||||
return stack.removeAt(stack.size - 1)
|
||||
}
|
||||
|
||||
override fun peekFrame(): Frame {
|
||||
if (stack.isEmpty()) {
|
||||
throw IndexOutOfBoundsException("Stack is empty")
|
||||
}
|
||||
return stack.get(stack.size - 1)
|
||||
}
|
||||
}
|
||||
|
||||
class InterpreterFrame : Frame {
|
||||
val pool: MutableList<State> = mutableListOf()
|
||||
|
||||
override fun addVar(state: State) {
|
||||
pool.add(state)
|
||||
}
|
||||
|
||||
override fun getVar(name: String): State {
|
||||
return pool.firstOrNull { it.getName() == name }
|
||||
?: throw NoSuchElementException("Frame pool doesn't contains variable with name $name")
|
||||
}
|
||||
}
|
||||
+46
-7
@@ -5,28 +5,67 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.interpreter.stack
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
|
||||
interface State {
|
||||
fun getState(): List<State>
|
||||
fun getName(): String
|
||||
fun getDescriptor(): DeclarationDescriptor?
|
||||
fun setDescriptor(descriptor: DeclarationDescriptor): State
|
||||
fun copy(): State
|
||||
}
|
||||
|
||||
class Primitive<T>(public val varName: String, public val value: IrConst<T>) : State {
|
||||
class Primitive<T>(private val value: IrConst<T>) : State {
|
||||
private lateinit var declarationDescriptor: DeclarationDescriptor
|
||||
|
||||
private constructor(descriptor: DeclarationDescriptor, value: IrConst<T>) : this(value) {
|
||||
declarationDescriptor = descriptor
|
||||
}
|
||||
|
||||
override fun getState(): List<State> {
|
||||
return listOf(this)
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return varName
|
||||
override fun getDescriptor(): DeclarationDescriptor? {
|
||||
return declarationDescriptor
|
||||
}
|
||||
|
||||
override fun setDescriptor(descriptor: DeclarationDescriptor): State {
|
||||
declarationDescriptor = descriptor
|
||||
return this
|
||||
}
|
||||
|
||||
override fun copy(): State {
|
||||
return Primitive(declarationDescriptor, value)
|
||||
}
|
||||
|
||||
public fun getIrConst(): IrConst<T> {
|
||||
return value
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Primitive(varName='${declarationDescriptor.name}', value=${value.value})"
|
||||
}
|
||||
}
|
||||
class Complex(public val objName: String, public val values: List<State>) : State {
|
||||
class Complex(private var declarationDescriptor: DeclarationDescriptor?, private val values: List<State>) : State {
|
||||
override fun getState(): List<State> {
|
||||
return values
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return objName
|
||||
override fun getDescriptor(): DeclarationDescriptor? {
|
||||
return declarationDescriptor
|
||||
}
|
||||
|
||||
override fun setDescriptor(descriptor: DeclarationDescriptor): State {
|
||||
declarationDescriptor = descriptor
|
||||
return this
|
||||
}
|
||||
|
||||
override fun copy(): State {
|
||||
return Complex(declarationDescriptor, values)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Complex(objName='${declarationDescriptor?.name}', values=$values)"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user