Fix NCDFE on primitive iterators during boxing optimization
The real fix is in ProgressionIteratorBasicValue's constructor, other changes are refactorings #KT-11153 Fixed
This commit is contained in:
@@ -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<FqName, PrimitiveType> RANGE_TO_ELEMENT_TYPE;
|
||||
private static final ImmutableMap<FqName, PrimitiveType> 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<PrimitiveType> supportedRangeTypes() {
|
||||
return Arrays.asList(PrimitiveType.CHAR, PrimitiveType.INT, PrimitiveType.LONG);
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-15
@@ -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<String, Type> VALUES_TYPENAME_TO_TYPE;
|
||||
|
||||
static {
|
||||
VALUES_TYPENAME_TO_TYPE = ImmutableMap.<String, Type>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<String, Type> 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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user