Unify logic of creation new ir tree nodes in interpreter

This commit is contained in:
Ivan Kylchik
2021-06-21 23:44:29 +03:00
committed by TeamCityServer
parent 6ce2f8eb14
commit 4ad88679fd
8 changed files with 286 additions and 259 deletions
@@ -7,11 +7,8 @@ package org.jetbrains.kotlin.ir.interpreter
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretBinaryFunction
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretTernaryFunction
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretUnaryFunction
@@ -24,7 +21,6 @@ import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isArray
@@ -55,9 +51,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
private val bodyMap: Map<IdSignature, IrBody> = interpreter.bodyMap
override fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, expectedResultClass: Class<*>): Any? {
val irCall = IrCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.returnType, irFunction.symbol as IrSimpleFunctionSymbol
)
val irCall = irFunction.createCall()
return interpreter.withNewCallStack(irCall) {
this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall))
valueArguments.forEach { this@withNewCallStack.environment.callStack.pushState(it.state) }
@@ -186,7 +180,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
private fun calculateRangeTo(type: IrType, args: List<State>) {
val constructor = type.classOrNull!!.owner.constructors.first()
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
val constructorCall = constructor.createConstructorCall()
val constructorValueParameters = constructor.valueParameters.map { it.symbol }
val primitiveValueParameters = args.map { it as Primitive<*> }
@@ -6,30 +6,19 @@
package org.jetbrains.kotlin.ir.interpreter
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isSubtypeOf
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.Name
internal fun IrExpression.handleAndDropResult(callStack: CallStack, dropOnlyUnit: Boolean = false) {
@@ -118,132 +107,54 @@ private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack)
}
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) {
val irFunction = expression.symbol.owner
val hasDefaults = (0 until expression.valueArgumentsCount).any { expression.getValueArgument(it) == null }
if (hasDefaults) {
val visibility = if (expression is IrEnumConstructorCall || expression is IrDelegatingConstructorCall) DescriptorVisibilities.LOCAL else irFunction.visibility
val defaultFun = IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER,
IrSimpleFunctionSymbolImpl(), Name.identifier(irFunction.name.asString() + "\$default"),
visibility, Modality.FINAL, irFunction.returnType,
isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isOperator = true, isInfix = false, isExpect = false
)
defaultFun.parent = irFunction.parent
expression.dispatchReceiver?.let {
defaultFun.dispatchReceiverParameter = irFunction.dispatchReceiverParameter!!//.deepCopyWithSymbols(defaultFun)
}
expression.extensionReceiver?.let {
defaultFun.extensionReceiverParameter = irFunction.extensionReceiverParameter!!//.deepCopyWithSymbols(defaultFun)
}
val parameters = mutableListOf<IrValueDeclaration>()
(0 until expression.valueArgumentsCount).forEach {
if (expression.getValueArgument(it) != null) {
val param = irFunction.valueParameters[it]//.deepCopyWithSymbols(defaultFun)
defaultFun.valueParameters += param
parameters += param
}
// if some arguments are not defined, then it is necessary to create temp function where defaults will be evaluated
val actualParameters = MutableList<IrValueDeclaration?>(expression.valueArgumentsCount) { null }
val ownerWithDefaults = expression.getFunctionThatContainsDefaults()
val visibility = when (expression) {
is IrEnumConstructorCall, is IrDelegatingConstructorCall -> DescriptorVisibilities.LOCAL
else -> ownerWithDefaults.visibility
}
val callToDefault = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, defaultFun.returnType, defaultFun.symbol)
expression.dispatchReceiver?.let {
callToDefault.dispatchReceiver = it
}
expression.extensionReceiver?.let {
callToDefault.extensionReceiver = it
}
var index = 0
(0 until expression.valueArgumentsCount).forEach {
if (expression.getValueArgument(it) != null) {
callToDefault.putValueArgument(index++, expression.getValueArgument(it))
}
}
fun getDefaultForParameterAt(index: Int): IrExpression? {
fun IrExpressionBody.replaceGetValueFromOtherClass(owner: IrFunction): IrExpressionBody {
if (this.expression is IrConst<*>) return this
return this.deepCopyWithSymbols(owner).transform(
object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val parameter = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression)
if (parameter.parent != owner) return super.visitGetValue(expression)
val newParameter = when (val indexInParameters = parameter.index) {
-1 -> (irFunction.dispatchReceiverParameter ?: irFunction.extensionReceiverParameter)!!
else -> parameters[indexInParameters]//parameters[indexInParameters]
}
return IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, newParameter.symbol)
}
}, null
)//.deepCopyWithSymbols(defaultFun) TODO ???
}
fun IrValueParameter.getDefault(): IrExpressionBody? {
if (defaultValue != null) return defaultValue?.replaceGetValueFromOtherClass(this.parent as IrFunction)
return (this.parent as? IrSimpleFunction)?.overriddenSymbols
?.map { it.owner.valueParameters[this.index] }
?.firstOrNull { it.getDefault() != null }?.let { it.getDefault()?.replaceGetValueFromOtherClass(it.parent as IrFunction) }
}
return irFunction.valueParameters[index].getDefault()?.expression
}
val newExpression = when (expression) {
is IrCall -> IrCallImpl.fromSymbolOwner(expression.startOffset, expression.endOffset, expression.type, expression.symbol)
is IrConstructorCall -> IrConstructorCallImpl.fromSymbolOwner(expression.type, expression.symbol)
is IrDelegatingConstructorCall -> IrDelegatingConstructorCallImpl(0, 0, expression.type, expression.symbol, expression.typeArgumentsCount, expression.valueArgumentsCount)
is IrEnumConstructorCall -> IrEnumConstructorCallImpl(0, 0, expression.type, expression.symbol, expression.typeArgumentsCount, expression.valueArgumentsCount)
else -> TODO()
}
expression.dispatchReceiver?.let {
newExpression.dispatchReceiver = IrGetValueImpl(0, 0, defaultFun.dispatchReceiverParameter!!.type, defaultFun.dispatchReceiverParameter!!.symbol)
}
expression.extensionReceiver?.let {
newExpression.extensionReceiver = IrGetValueImpl(0, 0, defaultFun.extensionReceiverParameter!!.type, defaultFun.extensionReceiverParameter!!.symbol)
}
val variablesForDefault = mutableListOf<IrVariable>()
index = 0
(0 until expression.valueArgumentsCount).forEach {
val arg = if (expression.getValueArgument(it) != null) {
IrGetValueImpl(0, 0, defaultFun.valueParameters[index].type, defaultFun.valueParameters[index++].symbol)
} else {
val init = getDefaultForParameterAt(it)
?: expression.getVarargType(it)?.let { // case when value parameter is vararg and it is missing
IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it)
val defaultFun = createTempFunction(
Name.identifier(ownerWithDefaults.name.asString() + "\$default"), ownerWithDefaults.returnType,
origin = IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, visibility
).apply {
this.parent = ownerWithDefaults.parent
this.dispatchReceiverParameter = ownerWithDefaults.dispatchReceiverParameter?.deepCopyWithSymbols(this)
this.extensionReceiverParameter = ownerWithDefaults.extensionReceiverParameter?.deepCopyWithSymbols(this)
(0 until expression.valueArgumentsCount).forEach { index ->
val parameter = ownerWithDefaults.valueParameters[index]
actualParameters[index] = if (expression.getValueArgument(index) != null) {
parameter.deepCopyWithSymbols(this).also { this.valueParameters += it }
} else {
parameter.createTempVariable().apply variable@{
this@variable.initializer = parameter.getDefaultWithActualParameters(this@apply, actualParameters)
?: expression.getVarargType(index)?.let { null.toIrConst(it) } // if parameter is vararg and it is missing
}
val variable = IrVariableImpl(
0, 0, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, IrVariableSymbolImpl(),
irFunction.valueParameters[it].name, irFunction.valueParameters[it].type, isVar = false, isConst = false, isLateinit = false
)
variablesForDefault += variable
parameters += variable
variable.initializer = init
IrGetValueImpl(0, 0, variable.type, variable.symbol)
}
}
newExpression.putValueArgument(it, arg)
}
(0 until expression.typeArgumentsCount).forEach {
newExpression.putTypeArgument(it, expression.getTypeArgument(it))
}
val callWithAllArgs = expression.shallowCopy() // just a copy of given call, but with all arguments in place
expression.dispatchReceiver?.let { callWithAllArgs.dispatchReceiver = defaultFun.dispatchReceiverParameter!!.createGetValue() }
expression.extensionReceiver?.let { callWithAllArgs.extensionReceiver = defaultFun.extensionReceiverParameter!!.createGetValue() }
(0 until expression.valueArgumentsCount).forEach { callWithAllArgs.putValueArgument(it, actualParameters[it]?.createGetValue()) }
defaultFun.body = (actualParameters.filterIsInstance<IrVariable>() + defaultFun.createReturn(callWithAllArgs)).wrapWithBlockBody()
defaultFun.body = IrBlockBodyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
variablesForDefault + IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, defaultFun.returnType, defaultFun.symbol, newExpression)
)
val callToDefault = defaultFun.createCall().apply { expression.copyArgsInto(this) }
callStack.addInstruction(CompoundInstruction(callToDefault))
} else {
val irFunction = expression.symbol.owner
callStack.addInstruction(SimpleInstruction(expression))
fun IrValueParameter.schedule(arg: IrExpression?) {
callStack.addInstruction(SimpleInstruction(this))
callStack.addInstruction(CompoundInstruction(arg))
}
(expression.valueArgumentsCount - 1 downTo 0).forEach {
irFunction.valueParameters[it].schedule(expression.getValueArgument(it))
}
(expression.valueArgumentsCount - 1 downTo 0).forEach { irFunction.valueParameters[it].schedule(expression.getValueArgument(it)) }
expression.extensionReceiver?.let { irFunction.extensionReceiverParameter!!.schedule(it) }
expression.dispatchReceiver?.let { irFunction.dispatchReceiverParameter!!.schedule(it) }
}
@@ -311,7 +222,7 @@ private fun unfoldGetValue(expression: IrGetValue, environment: IrInterpreterEnv
// used to evaluate constants inside object
if (expectedClass != null && expectedClass.isObject && expression.symbol.owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER) {
// TODO is this correct behaviour?
val irGetObject = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, expectedClass.defaultType, expectedClass.symbol)
val irGetObject = expectedClass.createGetObject()
return unfoldGetObjectValue(irGetObject, environment)
}
environment.callStack.pushState(environment.callStack.getState(expression.symbol))
@@ -0,0 +1,174 @@
/*
* Copyright 2010-2021 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.ir.interpreter
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.interpreter.state.Complex
import org.jetbrains.kotlin.ir.interpreter.state.ExceptionState
import org.jetbrains.kotlin.ir.interpreter.state.Primitive
import org.jetbrains.kotlin.ir.interpreter.state.State
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.name.Name
internal val TEMP_CLASS_FOR_INTERPRETER = object : IrDeclarationOriginImpl("TEMP_CLASS_FOR_INTERPRETER") {}
internal val TEMP_FUNCTION_FOR_INTERPRETER = object : IrDeclarationOriginImpl("TEMP_FUNCTION_FOR_INTERPRETER") {}
fun Any?.toIrConstOrNull(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*>? {
if (this == null) return IrConstImpl.constNull(startOffset, endOffset, irType)
val constType = irType.makeNotNull()
return when (irType.getPrimitiveType()) {
PrimitiveType.BOOLEAN -> IrConstImpl.boolean(startOffset, endOffset, constType, this as Boolean)
PrimitiveType.CHAR -> IrConstImpl.char(startOffset, endOffset, constType, this as Char)
PrimitiveType.BYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte())
PrimitiveType.SHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort())
PrimitiveType.INT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt())
PrimitiveType.FLOAT -> IrConstImpl.float(startOffset, endOffset, constType, (this as Number).toFloat())
PrimitiveType.LONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong())
PrimitiveType.DOUBLE -> IrConstImpl.double(startOffset, endOffset, constType, (this as Number).toDouble())
null -> when (constType.getUnsignedType()) {
UnsignedType.UBYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte())
UnsignedType.USHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort())
UnsignedType.UINT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt())
UnsignedType.ULONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong())
null -> when {
constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String)
else -> null
}
}
}
}
fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> =
toIrConstOrNull(irType, startOffset, endOffset)
?: throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}")
fun Any?.toIrConst(
irType: IrType, irBuiltIns: IrBuiltIns,
startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET
): IrConst<*> =
toIrConstOrNull(irType, startOffset, endOffset) ?: run {
if (irType == irBuiltIns.stringType) IrConstImpl.string(startOffset, endOffset, irType.makeNotNull(), this as String)
else throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}")
}
internal fun State.toIrExpression(expression: IrExpression): IrExpression {
val start = expression.startOffset
val end = expression.endOffset
val type = expression.type.makeNotNull()
return when (this) {
is Primitive<*> ->
when {
this.value == null -> this.value.toIrConst(type, start, end)
type.isPrimitiveType() || type.isString() -> this.value.toIrConst(type, start, end)
else -> expression // TODO support for arrays
}
is ExceptionState -> {
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + this.getFullDescription())
}
is Complex -> {
val stateType = this.irClass.defaultType
when {
stateType.isUnsignedType() -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end)
else -> expression
}
}
else -> expression // TODO support
}
}
internal fun IrFunction.createCall(): IrCall {
this as IrSimpleFunction
return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, returnType, symbol, typeParameters.size, valueParameters.size)
}
internal fun IrConstructor.createConstructorCall(): IrConstructorCall {
return IrConstructorCallImpl.fromSymbolOwner(returnType, symbol)
}
internal fun IrValueDeclaration.createGetValue(): IrGetValue {
return IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.type, this.symbol)
}
internal fun IrValueDeclaration.createTempVariable(): IrVariable {
return IrVariableImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, IrVariableSymbolImpl(),
this.name, this.type, isVar = false, isConst = false, isLateinit = false
)
}
internal fun IrClass.createGetObject(): IrGetObjectValue {
return IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.defaultType, this.symbol)
}
internal fun IrFunction.createReturn(value: IrExpression): IrReturn {
return IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.returnType, this.symbol, value)
}
internal fun createTempFunction(
name: Name,
type: IrType,
origin: IrDeclarationOrigin = TEMP_FUNCTION_FOR_INTERPRETER,
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC
): IrSimpleFunction {
return IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, IrSimpleFunctionSymbolImpl(), name, visibility, Modality.FINAL, type,
isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isOperator = true, isInfix = false, isExpect = false
)
}
internal fun createTempClass(name: Name, origin: IrDeclarationOrigin = TEMP_CLASS_FOR_INTERPRETER): IrClass {
return IrFactoryImpl.createClass(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, IrClassSymbolImpl(), name,
ClassKind.CLASS, DescriptorVisibilities.PRIVATE, Modality.FINAL
)
}
internal fun List<IrStatement>.wrapWithBlockBody(): IrBlockBody {
return IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this)
}
internal fun IrFunctionAccessExpression.shallowCopy(copyTypeArguments: Boolean = true): IrFunctionAccessExpression {
return when (this) {
is IrCall -> IrCallImpl.fromSymbolOwner(startOffset, endOffset, type, symbol)
is IrConstructorCall -> IrConstructorCallImpl.fromSymbolOwner(type, symbol)
is IrDelegatingConstructorCall -> IrDelegatingConstructorCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol)
is IrEnumConstructorCall ->
IrEnumConstructorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, typeArgumentsCount, valueArgumentsCount)
else -> TODO("Expression $this cannot be copied")
}.apply {
if (copyTypeArguments) {
(0 until this@shallowCopy.typeArgumentsCount).forEach { this.putTypeArgument(it, this@shallowCopy.getTypeArgument(it)) }
}
}
}
internal fun IrFunctionAccessExpression.copyArgsInto(newCall: IrFunctionAccessExpression) {
newCall.dispatchReceiver = this.dispatchReceiver
newCall.extensionReceiver = this.extensionReceiver
(0 until this.valueArgumentsCount)
.mapNotNull { this.getValueArgument(it) }
.forEachIndexed { i, arg -> newCall.putValueArgument(i, arg) }
}
@@ -7,23 +7,23 @@ package org.jetbrains.kotlin.ir.interpreter
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.interpreter.state.Primitive
import org.jetbrains.kotlin.ir.interpreter.state.State
import org.jetbrains.kotlin.ir.interpreter.state.Wrapper
import org.jetbrains.kotlin.ir.interpreter.state.isSubtypeOf
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
@@ -42,31 +42,6 @@ internal fun IrFunction.getReceiver(): IrSymbol? = this.getDispatchReceiver() ?:
internal fun IrFunctionAccessExpression.getThisReceiver(): IrValueSymbol = this.symbol.owner.parentAsClass.thisReceiver!!.symbol
internal fun State.toIrExpression(expression: IrExpression): IrExpression {
val start = expression.startOffset
val end = expression.endOffset
val type = expression.type.makeNotNull()
return when (this) {
is Primitive<*> ->
when {
this.value == null -> this.value.toIrConst(type, start, end)
type.isPrimitiveType() || type.isString() -> this.value.toIrConst(type, start, end)
else -> expression // TODO support for arrays
}
is ExceptionState -> {
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + this.getFullDescription())
}
is Complex -> {
val stateType = this.irClass.defaultType
when {
stateType.isUnsignedType() -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end)
else -> expression
}
}
else -> expression // TODO support
}
}
/**
* Convert object from outer world to state
*/
@@ -81,45 +56,6 @@ internal fun Any?.toState(irType: IrType): State {
}
}
fun Any?.toIrConstOrNull(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*>? {
if (this == null) return IrConstImpl.constNull(startOffset, endOffset, irType)
val constType = irType.makeNotNull()
return when (irType.getPrimitiveType()) {
PrimitiveType.BOOLEAN -> IrConstImpl.boolean(startOffset, endOffset, constType, this as Boolean)
PrimitiveType.CHAR -> IrConstImpl.char(startOffset, endOffset, constType, this as Char)
PrimitiveType.BYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte())
PrimitiveType.SHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort())
PrimitiveType.INT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt())
PrimitiveType.FLOAT -> IrConstImpl.float(startOffset, endOffset, constType, (this as Number).toFloat())
PrimitiveType.LONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong())
PrimitiveType.DOUBLE -> IrConstImpl.double(startOffset, endOffset, constType, (this as Number).toDouble())
null -> when (constType.getUnsignedType()) {
UnsignedType.UBYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte())
UnsignedType.USHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort())
UnsignedType.UINT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt())
UnsignedType.ULONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong())
null -> when {
constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String)
else -> null
}
}
}
}
fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> =
toIrConstOrNull(irType, startOffset, endOffset)
?: throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}")
fun Any?.toIrConst(
irType: IrType, irBuiltIns: IrBuiltIns,
startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET
): IrConst<*> =
toIrConstOrNull(irType, startOffset, endOffset) ?: run {
if (irType == irBuiltIns.stringType) IrConstImpl.string(startOffset, endOffset, irType.makeNotNull(), this as String)
else throw UnsupportedOperationException("Unsupported const element type ${irType.makeNotNull().render()}")
}
@Suppress("UNCHECKED_CAST")
internal fun <T> IrConst<T>.toPrimitive(): Primitive<T> = when {
type.isByte() -> Primitive((value as Number).toByte() as T, type)
@@ -276,3 +212,38 @@ internal fun IrType.getOnlyName(): String {
internal fun IrFieldAccessExpression.accessesTopLevelOrObjectField(): Boolean {
return this.receiver == null || (this.receiver?.type?.classifierOrNull?.owner as? IrClass)?.isObject == true
}
internal fun IrFunctionAccessExpression.getFunctionThatContainsDefaults(): IrFunction {
val irFunction = this.symbol.owner
fun IrValueParameter.lookup(): IrFunction? {
return defaultValue?.let { this.parent as IrFunction }
?: (this.parent as? IrSimpleFunction)?.overriddenSymbols
?.map { it.owner.valueParameters[this.index] }
?.firstNotNullOfOrNull { it.lookup() }
}
return (0 until this.valueArgumentsCount)
.first { this.getValueArgument(it) == null }
.let { irFunction.valueParameters[it].lookup() ?: irFunction }
}
internal fun IrValueParameter.getDefaultWithActualParameters(
newParent: IrFunction, actualParameters: List<IrValueDeclaration?>
): IrExpression? {
val expression = this.defaultValue?.expression
if (expression is IrConst<*>) return expression
val parameterOwner = this.parent as IrFunction
val transformer = object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val parameter = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression)
if (parameter.parent != parameterOwner) return super.visitGetValue(expression)
val newParameter = when (parameter.index) {
-1 -> newParent.dispatchReceiverParameter ?: newParent.extensionReceiverParameter
else -> actualParameters[parameter.index]
}
return IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, newParameter!!.symbol)
}
}
return expression?.deepCopyWithSymbols(newParent)?.transform(transformer, null)
}
@@ -5,12 +5,11 @@
package org.jetbrains.kotlin.ir.interpreter.intrinsics
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.createCall
import org.jetbrains.kotlin.ir.interpreter.createGetValue
import org.jetbrains.kotlin.ir.interpreter.toIrConst
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.exceptions.stop
import org.jetbrains.kotlin.ir.interpreter.state.*
@@ -235,10 +234,9 @@ internal object ArrayConstructor : IntrinsicBase() {
callStack.setState(initSymbol, state)
for (i in size - 1 downTo 0) {
val invoke = state.invokeSymbol.owner as IrSimpleFunction
val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, invoke.returnType, invoke.symbol)
call.dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, initSymbol)
call.putValueArgument(0, IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, environment.irBuiltIns.intType, i))
val call = (state.invokeSymbol.owner as IrSimpleFunction).createCall()
call.dispatchReceiver = initSymbol.owner.createGetValue()
call.putValueArgument(0, i.toIrConst(environment.irBuiltIns.intType))
instructions += CompoundInstruction(call)
}
@@ -292,10 +290,10 @@ internal object AssertIntrinsic : IntrinsicBase() {
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment))
val messageLambda = environment.callStack.getState(irFunction.valueParameters.last().symbol) as KFunctionState
val function = messageLambda.irFunction as IrSimpleFunction
environment.callStack.loadUpValues(messageLambda)
val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.returnType, function.symbol)
val lambdaParameter = irFunction.valueParameters.last()
val lambdaState = environment.callStack.getState(lambdaParameter.symbol) as KFunctionState
val call = (lambdaState.invokeSymbol.owner as IrSimpleFunction).createCall()
call.dispatchReceiver = lambdaParameter.createGetValue()
return listOf(customEvaluateInstruction(irFunction, environment), CompoundInstruction(call))
}
@@ -5,13 +5,12 @@
package org.jetbrains.kotlin.ir.interpreter.state
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.interpreter.createCall
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
@@ -69,8 +68,7 @@ internal class Common private constructor(override val irClass: IrClass, overrid
}
fun createToStringIrCall(): IrCall {
val toStringFun = getToStringFunction()
return IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, toStringFun.returnType, toStringFun.symbol)
return getToStringFunction().createCall()
}
override fun toString(): String {
@@ -5,29 +5,25 @@
package org.jetbrains.kotlin.ir.interpreter.state.reflection
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.expressions.putArgument
import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.TEMP_FUNCTION_FOR_INTERPRETER
import org.jetbrains.kotlin.ir.interpreter.createTempClass
import org.jetbrains.kotlin.ir.interpreter.createTempFunction
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KParameterProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeParameterProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.defaultType
@@ -51,20 +47,11 @@ internal class KFunctionState(
init {
val invokeFunction = irClass.declarations.filterIsInstance<IrSimpleFunction>().single { it.name == OperatorNameConventions.INVOKE }
// TODO do we need new class here? if yes, do we need different names for temp classes?
functionClass = IrFactoryImpl.createClass(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
object : IrDeclarationOriginImpl("TEMP_CLASS_FOR_INTERPRETER") {}, IrClassSymbolImpl(),
Name.identifier("Function\$0"), ClassKind.CLASS, DescriptorVisibilities.PRIVATE, Modality.FINAL
).apply {
parent = irFunction.parent
}
functionClass = createTempClass(Name.identifier("Function\$0")).apply { parent = irFunction.parent }
functionClass.superTypes += irClass.defaultType
functionClass.declarations += IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
object : IrDeclarationOriginImpl("TEMP_FUNCTION_FOR_INTERPRETER") {}, IrSimpleFunctionSymbolImpl(),
OperatorNameConventions.INVOKE, DescriptorVisibilities.PUBLIC, Modality.FINAL, irFunction.returnType,
isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isOperator = true, isInfix = false, isExpect = false
functionClass.declarations += createTempFunction(
OperatorNameConventions.INVOKE, irFunction.returnType, TEMP_FUNCTION_FOR_INTERPRETER
).apply impl@{
parent = functionClass
overriddenSymbols = listOf(invokeFunction.symbol)
@@ -72,36 +59,29 @@ internal class KFunctionState(
dispatchReceiverParameter = invokeFunction.dispatchReceiverParameter?.deepCopyWithSymbols(initialParent = this)
valueParameters = mutableListOf()
val call = when (val symbol = irFunction.symbol) {
is IrSimpleFunctionSymbol -> IrCallImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
irFunction.returnType, symbol, irFunction.typeParameters.size, irFunction.valueParameters.size
)
is IrConstructorSymbol -> IrConstructorCallImpl.fromSymbolOwner(irFunction.returnType, symbol)
val call = when (irFunction) {
is IrSimpleFunction -> irFunction.createCall()
is IrConstructor -> irFunction.createConstructorCall()
else -> TODO("Unsupported symbol $symbol for invoke")
}.apply {
val dispatchParameter = irFunction.dispatchReceiverParameter
val extensionParameter = irFunction.extensionReceiverParameter
if (dispatchParameter != null) {
dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchParameter.type, dispatchParameter.symbol)
if (getField(dispatchParameter.symbol) == null) (this@impl.valueParameters as MutableList).add(dispatchParameter)
dispatchReceiver = dispatchParameter.createGetValue()
if (getField(dispatchParameter.symbol) == null) (this@impl.valueParameters as MutableList) += dispatchParameter
}
if (extensionParameter != null) {
extensionReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionParameter.type, extensionParameter.symbol)
if (getField(extensionParameter.symbol) == null) (this@impl.valueParameters as MutableList).add(extensionParameter)
extensionReceiver = extensionParameter.createGetValue()
if (getField(extensionParameter.symbol) == null) (this@impl.valueParameters as MutableList) += extensionParameter
}
irFunction.valueParameters.forEach {
putArgument(it, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, it.symbol))
(this@impl.valueParameters as MutableList).add(it)
putArgument(it, it.createGetValue())
(this@impl.valueParameters as MutableList) += it
}
}
body = IrBlockBodyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
listOf(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this.returnType, this.symbol, call))
)
body = listOf(this.createReturn(call)).wrapWithBlockBody()
invokeSymbol = this.symbol
}
}
+4 -3
View File
@@ -2,7 +2,7 @@
fun sum(a: Int = 1, b: Int = 2, c: Int = 3) = a + b + c
@CompileTimeCalculation
fun sumBasedOnPrevious(a: Int = 1, b: Int = a * 2, c: Int = b * 2) = a + b + c
fun sumBasedOnPrevious(a: Int = 1, b: Int = a * 2, c: Int = b * 2, d: Int = b * 2) = a + b + c + d
@CompileTimeCalculation
interface A {
@@ -16,8 +16,9 @@ const val sum1 = <!EVALUATED: `6`!>sum()<!>
const val sum2 = <!EVALUATED: `1`!>sum(b = -3)<!>
const val sum3 = <!EVALUATED: `3`!>sum(c = 1, a = 1, b = 1)<!>
const val sumBasedOnPrevious1 = <!EVALUATED: `7`!>sumBasedOnPrevious()<!>
const val sumBasedOnPrevious2 = <!EVALUATED: `3`!>sumBasedOnPrevious(b = 1, c = 1)<!>
const val sumBasedOnPrevious1 = <!EVALUATED: `11`!>sumBasedOnPrevious()<!>
const val sumBasedOnPrevious2 = <!EVALUATED: `5`!>sumBasedOnPrevious(b = 1, c = 1)<!>
const val sumBasedOnPrevious3 = <!EVALUATED: `8`!>sumBasedOnPrevious(a = 1, c = 1)<!>
const val sumInInterfaceDefault1 = B().<!EVALUATED: `42`!>foo(1)<!>
const val sumInInterfaceDefault2 = B().<!EVALUATED: `4`!>foo(x = 1, y = 2)<!>