From c71c344b8a46428174db59050f08a19a1fa3fd93 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 22 Feb 2016 16:53:55 +0300 Subject: [PATCH] Fix NCDFE on primitive iterators during boxing optimization The real fix is in ProgressionIteratorBasicValue's constructor, other changes are refactorings #KT-11153 Fixed --- .../kotlin/codegen/RangeCodegenUtil.java | 13 +++---- .../kotlin/codegen/intrinsics/IteratorNext.kt | 35 ++++++++++--------- .../boxing/ProgressionIteratorBasicValue.java | 28 +++++++-------- .../boxingOptimization/progressions.kt | 5 +++ 4 files changed, 40 insertions(+), 41 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/RangeCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/RangeCodegenUtil.java index de176ab0841..3a7aa46dc18 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/RangeCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/RangeCodegenUtil.java @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.types.KotlinType; +import java.util.Arrays; import java.util.List; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.RANGES_PACKAGE_FQ_NAME; @@ -38,15 +39,9 @@ public class RangeCodegenUtil { private static final ImmutableMap RANGE_TO_ELEMENT_TYPE; private static final ImmutableMap PROGRESSION_TO_ELEMENT_TYPE; - private static PrimitiveType[] supportedRangeTypes() { - return new PrimitiveType[] { - PrimitiveType.CHAR, - PrimitiveType.INT, - PrimitiveType.LONG, - // deprecated: - PrimitiveType.BYTE, - PrimitiveType.SHORT, - }; + @NotNull + public static List supportedRangeTypes() { + return Arrays.asList(PrimitiveType.CHAR, PrimitiveType.INT, PrimitiveType.LONG); } static { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IteratorNext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IteratorNext.kt index 1cbd5419b5a..42737865690 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IteratorNext.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IteratorNext.kt @@ -20,38 +20,39 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.Callable import org.jetbrains.kotlin.codegen.CallableMethod +import org.jetbrains.kotlin.fileClasses.internalNameWithoutInnerClasses import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter class IteratorNext : IntrinsicMethod() { - private fun getIteratorName(returnType: Type): String { - return when (returnType) { - Type.CHAR_TYPE -> "Char" - Type.BOOLEAN_TYPE -> "Boolean" - Type.BYTE_TYPE -> "Byte" - Type.SHORT_TYPE -> "Short" - Type.INT_TYPE -> "Int" - Type.LONG_TYPE -> "Long" - Type.FLOAT_TYPE -> "Float" - Type.DOUBLE_TYPE -> "Double" - else -> throw UnsupportedOperationException("Can't get correct name for iterator from type: " + returnType) - } - } - override fun toCallable(method: CallableMethod): Callable { val type = AsmUtil.unboxType(method.returnType) return object : IntrinsicCallable(type, listOf(), AsmTypes.OBJECT_TYPE, null) { override fun invokeIntrinsic(v: InstructionAdapter) { - val name = getIteratorName(returnType) + val primitiveClassName = getKotlinPrimitiveClassName(returnType) v.invokevirtual( - COLLECTIONS_PACKAGE_FQ_NAME.child(Name.identifier(name + "Iterator")) .asString().replace('.', '/'), - "next$name", + getPrimitiveIteratorType(primitiveClassName).internalName, + "next${primitiveClassName.asString()}", "()" + returnType.descriptor, false ) } } } + + companion object { + // Type.CHAR_TYPE -> "Char" + private fun getKotlinPrimitiveClassName(type: Type): Name { + return JvmPrimitiveType.get(type.className).primitiveType.typeName + } + + // "Char" -> type for kotlin.collections.CharIterator + fun getPrimitiveIteratorType(primitiveClassName: Name): Type { + val iteratorName = Name.identifier(primitiveClassName.asString() + "Iterator") + return Type.getObjectType(COLLECTIONS_PACKAGE_FQ_NAME.child(iteratorName).internalNameWithoutInnerClasses) + } + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/ProgressionIteratorBasicValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/ProgressionIteratorBasicValue.java index aae5e0c1cb6..3f6dc1b5c48 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/ProgressionIteratorBasicValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/ProgressionIteratorBasicValue.java @@ -18,6 +18,11 @@ package org.jetbrains.kotlin.codegen.optimization.boxing; import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.builtins.PrimitiveType; +import org.jetbrains.kotlin.codegen.RangeCodegenUtil; +import org.jetbrains.kotlin.codegen.intrinsics.IteratorNext; +import org.jetbrains.kotlin.name.Name; +import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; @@ -25,15 +30,11 @@ public class ProgressionIteratorBasicValue extends BasicValue { private final static ImmutableMap VALUES_TYPENAME_TO_TYPE; static { - VALUES_TYPENAME_TO_TYPE = ImmutableMap.builder(). - put("Byte", Type.BYTE_TYPE). - put("Char", Type.CHAR_TYPE). - put("Short", Type.SHORT_TYPE). - put("Int", Type.INT_TYPE). - put("Long", Type.LONG_TYPE). - put("Float", Type.FLOAT_TYPE). - put("Double", Type.DOUBLE_TYPE). - build(); + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (PrimitiveType primitiveType : RangeCodegenUtil.supportedRangeTypes()) { + builder.put(primitiveType.getTypeName().asString(), Type.getType(JvmPrimitiveType.get(primitiveType).getDesc())); + } + VALUES_TYPENAME_TO_TYPE = builder.build(); } @NotNull @@ -47,19 +48,16 @@ public class ProgressionIteratorBasicValue extends BasicValue { private final String valuesPrimitiveTypeName; public ProgressionIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) { - super(Type.getObjectType("kotlin/" + valuesPrimitiveTypeName + "Iterator")); + super(IteratorNext.Companion.getPrimitiveIteratorType(Name.identifier(valuesPrimitiveTypeName))); this.valuesPrimitiveType = getValuesType(valuesPrimitiveTypeName); this.valuesPrimitiveTypeName = valuesPrimitiveTypeName; } + @NotNull public Type getValuesPrimitiveType() { return valuesPrimitiveType; } - public String getValuesPrimitiveTypeName() { - return valuesPrimitiveTypeName; - } - @Override public boolean equals(Object o) { if (this == o) return true; @@ -75,7 +73,7 @@ public class ProgressionIteratorBasicValue extends BasicValue { @NotNull public String getNextMethodName() { - return "next" + getValuesPrimitiveTypeName(); + return "next" + valuesPrimitiveTypeName; } @NotNull diff --git a/compiler/testData/codegen/boxWithStdlib/boxingOptimization/progressions.kt b/compiler/testData/codegen/boxWithStdlib/boxingOptimization/progressions.kt index 7083ba63844..f57685da01e 100644 --- a/compiler/testData/codegen/boxWithStdlib/boxingOptimization/progressions.kt +++ b/compiler/testData/codegen/boxWithStdlib/boxingOptimization/progressions.kt @@ -23,6 +23,11 @@ fun box() : String { assertEquals(result7, 100) assertEquals(result8, 100) + val result9 = (0..10).reduce { total, next -> total + next } + val result10 = (0L..10L).reduce { total, next -> total + next } + assertEquals(result9, 55) + assertEquals(result10, 55L) + return "OK" }