Support Enum class as intrinsic in ir interpreter

Methods of Enum class don't have bodies, so must be treated as
intrinsics
This commit is contained in:
Ivan Kylchik
2021-05-19 13:58:51 +03:00
committed by TeamCityServer
parent e5617ede7e
commit 0cc866a2fb
8 changed files with 145 additions and 135 deletions
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.name.FqName
@@ -183,7 +182,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
}
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
this ?: return handleIntrinsicMethods(irFunction)
this ?: return assert(handleIntrinsicMethods(irFunction)) { "Unsupported intrinsic function: ${irFunction.render()}" }
val argsForMethodInvocation = irFunction.getArgsForMethodInvocation(this@DefaultCallInterceptor, this.type(), args)
withExceptionHandler(environment) {
val result = this.invokeWithArguments(argsForMethodInvocation) // TODO if null return Unit
@@ -191,8 +190,10 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
}
}
private fun handleIntrinsicMethods(irFunction: IrFunction) {
IntrinsicEvaluator.unwindInstructions(irFunction, environment).forEach { callStack.addInstruction(it) }
private fun handleIntrinsicMethods(irFunction: IrFunction): Boolean {
val instructions = IntrinsicEvaluator.unwindInstructions(irFunction, environment) ?: return false
instructions.forEach { callStack.addInstruction(it) }
return true
}
private fun calculateBuiltIns(irFunction: IrFunction, args: List<State>) {
@@ -201,18 +202,10 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
else -> property.owner.name.asString()
}
val receiverType = irFunction.dispatchReceiverParameter?.type
val receiverType = irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type
val argsType = listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }
val argsValues = args.wrap(this, irFunction)
fun IrType.getOnlyName(): String {
return when {
this.originalKotlinType != null -> this.originalKotlinType.toString()
this is IrSimpleType -> (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
else -> this.render()
}
}
// TODO replace unary, binary, ternary functions with vararg
withExceptionHandler(environment) {
val result = when (argsType.size) {
@@ -227,7 +220,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(),
argsValues[0], argsValues[1], argsValues[2]
)
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin functions")
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin function: $methodName")
}
// TODO check "result is Unit"
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.ir.IrStatement
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.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
@@ -26,7 +25,7 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn
when (element) {
null -> return
is IrSimpleFunction -> unfoldFunction(element, environment)
is IrConstructor -> unfoldConstructor(element, callStack)
is IrConstructor -> unfoldConstructor(element, environment)
is IrCall -> unfoldCall(element, callStack)
is IrConstructorCall -> unfoldConstructorCall(element, callStack)
is IrEnumConstructorCall -> unfoldEnumConstructorCall(element, callStack)
@@ -76,10 +75,23 @@ private fun unfoldFunction(function: IrSimpleFunction, environment: IrInterprete
?: throw InterpreterError("Ir function must be with body")
}
private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack) {
// SimpleInstruction with function is added in constructor call
// It will serve as endpoint for all possible constructor calls, there we drop frame and return object
callStack.addInstruction(CompoundInstruction(constructor.body!!))
private fun unfoldConstructor(constructor: IrConstructor, environment: IrInterpreterEnvironment) {
val callStack = environment.callStack
when (constructor.fqNameWhenAvailable?.asString()) {
"kotlin.Enum.<init>" -> {
val irClass = constructor.parentAsClass
val receiver = irClass.thisReceiver!!.symbol
val receiverState = callStack.getState(receiver)
irClass.declarations.filterIsInstance<IrProperty>().forEachIndexed { index, property ->
receiverState.setField(Variable(property.symbol, callStack.getState(constructor.valueParameters[index].symbol)))
}
}
else -> {
// SimpleInstruction with function is added in constructor call
// It will serve as endpoint for all possible constructor calls, there we drop frame and return object
callStack.addInstruction(CompoundInstruction(constructor.body!!))
}
}
}
private fun unfoldCall(call: IrCall, callStack: CallStack) {
@@ -341,14 +353,10 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
}
return callStack.pushState(result.toState(environment.irBuiltIns.stringType))
}
val toStringFun = state.getToStringFunction()
val receiver = toStringFun.dispatchReceiverParameter!!
val toStringCall =
IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, environment.irBuiltIns.stringType, toStringFun.symbol)
val toStringCall = state.createToStringIrCall()
callStack.newSubFrame(toStringCall)
callStack.addInstruction(SimpleInstruction(toStringCall))
callStack.addVariable(Variable(receiver.symbol, state))
callStack.addVariable(Variable(toStringCall.symbol.owner.dispatchReceiverParameter!!.symbol, state))
}
}
}
@@ -360,10 +368,8 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
when (element.origin) {
IrStatementOrigin.DESTRUCTURING_DECLARATION -> element.statements.reversed()
.forEach { callStack.addInstruction(CompoundInstruction(it)) }
null -> element.statements.reversed()
.forEach { callStack.addInstruction(CompoundInstruction(it)) } // is null for body of do while loop
IrStatementOrigin.DESTRUCTURING_DECLARATION, IrStatementOrigin.DO_WHILE_LOOP ->
element.statements.reversed().forEach { callStack.addInstruction(CompoundInstruction(it)) }
else -> TODO("${element.origin} not implemented")
}
}
@@ -211,9 +211,6 @@ internal fun IrClass.internalName(): String {
internal inline fun withExceptionHandler(environment: IrInterpreterEnvironment, block: () -> Unit) {
try {
block()
// check if during proxy interpretation was an exception
val possibleException = environment.callStack.peekState() as? ExceptionState
if (possibleException != null) environment.callStack.dropFramesUntilTryCatch()
} catch (e: Throwable) {
e.handleUserException(environment)
}
@@ -265,3 +262,8 @@ internal fun IrFunction.getArgsForMethodInvocation(
return argsValues
}
internal fun IrType.getOnlyName(): String {
if (this !is IrSimpleType) return this.render()
return (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
}
@@ -8,22 +8,23 @@ package org.jetbrains.kotlin.ir.interpreter.intrinsics
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.interpreter.Instruction
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterMethodNotFoundError
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
internal object IntrinsicEvaluator {
fun unwindInstructions(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
fun unwindInstructions(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction>? {
val fqName = irFunction.fqNameWhenAvailable.toString()
return when {
EmptyArray.equalTo(irFunction) -> EmptyArray.unwind(irFunction, environment)
ArrayOf.equalTo(irFunction) -> ArrayOf.unwind(irFunction, environment)
ArrayOfNulls.equalTo(irFunction) -> ArrayOfNulls.unwind(irFunction, environment)
EnumValues.equalTo(irFunction) -> EnumValues.unwind(irFunction, environment)
EnumValueOf.equalTo(irFunction) -> EnumValueOf.unwind(irFunction, environment)
EnumHashCode.equalTo(irFunction) -> EnumHashCode.unwind(irFunction, environment)
JsPrimitives.equalTo(irFunction) -> JsPrimitives.unwind(irFunction, environment)
ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.unwind(irFunction, environment)
SourceLocation.equalTo(irFunction) -> SourceLocation.unwind(irFunction, environment)
AssertIntrinsic.equalTo(irFunction) -> AssertIntrinsic.unwind(irFunction, environment)
else -> throw InterpreterMethodNotFoundError("Method ${irFunction.name} hasn't implemented")
EmptyArray.canHandleFunctionWithName(fqName, irFunction.origin) -> EmptyArray.unwind(irFunction, environment)
ArrayOf.canHandleFunctionWithName(fqName, irFunction.origin) -> ArrayOf.unwind(irFunction, environment)
ArrayOfNulls.canHandleFunctionWithName(fqName, irFunction.origin) -> ArrayOfNulls.unwind(irFunction, environment)
EnumValues.canHandleFunctionWithName(fqName, irFunction.origin) -> EnumValues.unwind(irFunction, environment)
EnumValueOf.canHandleFunctionWithName(fqName, irFunction.origin) -> EnumValueOf.unwind(irFunction, environment)
EnumIntrinsics.canHandleFunctionWithName(fqName, irFunction.origin) -> EnumIntrinsics.unwind(irFunction, environment)
JsPrimitives.canHandleFunctionWithName(fqName, irFunction.origin) -> JsPrimitives.unwind(irFunction, environment)
ArrayConstructor.canHandleFunctionWithName(fqName, irFunction.origin) -> ArrayConstructor.unwind(irFunction, environment)
SourceLocation.canHandleFunctionWithName(fqName, irFunction.origin) -> SourceLocation.unwind(irFunction, environment)
AssertIntrinsic.canHandleFunctionWithName(fqName, irFunction.origin) -> AssertIntrinsic.unwind(irFunction, environment)
else -> null
}
}
}
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.ir.interpreter.intrinsics
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
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.interpreter.*
@@ -23,12 +20,15 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.isArray
import org.jetbrains.kotlin.ir.types.isCharArray
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.types.Variance
internal sealed class IntrinsicBase {
abstract fun equalTo(irFunction: IrFunction): Boolean
abstract fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean
abstract fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment)
abstract fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction>
open fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
return listOf(customEvaluateInstruction(irFunction, environment))
}
fun customEvaluateInstruction(irFunction: IrFunction, environment: IrInterpreterEnvironment): CustomInstruction {
return CustomInstruction {
@@ -39,15 +39,10 @@ internal sealed class IntrinsicBase {
}
internal object EmptyArray : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName in setOf("kotlin.emptyArray", "kotlin.ArrayIntrinsicsKt.emptyArray")
}
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
return listOf(customEvaluateInstruction(irFunction, environment))
}
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val returnType = environment.callStack.getState(irFunction.symbol) as KTypeState
environment.callStack.pushState(emptyArray<Any?>().toState(returnType.irType))
@@ -55,13 +50,8 @@ internal object EmptyArray : IntrinsicBase() {
}
internal object ArrayOf : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
return fqName == "kotlin.arrayOf"
}
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
return listOf(customEvaluateInstruction(irFunction, environment))
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName == "kotlin.arrayOf" || fqName.matches("kotlin\\.(byte|char|short|int|long|float|double|boolean|)ArrayOf".toRegex())
}
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
@@ -72,15 +62,10 @@ internal object ArrayOf : IntrinsicBase() {
}
internal object ArrayOfNulls : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName == "kotlin.arrayOfNulls"
}
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
return listOf(customEvaluateInstruction(irFunction, environment))
}
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val size = environment.callStack.getState(irFunction.valueParameters.first().symbol).asInt()
val array = arrayOfNulls<Any?>(size)
@@ -94,9 +79,8 @@ internal object ArrayOfNulls : IntrinsicBase() {
}
internal object EnumValues : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
return (fqName == "kotlin.enumValues" || fqName.endsWith(".values")) && irFunction.valueParameters.isEmpty()
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName == "kotlin.enumValues"
}
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
@@ -113,7 +97,7 @@ internal object EnumValues : IntrinsicBase() {
val enumClass = getEnumClass(irFunction, environment)
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>()
return listOf(customEvaluateInstruction(irFunction, environment)) + enumEntries.reversed().map { SimpleInstruction(it) }
return super.unwind(irFunction, environment) + enumEntries.reversed().map { SimpleInstruction(it) }
}
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
@@ -125,9 +109,8 @@ internal object EnumValues : IntrinsicBase() {
}
internal object EnumValueOf : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
return (fqName == "kotlin.enumValueOf" || fqName.endsWith(".valueOf")) && irFunction.valueParameters.size == 1
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName == "kotlin.enumValueOf"
}
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
@@ -161,32 +144,59 @@ internal object EnumValueOf : IntrinsicBase() {
}
}
internal object EnumHashCode : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
return fqName == "kotlin.Enum.hashCode"
internal object EnumIntrinsics : IntrinsicBase() {
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
if (origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER) return true
return fqName.startsWith("kotlin.Enum.")
}
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
return listOf(customEvaluateInstruction(irFunction, environment))
return when (irFunction.name.asString()) {
"values" -> EnumValues.unwind(irFunction, environment)
"valueOf" -> EnumValueOf.unwind(irFunction, environment)
else -> super.unwind(irFunction, environment)
}
}
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val hashCode = environment.callStack.getState(irFunction.dispatchReceiverParameter!!.symbol).hashCode()
environment.callStack.pushState(hashCode.toState(irFunction.returnType))
val callStack = environment.callStack
val enumEntry = callStack.getState(irFunction.dispatchReceiverParameter!!.symbol)
when (irFunction.name.asString()) {
"<get-name>", "<get-ordinal>" -> {
val symbol = (irFunction as IrSimpleFunction).correspondingPropertySymbol!!
callStack.pushState(enumEntry.getField(symbol)!!)
}
"compareTo" -> {
val ordinal = enumEntry.irClass.declarations.filterIsInstance<IrProperty>()
.first { it.name.asString() == "ordinal" }
.resolveFakeOverride()!!
val other = callStack.getState(irFunction.valueParameters.single().symbol)
val compareTo = enumEntry.getField(ordinal.symbol)!!.asInt().compareTo(other.getField(ordinal.symbol)!!.asInt())
callStack.pushState(compareTo.toState(irFunction.returnType))
}
// TODO "clone" -> throw exception
"equals" -> {
val other = callStack.getState(irFunction.valueParameters.single().symbol)
callStack.pushState((enumEntry === other).toState(irFunction.returnType))
}
"hashCode" -> callStack.pushState(enumEntry.hashCode().toState(irFunction.returnType))
"toString" -> {
val name = enumEntry.irClass.declarations.filterIsInstance<IrProperty>()
.first { it.name.asString() == "name" }
.resolveFakeOverride()!!
callStack.pushState(enumEntry.getField(name.symbol)!!)
}
"values" -> EnumValues.evaluate(irFunction, environment)
"valueOf" -> EnumValueOf.evaluate(irFunction, environment)
}
}
}
internal object JsPrimitives : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName == "kotlin.Long.<init>" || fqName == "kotlin.Char.<init>"
}
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
return listOf(customEvaluateInstruction(irFunction, environment))
}
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
when (irFunction.fqNameWhenAvailable.toString()) {
"kotlin.Long.<init>" -> {
@@ -203,8 +213,7 @@ internal object JsPrimitives : IntrinsicBase() {
}
internal object ArrayConstructor : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName.matches("kotlin\\.(Byte|Char|Short|Int|Long|Float|Double|Boolean|)Array\\.<init>".toRegex())
}
@@ -220,7 +229,7 @@ internal object ArrayConstructor : IntrinsicBase() {
environment.callStack.loadUpValues(initLambda)
val function = initLambda.irFunction as IrSimpleFunction
val index = initLambda.irFunction.valueParameters.single()
for (i in 0 until size) {
for (i in size - 1 downTo 0) {
val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.returnType, function.symbol)
call.putValueArgument(0, IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, index.type, i))
instructions += CompoundInstruction(call)
@@ -235,9 +244,9 @@ internal object ArrayConstructor : IntrinsicBase() {
val arrayValue = MutableList<Any?>(size) { if (irFunction.returnType.isCharArray()) 0.toChar() else 0 }
if (irFunction.valueParameters.size == 2) {
for (i in 0 until size) {
for (i in size - 1 downTo 0) {
arrayValue[i] = environment.callStack.popState().let {
// TODO wrap
// TODO may be use wrap
when (it) {
is Wrapper -> it.value
is Primitive<*> -> if (it.type.isArray() || it.type.isPrimitiveArray()) it else it.value
@@ -253,23 +262,17 @@ internal object ArrayConstructor : IntrinsicBase() {
}
internal object SourceLocation : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName == "kotlin.experimental.sourceLocation" || fqName == "kotlin.experimental.SourceLocationKt.sourceLocation"
}
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
return listOf(customEvaluateInstruction(irFunction, environment))
}
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
environment.callStack.pushState(environment.callStack.getFileAndPositionInfo().toState(irFunction.returnType))
}
}
internal object AssertIntrinsic : IntrinsicBase() {
override fun equalTo(irFunction: IrFunction): Boolean {
val fqName = irFunction.fqNameWhenAvailable.toString()
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
return fqName == "kotlin.PreconditionsKt.assert"
}
@@ -25,7 +25,8 @@ internal class CommonProxy private constructor(override val state: Common, overr
*/
private fun IrFunction.wasAlreadyCalled(): Boolean {
val anyParameter = this.getLastOverridden().dispatchReceiverParameter!!.symbol
if (callInterceptor.environment.callStack.containsVariable(anyParameter)) return true
val callStack = callInterceptor.environment.callStack
if (callStack.containsVariable(anyParameter) && callStack.getState(anyParameter) === state) return true
return this == callInterceptor.environment.callStack.currentFrameOwner
}
@@ -5,12 +5,18 @@
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.stack.Variable
import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import org.jetbrains.kotlin.name.Name
internal class Common private constructor(override val irClass: IrClass, override val fields: MutableList<Variable>) : Complex, StateWithClosure {
override val upValues: MutableList<Variable> = mutableListOf()
@@ -19,11 +25,6 @@ internal class Common private constructor(override val irClass: IrClass, overrid
constructor(irClass: IrClass) : this(irClass, mutableListOf())
fun copyFieldsFrom(state: Complex) {
this.fields.addAll(state.fields)
superWrapperClass = state.superWrapperClass ?: state as? Wrapper
}
// This method is used to get correct java method name
private fun getKotlinName(declaringClassName: String, methodName: String): String {
return when {
@@ -44,6 +45,33 @@ internal class Common private constructor(override val irClass: IrClass, overrid
}
}
fun getEqualsFunction(): IrSimpleFunction {
val equalsFun = irClass.declarations
.filterIsInstance<IrSimpleFunction>()
.single {
it.name == Name.identifier("equals") && it.dispatchReceiverParameter != null
&& it.valueParameters.size == 1 && it.valueParameters[0].type.isNullableAny()
}
return getOverridden(equalsFun)
}
fun getHashCodeFunction(): IrSimpleFunction {
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
.single { it.name.asString() == "hashCode" && it.valueParameters.isEmpty() }
.let { getOverridden(it) }
}
fun getToStringFunction(): IrSimpleFunction {
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
.single { it.name.asString() == "toString" && it.valueParameters.isEmpty() }
.let { getOverridden(it) }
}
fun createToStringIrCall(): IrCall {
val toStringFun = getToStringFunction()
return IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, toStringFun.returnType, toStringFun.symbol)
}
override fun toString(): String {
return "Common(obj='${irClass.fqNameForIrSerialization}', values=$fields)"
}
@@ -48,7 +48,7 @@ internal interface Complex: State {
}
}
private fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction {
fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction {
if (owner.parent == superWrapperClass?.irClass) return owner
if (!owner.isFakeOverride || owner.body != null || owner.parentAsClass.defaultType.isAny()) return owner
@@ -61,28 +61,4 @@ internal interface Complex: State {
val irFunction = receiver.getIrFunction(expression.symbol) ?: return null
return getOverridden(irFunction as IrSimpleFunction)
}
fun getEqualsFunction(): IrSimpleFunction {
val equalsFun = irClass.declarations
.filterIsInstance<IrSimpleFunction>()
.single {
it.name == Name.identifier("equals") && it.dispatchReceiverParameter != null
&& it.valueParameters.size == 1 && it.valueParameters[0].type.isNullableAny()
}
return getOverridden(equalsFun)
}
fun getHashCodeFunction(): IrSimpleFunction {
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
.filter { it.name.asString() == "hashCode" }
.first { it.valueParameters.isEmpty() }
.let { getOverridden(it) }
}
fun getToStringFunction(): IrSimpleFunction {
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
.filter { it.name.asString() == "toString" }
.first { it.valueParameters.isEmpty() }
.let { getOverridden(it) }
}
}