From 4c1727b82e70a13a1e782c58c9a63580d4c8d974 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 13 Feb 2020 00:04:09 +0300 Subject: [PATCH] Move intrinsic handling inside IrInterpreter class --- .../common/interpreter/IrInterpreter.kt | 77 ++++++++++++------- .../backend/common/interpreter/Utils.kt | 4 +- .../intrinsic/InterpreterIntrinsics.kt | 14 ---- .../backend/common/interpreter/stack/State.kt | 9 ++- 4 files changed, 56 insertions(+), 48 deletions(-) delete mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsic/InterpreterIntrinsics.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 82be7607067..d2113efa425 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 @@ -181,32 +181,8 @@ class IrInterpreter(irModule: IrModuleFragment) { } when (val kind = (irFunction.body as? IrSyntheticBody)?.kind) { - IrSyntheticBodyKind.ENUM_VALUES -> { - val enumClass = irFunction.parentAsClass - val enumEntries = enumClass.declarations - .filterIsInstance() - .map { entry -> - entry.interpret(data).also { if (it != Code.NEXT) return it } - data.popReturnValue() as Common - } - data.pushReturnValue(enumEntries.toTypedArray().toState(irBuiltIns.arrayClass.defaultType)) - Code.NEXT - } - IrSyntheticBodyKind.ENUM_VALUEOF -> { - val enumClass = irFunction.parentAsClass - val enumEntryName = (data.getAll().single().state 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)) - Code.EXCEPTION - } else { - enumEntry.interpret(data).also { if (it != Code.NEXT) return it } - Code.NEXT - } - } + IrSyntheticBodyKind.ENUM_VALUES -> handleIntrinsicMethods(irFunction, data) + IrSyntheticBodyKind.ENUM_VALUEOF -> handleIntrinsicMethods(irFunction, data) null -> irFunction.body?.interpret(data) ?: throw AssertionError("Ir function must be with body") else -> throw AssertionError("Unsupported IrSyntheticBodyKind $kind") } @@ -215,13 +191,57 @@ class IrInterpreter(irModule: IrModuleFragment) { } } - private suspend fun MethodHandle.invokeMethod(irFunction: IrFunction, data: Frame): Code { + private suspend fun MethodHandle?.invokeMethod(irFunction: IrFunction, data: Frame): Code { + this ?: return handleIntrinsicMethods(irFunction, data) val result = this.invokeWithArguments(irFunction.getArgsForMethodInvocation(data)) data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) return Code.NEXT } + private suspend fun handleIntrinsicMethods(irFunction: IrFunction, data: Frame): Code { + when (irFunction.name.asString()) { + "emptyArray" -> { + val result = emptyArray() + data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) + } + "arrayOf" -> { + val result = irFunction.getArgsForMethodInvocation(data).toTypedArray() + data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) + } + "arrayOfNulls" -> { + val result = arrayOfNulls(irFunction.getArgsForMethodInvocation(data).first() as Int) + data.pushReturnValue(result.toState(result.getType(irFunction.returnType))) + } + "values", "enumValues" -> { + val enumClass = irFunction.parentAsClass + val enumEntries = enumClass.declarations + .filterIsInstance() + .map { entry -> + entry.interpret(data).also { if (it != Code.NEXT) return it } + data.popReturnValue() as Common + } + 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 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)) + } else { + enumEntry.interpret(data).also { if (it != Code.NEXT) return it } + } + } + else -> throw AssertionError("Unsupported intrinsic ${irFunction.name}") + } + + return Code.NEXT + } + private suspend fun calculateAbstract(irFunction: IrFunction, data: Frame): Code { if (irFunction.body == null) { val receiver = data.getVariableState(irFunction.symbol.getReceiver()!!) as Complex @@ -259,6 +279,7 @@ class IrInterpreter(irModule: IrModuleFragment) { val overriddenOwner = overridden.owner as IrFunctionImpl return when { + // TODO figure something better superQualifier.irClassFqName() == "kotlin.Enum" && owner.name.asString() == "hashCode" -> calculateOverridden(overriddenOwner, newStates) overriddenOwner.body != null -> overriddenOwner.interpret(newStates) superQualifier.superType == null -> calculateBuiltIns(overriddenOwner, newStates) @@ -461,7 +482,7 @@ class IrInterpreter(irModule: IrModuleFragment) { } val originalVarToInline = ParallelVisitorForInlineFun() - .apply { this.visitElement(inlineFun.body!!.statements.first(), block.statements.last()) } + .apply { this.visitElement(inlineFun.body!!.statements.first(), block.removeBlocks()!!) } .originalVarToInline val frameForWrapper = InterpreterFrame() 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 5818d080ec1..b44dfa5094a 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 @@ -143,11 +143,9 @@ fun IrAnnotationContainer.getAnnotation(annotation: FqName): IrConstructorCall { ?: ((this as IrFunction).parent as IrClass).annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation } } -const val defaultIntrinsicLocation = "org.jetbrains.kotlin.backend.common.interpreter.intrinsic.InterpreterIntrinsicsKt" fun IrAnnotationContainer.getEvaluateIntrinsicValue(): String? { if (!this.hasAnnotation(evaluateIntrinsicAnnotation)) return null - val value = (this.getAnnotation(evaluateIntrinsicAnnotation).getValueArgument(0) as IrConst<*>).value.toString() - return if (value.isEmpty()) defaultIntrinsicLocation else value + return (this.getAnnotation(evaluateIntrinsicAnnotation).getValueArgument(0) as IrConst<*>).value.toString() } fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsic/InterpreterIntrinsics.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsic/InterpreterIntrinsics.kt deleted file mode 100644 index c157dc1dd45..00000000000 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/intrinsic/InterpreterIntrinsics.kt +++ /dev/null @@ -1,14 +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. - */ - -@file:JvmName("InterpreterIntrinsicsKt") - -package org.jetbrains.kotlin.backend.common.interpreter.intrinsic - -public fun emptyArray(): Array = kotlin.emptyArray() - -public fun arrayOf(vararg elements: Any?): Array = elements as Array - -public fun arrayOfNulls(size: Int): Array = arrayOfNulls(size) \ No newline at end of file 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 018ee57d79e..d1695ed518c 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 @@ -159,7 +159,7 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe() private val receiverClass = irClass.defaultType.getClass(true) - fun getMethod(irFunction: IrFunction): MethodHandle { + fun getMethod(irFunction: IrFunction): MethodHandle? { // if function is actually a getter, then use property name as method name val property = (irFunction as? IrFunctionImpl)?.correspondingPropertySymbol?.owner @@ -167,6 +167,7 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, // for example: - method 'get' in kotlin StringBuilder is actually 'charAt' in java StringBuilder // - use getter for private fields such as detailMessage in java.lang.Throwable val intrinsicName = property?.getEvaluateIntrinsicValue() ?: irFunction.getEvaluateIntrinsicValue() + if (intrinsicName?.isEmpty() == true) return null val methodName = intrinsicName ?: (property ?: irFunction).name.toString() val methodType = irFunction.getMethodType() @@ -184,8 +185,10 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, return MethodHandles.lookup().findConstructor(irConstructor.returnType.getClass(true), methodType) } - fun getStaticMethod(irFunction: IrFunction): MethodHandle { - val jvmClassName = Class.forName(irFunction.getEvaluateIntrinsicValue()!!) + fun getStaticMethod(irFunction: IrFunction): MethodHandle? { + val intrinsicName = irFunction.getEvaluateIntrinsicValue() + if (intrinsicName?.isEmpty() == true) return null + val jvmClassName = Class.forName(intrinsicName!!) val methodType = irFunction.getMethodType() return MethodHandles.lookup().findStatic(jvmClassName, irFunction.name.asString(), methodType)