diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 078bc71a4cc..1923fa8d8c9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -1087,6 +1087,6 @@ class ExpressionCodegen( return irFunction.isInline || inlinedInto != null } - private val IrType.isReifiedTypeParameter: Boolean + val IrType.isReifiedTypeParameter: Boolean get() = this.classifierOrNull?.safeAs()?.owner?.isReified == true } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/EnumIntrinsics.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/EnumIntrinsics.kt new file mode 100644 index 00000000000..9ccd3a07f22 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/EnumIntrinsics.kt @@ -0,0 +1,68 @@ +/* + * 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.jvm.intrinsics + +import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo +import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen +import org.jetbrains.kotlin.backend.jvm.codegen.MaterialValue +import org.jetbrains.kotlin.backend.jvm.codegen.materialized +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.org.objectweb.asm.Type + +object EnumValueOf : IntrinsicMethod() { + override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo) = with(codegen) { + val type = expression.getTypeArgument(0)!! + val result = expression.getValueArgument(0)!!.accept(this, data).materialized + if (type.isReifiedTypeParameter) { + // Note that the inliner expects exactly the following sequence of instructions. + // + // ACONST_NULL + // ALOAD n + // INVOKESTATIC java/lang/Enum.valueOf... + val temporary = frameMap.enterTemp(result.type) + mv.store(temporary, result.type) + putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED) + mv.aconst(null) + mv.load(temporary, result.type) + val descriptor = Type.getMethodDescriptor(AsmTypes.ENUM_TYPE, AsmTypes.JAVA_CLASS_TYPE, AsmTypes.JAVA_STRING_TYPE) + mv.invokestatic("java/lang/Enum", "valueOf", descriptor, false) + frameMap.leaveTemp(result.type) + MaterialValue(codegen, AsmTypes.ENUM_TYPE, expression.type) + } else { + val returnType = typeMapper.mapType(type) + val descriptor = Type.getMethodDescriptor(returnType, AsmTypes.JAVA_STRING_TYPE) + mv.invokestatic(returnType.internalName, "valueOf", descriptor, false) + MaterialValue(codegen, returnType, expression.type) + } + } +} + +object EnumValues : IntrinsicMethod() { + override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo) = with(codegen) { + val type = expression.getTypeArgument(0)!! + if (type.isReifiedTypeParameter) { + // Note that the inliner expects exactly the following sequence of instructions. + // + // ICONST_0 + // ANEWARRAY Ljava/lang/Enum; + putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED) + mv.iconst(0) + mv.newarray(AsmTypes.ENUM_TYPE) + MaterialValue(codegen, ENUM_ARRAY_TYPE, expression.type) + } else { + val enumType = typeMapper.mapType(type) + val enumArrayType = AsmUtil.getArrayType(enumType) + val descriptor = Type.getMethodDescriptor(enumArrayType) + mv.invokestatic(enumType.internalName, "values", descriptor, false) + MaterialValue(codegen, enumArrayType, expression.type) + } + } + + private val ENUM_ARRAY_TYPE = AsmUtil.getArrayType(AsmTypes.ENUM_TYPE) +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt index a21b7fd6c47..60c7fab91d2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt @@ -78,6 +78,18 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { "clone", emptyList() ) to Clone, + Key( + KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME, + null, + "enumValues", + listOf() + ) to EnumValues, + Key( + KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME, + null, + "enumValueOf", + listOf(KotlinBuiltIns.FQ_NAMES.string.toSafe()) + ) to EnumValueOf, irBuiltIns.eqeqSymbol.toKey()!! to Equals(KtTokens.EQEQ), irBuiltIns.eqeqeqSymbol.toKey()!! to Equals(KtTokens.EQEQEQ), irBuiltIns.ieee754equalsFunByOperandType[irBuiltIns.floatClass]!!.toKey()!! to Ieee754Equals(Type.FLOAT_TYPE),