diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt index bfa7cdb8fc8..afc2c08fdd3 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt @@ -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) { - 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) { @@ -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))) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt index 5b736cd7bfd..f71d16e35d6 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt @@ -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." -> { + val irClass = constructor.parentAsClass + val receiver = irClass.thisReceiver!!.symbol + val receiverState = callStack.getState(receiver) + irClass.declarations.filterIsInstance().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") } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index 8f43a4f10f0..aa42093578d 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -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 "") +} \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicEvaluator.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicEvaluator.kt index 639a467f0bf..22a5efdc086 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicEvaluator.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicEvaluator.kt @@ -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 { + fun unwindInstructions(irFunction: IrFunction, environment: IrInterpreterEnvironment): List? { + 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 } } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt index 1bb194348b5..dc52b62f055 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt @@ -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 + open fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List { + 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 { - 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().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 { - 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 { - 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(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() - 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 { - 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()) { + "", "" -> { + val symbol = (irFunction as IrSimpleFunction).correspondingPropertySymbol!! + callStack.pushState(enumEntry.getField(symbol)!!) + } + "compareTo" -> { + val ordinal = enumEntry.irClass.declarations.filterIsInstance() + .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() + .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." || fqName == "kotlin.Char." } - override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List { - return listOf(customEvaluateInstruction(irFunction, environment)) - } - override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { when (irFunction.fqNameWhenAvailable.toString()) { "kotlin.Long." -> { @@ -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\\.".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(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 { - 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" } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt index de66aa94280..77295beba80 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt @@ -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 } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt index 178dddcf5e7..137d1d2393e 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Common.kt @@ -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) : Complex, StateWithClosure { override val upValues: MutableList = 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() + .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() + .single { it.name.asString() == "hashCode" && it.valueParameters.isEmpty() } + .let { getOverridden(it) } + } + + fun getToStringFunction(): IrSimpleFunction { + return irClass.declarations.filterIsInstance() + .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)" } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt index 65bab793701..10ac702e493 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt @@ -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() - .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() - .filter { it.name.asString() == "hashCode" } - .first { it.valueParameters.isEmpty() } - .let { getOverridden(it) } - } - - fun getToStringFunction(): IrSimpleFunction { - return irClass.declarations.filterIsInstance() - .filter { it.name.asString() == "toString" } - .first { it.valueParameters.isEmpty() } - .let { getOverridden(it) } - } } \ No newline at end of file