From 731fb9bc703158439f77fd828383f4a5a9eeaea9 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Fri, 14 Feb 2020 19:16:03 +0300 Subject: [PATCH] Make ir interpreter to work with minimal dependence on ir lowerings --- .../common/interpreter/IrInterpreter.kt | 184 +++++++++++------- .../ParallelVisitorForInlineFun.kt | 137 ------------- .../backend/common/interpreter/Utils.kt | 16 +- .../interpreter/builtins/CompileTimeUtils.kt | 1 + .../builtins/IrBuiltInsMapGenerated.kt | 4 +- .../backend/common/interpreter/stack/State.kt | 26 ++- generators/evaluate/GenerateBuiltInsMap.kt | 4 +- 7 files changed, 132 insertions(+), 240 deletions(-) delete mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/ParallelVisitorForInlineFun.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt index d2113efa425..1a854728848 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt @@ -11,6 +11,7 @@ import kotlinx.coroutines.yield import org.jetbrains.kotlin.backend.common.interpreter.builtins.* import org.jetbrains.kotlin.backend.common.interpreter.stack.* import org.jetbrains.kotlin.builtins.DefaultBuiltIns +import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.* @@ -75,7 +76,9 @@ class IrInterpreter(irModule: IrModuleFragment) { is IrFunctionImpl -> interpretFunction(this, data) is IrCall -> interpretCall(this, data) is IrConstructorCall -> interpretConstructorCall(this, data) + is IrEnumConstructorCall -> interpretEnumConstructorCall(this, data) is IrDelegatingConstructorCall -> interpretDelegatedConstructorCall(this, data) + is IrInstanceInitializerCall -> interpretInstanceInitializerCall(this, data) is IrBody -> interpretBody(this, data) is IrBlock -> interpretBlock(this, data) is IrReturn -> interpretReturn(this, data) @@ -99,6 +102,8 @@ class IrInterpreter(irModule: IrModuleFragment) { is IrCatch -> interpretCatch(this, data) is IrThrow -> interpretThrow(this, data) is IrStringConcatenation -> interpretStringConcatenation(this, data) + is IrFunctionExpression -> interpretFunctionExpression(this, data) + is IrFunctionReference -> interpretFunctionReference(this, data) else -> TODO("${this.javaClass} not supported") } @@ -143,7 +148,7 @@ class IrInterpreter(irModule: IrModuleFragment) { while (cause != null) { for ((causeStackIndex, causeStackTraceElement) in cause.stackTrace.withIndex()) { val currentStackTraceValue = causeStackTraceElement.className + "." + causeStackTraceElement.methodName - if (currentStackTraceValue== lastNeededValue) { + if (currentStackTraceValue == lastNeededValue) { cause.stackTrace = cause.stackTrace.sliceArray(0 until causeStackIndex).reversedArray() break } @@ -210,11 +215,13 @@ class IrInterpreter(irModule: IrModuleFragment) { data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) } "arrayOfNulls" -> { - val result = arrayOfNulls(irFunction.getArgsForMethodInvocation(data).first() as Int) + val size = (data.getVariableState(irFunction.valueParameters.first().descriptor) as Primitive<*>).value as Int + val result = arrayOfNulls(size) data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) } "values", "enumValues" -> { - val enumClass = irFunction.parentAsClass + val enumClass = + (irFunction.parent as? IrClass) ?: data.getVariableState(irFunction.typeParameters.first().descriptor).irClass val enumEntries = enumClass.declarations .filterIsInstance() .map { entry -> @@ -224,14 +231,16 @@ class IrInterpreter(irModule: IrModuleFragment) { data.pushReturnValue(enumEntries.toTypedArray().toState(irBuiltIns.arrayClass.defaultType)) } "valueOf", "enumValueOf" -> { - val enumClass = irFunction.parentAsClass - val enumEntryName = (data.getAll().single().state as Primitive<*>).value.toString() + val enumClass = + (irFunction.parent as? IrClass) ?: data.getVariableState(irFunction.typeParameters.first().descriptor).irClass + val enumEntryName = (data.getVariableState(irFunction.valueParameters.first().descriptor) as Primitive<*>).value.toString() val enumEntry = enumClass.declarations .filterIsInstance() .singleOrNull { it.name.asString() == enumEntryName } if (enumEntry == null) { val message = "No enum constant ${enumClass.fqNameForIrSerialization}.$enumEntryName" data.pushReturnValue(ExceptionState(IllegalArgumentException(message), illegalArgumentException, stackTrace)) + return Code.EXCEPTION } else { enumEntry.interpret(data).also { if (it != Code.NEXT) return it } } @@ -289,7 +298,10 @@ class IrInterpreter(irModule: IrModuleFragment) { private suspend fun calculateBuiltIns(irFunction: IrFunction, data: Frame): Code { val descriptor = irFunction.descriptor - val methodName = descriptor.name.asString() + val methodName = when (val property = (irFunction as? IrFunctionImpl)?.correspondingPropertySymbol) { + null -> descriptor.name.asString() + else -> property.owner.name.asString() + } val args = data.getAll().map { it.state } val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type @@ -370,26 +382,50 @@ class IrInterpreter(irModule: IrModuleFragment) { extensionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getExtensionReceiver()!!, it)) } // if irFunction is lambda and it has receiver, then first descriptor must be taken from extension receiver - val receiverAsFirstArgument = if (irFunction.isLocalLambda()) listOfNotNull(irFunction.symbol.getExtensionReceiver()) else listOf() + val receiverAsFirstArgument = if (dispatchReceiver is Lambda) listOfNotNull(irFunction.symbol.getExtensionReceiver()) else listOf() val valueParametersDescriptors = receiverAsFirstArgument + irFunction.descriptor.valueParameters interpretValueParameters(expression, data).also { if (it != Code.NEXT) return it } newFrame.addAll(valueParametersDescriptors.map { Variable(it, data.popReturnValue()) }) - val isWrapper = (dispatchReceiver is Wrapper && rawExtensionReceiver == null) || - (extensionReceiver is Wrapper && rawDispatchReceiver == null) + irFunction.takeIf { it.isInline }?.typeParameters?.forEachIndexed { index, typeParameter -> + if (typeParameter.isReified) { + val typeArgumentState = Common(expression.getTypeArgument(index)?.classOrNull!!.owner, mutableListOf()) + newFrame.addVar(Variable(typeParameter.descriptor, typeArgumentState)) + } + } + + val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null val code = when { - isWrapper -> ((dispatchReceiver ?: extensionReceiver) as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame) + isWrapper -> (dispatchReceiver as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame) irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, newFrame) irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame) - irFunction.body == null -> calculateBuiltIns(irFunction, newFrame) + irFunction.body == null || dispatchReceiver is Primitive<*> -> calculateBuiltIns(irFunction, newFrame) else -> irFunction.interpret(newFrame) } data.pushReturnValue(newFrame) return code } + private suspend fun interpretInstanceInitializerCall(call: IrInstanceInitializerCall, data: Frame): Code { + val irClass = call.classSymbol.owner + + val classProperties = irClass.declarations.filterIsInstance() + classProperties.forEach { property -> + property.backingField?.initializer?.expression?.interpret(data)?.also { if (it != Code.NEXT) return it } + val receiver = irClass.thisReceiver!!.descriptor + if (property.backingField?.initializer != null) + property.backingField?.let { data.getVariableState(receiver).setState(Variable(it.descriptor, data.popReturnValue())) } + } + + val anonymousInitializer = irClass.declarations.filterIsInstance().filter { !it.isStatic } + anonymousInitializer.forEach { init -> init.body.interpret(data).also { if (it != Code.NEXT) return it } } + + return Code.NEXT + } + private suspend fun interpretConstructor(constructorCall: IrFunctionAccessExpression, data: Frame): Code { + val isPrimary = (constructorCall.symbol.owner as IrConstructor).isPrimary interpretValueParameters(constructorCall, data).also { if (it != Code.NEXT) return it } val valueParameters = constructorCall.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList() val newFrame = InterpreterFrame(valueParameters) @@ -402,23 +438,33 @@ class IrInterpreter(irModule: IrModuleFragment) { if (parent.defaultType.isArray() || parent.defaultType.isPrimitiveArray()) { // array constructor doesn't have body so must be treated separately - // here we must except only one possible constructor, with one value parameter size - // the other one, with lambda, is transforming into ir returnable block val arrayConstructor = irBuiltIns.primitiveArrays.first().constructors.single { it.owner.valueParameters.size == 2 } val sizeDescriptor = arrayConstructor.owner.valueParameters.single { it.name.asString() == "size" }.descriptor - val size = (newFrame.getVariableState(sizeDescriptor) as Primitive).value + val size = (newFrame.getVariableState(sizeDescriptor) as Primitive<*>).value as Int + + val arrayValue = Array(size) { 0 } + if (valueParameters.size == 2) { + val initDescriptor = arrayConstructor.owner.valueParameters.single { it.name.asString() == "init" }.descriptor + val initLambda = newFrame.getVariableState(initDescriptor) as Lambda + val indexDescriptor = initLambda.irFunction.valueParameters.single().descriptor + for (i in 0 until size) { + val lambdaFrame = InterpreterFrame(mutableListOf(Variable(indexDescriptor, i.toState(irBuiltIns.intType)))) + initLambda.irFunction.body!!.interpret(lambdaFrame).also { if (it != Code.RETURN) return it } + arrayValue[i] = lambdaFrame.popReturnValue().let { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it } + } + } val array = when (parent.defaultType.getFqName()) { - "kotlin.ByteArray" -> Primitive(ByteArray(size), parent.defaultType) - "kotlin.CharArray" -> Primitive(CharArray(size), parent.defaultType) - "kotlin.ShortArray" -> Primitive(ShortArray(size), parent.defaultType) - "kotlin.IntArray" -> Primitive(IntArray(size), parent.defaultType) - "kotlin.LongArray" -> Primitive(LongArray(size), parent.defaultType) - "kotlin.FloatArray" -> Primitive(FloatArray(size), parent.defaultType) - "kotlin.DoubleArray" -> Primitive(DoubleArray(size), parent.defaultType) - "kotlin.BooleanArray" -> Primitive(BooleanArray(size), parent.defaultType) - else -> throw AssertionError("Unsupported array class ${parent.defaultType.getFqName()}") - } + "kotlin.ByteArray" -> Primitive(ByteArray(size) { i -> (arrayValue[i] as Number).toByte() }, parent.defaultType) + "kotlin.CharArray" -> Primitive(CharArray(size) { i -> (arrayValue[i] as Number).toChar() }, parent.defaultType) + "kotlin.ShortArray" -> Primitive(ShortArray(size) { i -> (arrayValue[i] as Number).toShort() }, parent.defaultType) + "kotlin.IntArray" -> Primitive(IntArray(size) { i -> (arrayValue[i] as Number).toInt() }, parent.defaultType) + "kotlin.LongArray" -> Primitive(LongArray(size) { i -> (arrayValue[i] as Number).toLong() }, parent.defaultType) + "kotlin.FloatArray" -> Primitive(FloatArray(size) { i -> (arrayValue[i] as Number).toFloat() }, parent.defaultType) + "kotlin.DoubleArray" -> Primitive(DoubleArray(size) { i -> (arrayValue[i] as Number).toDouble() }, parent.defaultType) + "kotlin.BooleanArray" -> Primitive(BooleanArray(size) { i -> arrayValue[i].toString().toBoolean() }, parent.defaultType) + else -> Primitive>(arrayValue, parent.defaultType) + } as Primitive<*> data.pushReturnValue(array) return Code.NEXT @@ -426,10 +472,10 @@ class IrInterpreter(irModule: IrModuleFragment) { val state = Common(parent, mutableListOf()) newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body - val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT - state.superType = newFrame.popReturnValue() as Complex - data.pushReturnValue(state) - return code + constructorCall.getBody()?.interpret(newFrame)?.also { if (it != Code.NEXT) return it.apply { data.pushReturnValue(newFrame) } } + val returnedState = newFrame.popReturnValue() as Complex + data.pushReturnValue(if (isPrimary) state.apply { superType = returnedState } else returnedState.apply { setStatesFrom(state) }) + return Code.NEXT } private suspend fun interpretConstructorCall(constructorCall: IrConstructorCall, data: Frame): Code { @@ -439,6 +485,12 @@ class IrInterpreter(irModule: IrModuleFragment) { } } + private suspend fun interpretEnumConstructorCall(enumConstructorCall: IrEnumConstructorCall, data: Frame): Code { + return interpretConstructor(enumConstructorCall, data).apply { + (data.peekReturnValue() as Complex).let { it.setInstanceRecursive(it) } + } + } + private suspend fun interpretDelegatedConstructorCall(delegatingConstructorCall: IrDelegatingConstructorCall, data: Frame): Code { if (delegatingConstructorCall.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) { val anyAsStateObject = Common(irBuiltIns.anyClass.owner, mutableListOf()) @@ -458,7 +510,7 @@ class IrInterpreter(irModule: IrModuleFragment) { val newFrame = data.copy() var code = Code.NEXT - val iterator = statements.asSequence().iterator() + val iterator = statements.iterator() while (code == Code.NEXT && iterator.hasNext()) { code = iterator.next().interpret(newFrame) } @@ -467,34 +519,6 @@ class IrInterpreter(irModule: IrModuleFragment) { } private suspend fun interpretBlock(block: IrBlock, data: Frame): Code { - if (block.isLambdaFunction()) { - val irLambdaFunction = block.statements.filterIsInstance().first() - data.pushReturnValue(Lambda(irLambdaFunction.symbol.owner, irLambdaFunction.type.classOrNull!!.owner)) - return Code.NEXT - } - - val inlineFun = (block as? IrReturnableBlock)?.inlineFunctionSymbol?.owner - if (inlineFun?.hasAnnotation(evaluateIntrinsicAnnotation) == true) { - val newFrame = data.copy() - block.statements.filterIsInstance().forEach { variable -> - variable.initializer!!.interpret(newFrame).also { if (it != Code.NEXT) return it } - newFrame.addVar(Variable(variable.descriptor, newFrame.popReturnValue())) - } - - val originalVarToInline = ParallelVisitorForInlineFun() - .apply { this.visitElement(inlineFun.body!!.statements.first(), block.removeBlocks()!!) } - .originalVarToInline - - val frameForWrapper = InterpreterFrame() - (listOfNotNull(inlineFun.extensionReceiverParameter, inlineFun.dispatchReceiverParameter) + inlineFun.valueParameters) - .map { it.descriptor } - .forEach { frameForWrapper.addVar(Variable(it, newFrame.getVariableState(originalVarToInline[it]!!))) } - - return Wrapper.getStaticMethod(inlineFun) - .invokeMethod(inlineFun, frameForWrapper) - .apply { data.pushReturnValue(frameForWrapper) } - } - return interpretStatements(block.statements, data) } @@ -591,34 +615,36 @@ class IrInterpreter(irModule: IrModuleFragment) { } private suspend fun interpretGetObjectValue(expression: IrGetObjectValue, data: Frame): Code { - val objectState = Common(expression.symbol.owner, mutableListOf()) - val newFrame = data.copy().apply { addVar(Variable(expression.symbol.descriptor.thisAsReceiverParameter, objectState)) } - - val constructor = expression.symbol.owner.declarations.single { it is IrConstructor } as IrConstructor - val constructorBody = constructor.body?.statements?.get(1) as? IrBlock - val irAnnotatedSetFields = constructorBody?.statements?.filterIsInstance() - ?.filter { it.symbol.owner.correspondingPropertySymbol!!.owner.hasAnnotation(compileTimeAnnotation) } - irAnnotatedSetFields?.forEach { irSetField -> irSetField.interpret(newFrame).also { if (it != Code.NEXT) return it } } - + val objectState = Common(expression.symbol.owner, mutableListOf()).apply { this.instance = this } data.pushReturnValue(objectState) return Code.NEXT } private suspend fun interpretGetEnumValue(expression: IrGetEnumValue, data: Frame): Code { - return interpretEnumEntry(expression.symbol.owner, data) + val enumEntry = expression.symbol.owner + val enumSignature = Pair(enumEntry.parentAsClass, enumEntry.name.asString()) + mapOfEnums[enumSignature]?.let { return Code.NEXT.apply { data.pushReturnValue(it) } } + return interpretEnumEntry(enumEntry, data).apply { + if (this == Code.NEXT) mapOfEnums[enumSignature] = data.peekReturnValue() as Common + } } private suspend fun interpretEnumEntry(enumEntry: IrEnumEntry, data: Frame): Code { - val enumSignature = Pair(enumEntry.parentAsClass, enumEntry.name.asString()) - mapOfEnums[enumSignature]?.let { - data.pushReturnValue(it) - return Code.NEXT + val enumClass = enumEntry.symbol.owner.parentAsClass + val enumEntries = enumClass.declarations.filterIsInstance() + + val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall) + if (enumEntries.isNotEmpty() && enumSuperCall != null) { + val valueArguments = listOf( + enumEntry.name.asString().toIrConst(irBuiltIns.stringType), enumEntries.indexOf(enumEntry).toIrConst(irBuiltIns.intType) + ) + enumSuperCall.mapValueParameters { valueArguments[it.index] } } val code = enumEntry.initializerExpression?.interpret(data)?.also { if (it != Code.NEXT) return it } - code ?: throw AssertionError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null") - mapOfEnums[enumSignature] = data.peekReturnValue() as Common - return code + enumSuperCall?.mapValueParameters { null } + data.pushReturnValue((data.popReturnValue() as Complex)) + return code ?: throw AssertionError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null") } private suspend fun interpretTypeOperatorCall(expression: IrTypeOperatorCall, data: Frame): Code { @@ -737,4 +763,14 @@ class IrInterpreter(irModule: IrModuleFragment) { data.pushReturnValue(result.toString().toState(expression.type)) return Code.NEXT } + + private suspend fun interpretFunctionExpression(expression: IrFunctionExpression, data: Frame): Code { + data.pushReturnValue(Lambda(expression.function, expression.type.classOrNull!!.owner)) + return Code.NEXT + } + + private suspend fun interpretFunctionReference(reference: IrFunctionReference, data: Frame): Code { + data.pushReturnValue(Lambda(reference.symbol.owner, reference.type.classOrNull!!.owner)) + return Code.NEXT + } } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/ParallelVisitorForInlineFun.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/ParallelVisitorForInlineFun.kt deleted file mode 100644 index 11d952ddccc..00000000000 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/ParallelVisitorForInlineFun.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.backend.common.interpreter - -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.IrVariable -import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.util.statements -import org.jetbrains.kotlin.ir.visitors.IrElementVisitor - -/** - * This class is used for parallel processing two ir elements and gathering information about ir temporary variables from inline block - */ -internal class ParallelVisitorForInlineFun : IrElementVisitor { - val originalVarToInline = mutableMapOf() - - override fun visitElement(element: IrElement, data: IrElement) { - element.accept(this, data) - } - - override fun visitGetValue(expression: IrGetValue, data: IrElement) { - val original = expression.symbol.descriptor - val inline = (data as IrGetValue).symbol.descriptor - if (!original.equalTo(inline)) { - originalVarToInline[original] = inline - } - } - - override fun visitConst(expression: IrConst, data: IrElement) {} - - override fun visitVariable(declaration: IrVariable, data: IrElement) { - declaration.initializer?.accept(this, (data as IrVariable).initializer!!) - } - - override fun visitBody(body: IrBody, data: IrElement) { - for ((index, statement) in body.statements.withIndex()) { - statement.accept(this, (data as IrBody).statements[index]) - } - } - - override fun visitBlock(expression: IrBlock, data: IrElement) { - for ((index, statement) in expression.statements.withIndex()) { - statement.accept(this, (data as IrBlock).statements[index]) - } - } - - override fun visitStringConcatenation(expression: IrStringConcatenation, data: IrElement) { - for ((index, argument) in expression.arguments.withIndex()) { - argument.accept(this, (data as IrStringConcatenation).arguments[index]) - } - } - - override fun visitSetVariable(expression: IrSetVariable, data: IrElement) { - expression.value.accept(this, (data as IrSetVariable).value) - } - - override fun visitGetField(expression: IrGetField, data: IrElement) { - expression.receiver?.accept(this, (data as IrGetField).receiver!!) - } - - override fun visitSetField(expression: IrSetField, data: IrElement) { - expression.value.accept(this, (data as IrSetField).value) - expression.receiver?.accept(this, data.receiver!!) - } - - override fun visitCall(expression: IrCall, data: IrElement) { - expression.dispatchReceiver?.accept(this, (data as IrCall).dispatchReceiver!!) - expression.extensionReceiver?.accept(this, (data as IrCall).extensionReceiver!!) - for (i in 0 until expression.valueArgumentsCount) { - expression.getValueArgument(i)?.accept(this, (data as IrCall).getValueArgument(i)!!) - } - expression.getBody()?.accept(this, (data as IrCall).getBody()!!) - } - - override fun visitConstructorCall(expression: IrConstructorCall, data: IrElement) { - expression.dispatchReceiver?.accept(this, (data as IrConstructorCall).dispatchReceiver!!) - expression.extensionReceiver?.accept(this, (data as IrConstructorCall).extensionReceiver!!) - for (i in 0 until expression.valueArgumentsCount) { - expression.getValueArgument(i)?.accept(this, (data as IrConstructorCall).getValueArgument(i)!!) - } - expression.getBody()?.accept(this, (data as IrConstructorCall).getBody()!!) - } - - override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: IrElement) { - expression.dispatchReceiver?.accept(this, (data as IrDelegatingConstructorCall).dispatchReceiver!!) - expression.extensionReceiver?.accept(this, (data as IrDelegatingConstructorCall).extensionReceiver!!) - for (i in 0 until expression.valueArgumentsCount) { - expression.getValueArgument(i)?.accept(this, (data as IrDelegatingConstructorCall).getValueArgument(i)!!) - } - expression.getBody()?.accept(this, (data as IrDelegatingConstructorCall).getBody()!!) - } - - override fun visitWhen(expression: IrWhen, data: IrElement) { - for ((index, branch) in expression.branches.withIndex()) { - branch.accept(this, (data as IrWhen).branches[index]) - } - } - - override fun visitBranch(branch: IrBranch, data: IrElement) { - branch.condition.accept(this, (data as IrBranch).condition) - branch.result.accept(this, data.result) - } - - override fun visitLoop(loop: IrLoop, data: IrElement) { - loop.condition.accept(this, (data as IrLoop).condition) - loop.body?.accept(this, data.body!!) - } - - override fun visitTry(aTry: IrTry, data: IrElement) { - aTry.tryResult.accept(this, (data as IrTry).tryResult) - for ((index, catch) in aTry.catches.withIndex()) { - catch.accept(this, data.catches[index]) - } - aTry.finallyExpression?.accept(this, data.finallyExpression!!) - } - - override fun visitCatch(aCatch: IrCatch, data: IrElement) { - aCatch.catchParameter.accept(this, (data as IrCatch).catchParameter) - aCatch.result.accept(this, data.result) - } - - override fun visitReturn(expression: IrReturn, data: IrElement) { - expression.value.accept(this, (data as IrReturn).value) - } - - override fun visitThrow(expression: IrThrow, data: IrElement) { - expression.value.accept(this, (data as IrThrow).value) - } - - override fun visitTypeOperator(expression: IrTypeOperatorCall, data: IrElement) { - expression.argument.accept(this, (data as IrTypeOperatorCall).argument) - } -} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt index b44dfa5094a..85a474bd2e1 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt @@ -59,7 +59,9 @@ private fun DeclarationDescriptor.isSubtypeOf(other: DeclarationDescriptor): Boo private fun DeclarationDescriptor.hasSameNameAs(other: DeclarationDescriptor): Boolean { return (this is VariableDescriptor && other is VariableDescriptor && this.name == other.name) || - (this is FunctionInvokeDescriptor && other is FunctionInvokeDescriptor && this.valueParameters.size == other.valueParameters.size) + (this is FunctionDescriptor && other is FunctionDescriptor && + this.valueParameters.map { it.type.toString() } == other.valueParameters.map { it.type.toString() } && + this.name == other.name) } fun IrCall.isAbstract(): Boolean { @@ -71,19 +73,11 @@ fun IrCall.isFakeOverridden(): Boolean { } fun IrFunction.isAbstract(): Boolean { - return (this.symbol.owner as? IrSimpleFunction)?.modality == Modality.ABSTRACT + return (this as? IrSimpleFunction)?.modality == Modality.ABSTRACT } fun IrFunction.isFakeOverridden(): Boolean { - return this.symbol.owner.isFakeOverride -} - -fun IrContainerExpression.isLambdaFunction(): Boolean { - return this.origin == IrStatementOrigin.LAMBDA || this.origin == IrStatementOrigin.ANONYMOUS_FUNCTION -} - -fun IrDeclaration.isLocalLambda(): Boolean { - return this.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA + return this.isFakeOverride } fun State.toIrExpression(expression: IrExpression): IrExpression { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/builtins/CompileTimeUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/builtins/CompileTimeUtils.kt index 84d925ac963..eb1cbd042ae 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/builtins/CompileTimeUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/builtins/CompileTimeUtils.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.name.FqName val compileTimeAnnotation = FqName("kotlin.CompileTimeCalculation") val evaluateIntrinsicAnnotation = FqName("kotlin.EvaluateIntrinsic") +val contractsDslAnnotation = FqName("kotlin.internal.ContractsDsl") data class CompileTimeFunction(val methodName: String, val args: List) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/builtins/IrBuiltInsMapGenerated.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/builtins/IrBuiltInsMapGenerated.kt index 24d60188a46..5a56f8d8e78 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/builtins/IrBuiltInsMapGenerated.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/builtins/IrBuiltInsMapGenerated.kt @@ -121,8 +121,8 @@ val unaryFunctions = mapOf>( unaryOperation("hashCode", "Any") { a -> a.hashCode() }, unaryOperation("toString", "Any") { a -> a.defaultToString() }, unaryOperation("CHECK_NOT_NULL", "T0?") { a -> a!! }, - unaryOperation("", "Throwable") { a -> a.getMessage() }, - unaryOperation("", "Throwable") { a -> a.getCause() } + unaryOperation("message", "Throwable") { a -> a.getMessage() }, + unaryOperation("cause", "Throwable") { a -> a.getCause() } ) val binaryFunctions = mapOf>( diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt index d1695ed518c..786cff16e59 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt @@ -12,10 +12,13 @@ import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor 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.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.expressions.IrGetValue +import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* @@ -51,16 +54,8 @@ class Primitive(var value: T, val type: IrType) : State { override val fields: MutableList = mutableListOf() override val irClass: IrClass = type.classOrNull!!.owner - init { - if (value != null) { - val properties = irClass.declarations.filterIsInstance() - for (property in properties) { - val propertySignature = CompileTimeFunction(property.name.asString(), listOf(irClass.descriptor.defaultType.toString())) - val propertyValue = unaryFunctions[propertySignature]?.invoke(value) - ?: throw NoSuchMethodException("For given property $propertySignature there is no entry in unary map") - fields.add(Variable(property.descriptor, Primitive(propertyValue, property.backingField!!.type))) - } - } + override fun getState(descriptor: DeclarationDescriptor): State { + return super.getState(descriptor) ?: this } override fun setState(newVar: Variable) { @@ -129,10 +124,13 @@ abstract class Complex(override val irClass: IrClass, override val fields: Mutab } } + fun setStatesFrom(state: Complex) = state.fields.forEach { setState(it) } + override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? { - return irClass.declarations.filterIsInstance() - .filter { it.descriptor.name == descriptor.name } - .firstOrNull { it.descriptor.valueParameters.map { it.type } == descriptor.valueParameters.map { it.type } } + if (descriptor is PropertyGetterDescriptor) + return irClass.declarations.filterIsInstance().mapNotNull { it.getter }.single { it.descriptor.equalTo(descriptor) } + + return irClass.declarations.filterIsInstance().singleOrNull { it.descriptor.equalTo(descriptor) } } } @@ -274,7 +272,7 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : Complex(irClass, mutableListOf()) { // irFunction is anonymous declaration, but irCall will contain descriptor of invoke method from Function interface - private val invokeDescriptor = irClass.declarations.first().descriptor + private val invokeDescriptor = irClass.declarations.single { it.nameForIrSerialization.asString() == "invoke" }.descriptor override fun setState(newVar: Variable) { throw UnsupportedOperationException("Method setState is not supported in Lambda class") diff --git a/generators/evaluate/GenerateBuiltInsMap.kt b/generators/evaluate/GenerateBuiltInsMap.kt index a221a55baf1..88bb3dd83fb 100644 --- a/generators/evaluate/GenerateBuiltInsMap.kt +++ b/generators/evaluate/GenerateBuiltInsMap.kt @@ -151,8 +151,8 @@ private fun generateUnaryBody(unaryOperationsMap: Map $body }" } + " unaryOperation(\"${irNullCheck.name}\", \"${irNullCheck.valueParameters.first().type}\") { a -> a!! },\n" + - " unaryOperation(\"\", \"Throwable\") { a -> a.getMessage() },\n" + - " unaryOperation(\"\", \"Throwable\") { a -> a.getCause() }" + " unaryOperation(\"message\", \"Throwable\") { a -> a.getMessage() },\n" + + " unaryOperation(\"cause\", \"Throwable\") { a -> a.getCause() }" } private fun generateBinaryBody(