diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index b6f00c0de41..d0bfd7759cd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -168,6 +168,11 @@ public class AsmUtil { return Type.getType(internalName.substring(1)); } + @NotNull + public static Type getArrayType(@NotNull Type componentType) { + return Type.getType("[" + componentType.getDescriptor()); + } + @Nullable public static PrimitiveType asmPrimitiveTypeToLangPrimitiveType(Type type) { JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort()); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index dbfc4ac9cee..d1b31f4d980 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -239,12 +239,12 @@ public class InlineCodegen extends CallGenerator { assert resolvedCall != null : "Resolved call for " + functionDescriptor + " should be not null"; Map arguments = resolvedCall.getTypeArguments(); assert arguments.size() == 1 : "Resolved call for " + functionDescriptor + " should have 1 type argument"; - KotlinType type = arguments.values().iterator().next(); + MethodNode node = InlineCodegenUtil.createSpecialEnumMethodBody( codegen, functionDescriptor.getName().asString(), - type, + arguments.keySet().iterator().next().getDefaultType(), codegen.getState().getTypeMapper() ); return new SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java index a46c446468d..3c85c3b2d45 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.codegen.AsmUtil; import org.jetbrains.kotlin.codegen.ExpressionCodegen; import org.jetbrains.kotlin.codegen.MemberCodegen; import org.jetbrains.kotlin.codegen.binding.CodegenBinding; @@ -60,6 +61,9 @@ import java.io.StringWriter; import java.util.List; import java.util.ListIterator; +import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.ENUM_TYPE; +import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_CLASS_TYPE; + public class InlineCodegenUtil { public static final boolean GENERATE_SMAP = true; public static final int API = Opcodes.ASM5; @@ -530,7 +534,7 @@ public class InlineCodegenUtil { if (!(containingDeclaration instanceof PackageFragmentDescriptor)) { return false; } - if (!containingDeclaration.getName().equals(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) { + if (!((PackageFragmentDescriptor) containingDeclaration).getFqName().equals(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)) { return false; } if (functionDescriptor.getTypeParameters().size() != 1) { @@ -548,23 +552,30 @@ public class InlineCodegenUtil { @NotNull KotlinType type, @NotNull KotlinTypeMapper typeMapper ) { - boolean isEnumValues = "enumValues".equals(name); + boolean isValueOf = "enumValueOf".equals(name); Type invokeType = typeMapper.mapType(type); - String desc = getSpecialEnumFunDescriptor(invokeType, isEnumValues); - + String desc = getSpecialEnumFunDescriptor(invokeType, isValueOf); MethodNode node = new MethodNode(API, Opcodes.ACC_STATIC, "fake", desc, null, null); - if (!isEnumValues) { - node.visitVarInsn(Opcodes.ALOAD, 0); - } codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, new InstructionAdapter(node)); - node.visitMethodInsn(Opcodes.INVOKESTATIC, invokeType.getInternalName(), isEnumValues ? "values" : "valueOf", desc, false); + if (isValueOf) { + node.visitInsn(Opcodes.ACONST_NULL); + node.visitVarInsn(Opcodes.ALOAD, 0); + + node.visitMethodInsn(Opcodes.INVOKESTATIC, ENUM_TYPE.getInternalName(), "valueOf", + Type.getMethodDescriptor(ENUM_TYPE, JAVA_CLASS_TYPE, AsmTypes.JAVA_STRING_TYPE), false); + } + else { + node.visitInsn(Opcodes.ICONST_0); + node.visitTypeInsn(Opcodes.ANEWARRAY, ENUM_TYPE.getInternalName()); + } node.visitInsn(Opcodes.ARETURN); - node.visitMaxs(isEnumValues ? 2 : 3, isEnumValues ? 0 : 1); + node.visitMaxs(isValueOf ? 3 : 2, isValueOf ? 1 : 0); return node; } - public static String getSpecialEnumFunDescriptor(@NotNull Type type, boolean isEnumValues) { - return (isEnumValues ? "()[" : "(Ljava/lang/String;)") + "L" + type.getInternalName() + ";"; + @NotNull + public static String getSpecialEnumFunDescriptor(@NotNull Type type, boolean isValueOf) { + return isValueOf ? Type.getMethodDescriptor(type, AsmTypes.JAVA_STRING_TYPE) : Type.getMethodDescriptor(AsmUtil.getArrayType(type)); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index 4bf53467b17..7153bf15875 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -16,11 +16,13 @@ package org.jetbrains.kotlin.codegen.inline +import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.context.MethodContext import org.jetbrains.kotlin.codegen.generateAsCast import org.jetbrains.kotlin.codegen.generateIsCheck import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.common.intConstant +import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.Variance @@ -139,7 +141,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?) OperationKind.SAFE_AS -> processAs(insn, instructions, kotlinType, asmType, safe = true) OperationKind.IS -> processIs(insn, instructions, kotlinType, asmType) OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType) - OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, asmType) + OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType) }) { instructions.remove(insn.previous.previous!!) // PUSH operation ID instructions.remove(insn.previous!!) // PUSH type parameter @@ -221,12 +223,27 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?) return true } - private fun processSpecialEnumFunction(insn: MethodInsnNode, parameter: Type): Boolean { - val next = insn.next - if (next !is MethodInsnNode) return false - next.owner = parameter.internalName - next.desc = InlineCodegenUtil.getSpecialEnumFunDescriptor(parameter, "values" == next.name) - return true + private fun processSpecialEnumFunction(insn: MethodInsnNode, instructions: InsnList, parameter: Type): Boolean { + val next1 = insn.next ?: return false + val next2 = next1.next ?: return false + if (next1.opcode == Opcodes.ACONST_NULL && next2.opcode == Opcodes.ALOAD) { + val next3 = next2.next ?: return false + if (next3 is MethodInsnNode && next3.name == "valueOf") { + instructions.remove(next1) + next3.owner = parameter.internalName + next3.desc = InlineCodegenUtil.getSpecialEnumFunDescriptor(parameter, true) + return true + } + } + else if (next1.opcode == Opcodes.ICONST_0 && next2.opcode == Opcodes.ANEWARRAY) { + instructions.remove(next1) + instructions.remove(next2) + val desc = InlineCodegenUtil.getSpecialEnumFunDescriptor(parameter, false) + instructions.insert(insn, MethodInsnNode(Opcodes.INVOKESTATIC, parameter.internalName, "values", desc, false)) + return true + } + + return false } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index 1d1bf7ef197..979e7bc893a 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -29,6 +29,7 @@ public class AsmTypes { public static final Type JAVA_STRING_TYPE = getType(String.class); public static final Type JAVA_THROWABLE_TYPE = getType(Throwable.class); public static final Type JAVA_CLASS_TYPE = getType(Class.class); + public static final Type ENUM_TYPE = getType(Enum.class); public static final Type UNIT_TYPE = Type.getObjectType("kotlin/Unit"); diff --git a/compiler/testData/codegen/bytecodeText/inline/specialEnumFunction.kt b/compiler/testData/codegen/bytecodeText/inline/specialEnumFunction.kt new file mode 100644 index 00000000000..133b0853339 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inline/specialEnumFunction.kt @@ -0,0 +1,24 @@ +inline fun > myValues(): String { + val values = enumValues() + return "OK" +} + +inline fun > value(): String { + val values = enumValueOf("123") + return "OK" +} +enum class Z +fun main() { + myValues() + value() +} + +//2 reifiedOperationMarker +//1 INVOKESTATIC kotlin/jvm/internal/Intrinsics\.reifiedOperationMarker \(ILjava/lang/String;\)V\s*ICONST_0\s*ANEWARRAY java/lang/Enum +//1 INVOKESTATIC Z\.values \(\)\[LZ; + +//4 valueOf +//1 INVOKESTATIC kotlin/jvm/internal/Intrinsics\.reifiedOperationMarker \(ILjava/lang/String;\)V\s*ACONST_NULL\s*ALOAD 2\s*INVOKESTATIC java/lang/Enum\.valueOf \(Ljava/lang/Class;Ljava/lang/String;\)Ljava/lang/Enum; +//1 INVOKESTATIC Z\.valueOf \(Ljava/lang/String;\)LZ; +//1 public static valueOf +//2 INVOKESTATIC java/lang/Enum.valueOf \(Ljava/lang/Class;Ljava/lang/String;\)Ljava/lang/Enum; diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 78c4dd38de8..3373fab602e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1319,6 +1319,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("specialEnumFunction.kt") + public void testSpecialEnumFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/specialEnumFunction.kt"); + doTest(fileName); + } + @TestMetadata("splitedExceptionTable.kt") public void testSplitedExceptionTable() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/splitedExceptionTable.kt");