fix KT-6192: VerifyError when using spreads with primitive arrays

#KT-6192 Fixed
This commit is contained in:
Michael Nedzelsky
2014-12-23 20:09:50 +03:00
parent fb7fe81a85
commit eded72d633
7 changed files with 313 additions and 32 deletions
@@ -45,6 +45,7 @@ import org.jetbrains.jet.lang.types.Approximation;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypesPackage;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lang.types.lang.PrimitiveType;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
@@ -159,6 +160,12 @@ public class AsmUtil {
return Type.getType(internalName.substring(1));
}
@Nullable
public static PrimitiveType asmPrimitiveTypeToLangPrimitiveType(Type type) {
JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort());
return jvmPrimitiveType != null ? jvmPrimitiveType.getPrimitiveType() : null;
}
@NotNull
public static Method method(@NotNull String name, @NotNull Type returnType, @NotNull Type... parameterTypes) {
return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes));
@@ -2524,10 +2524,25 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
gen(arguments.get(0).getArgumentExpression(), type);
}
else {
String owner = "kotlin/jvm/internal/SpreadBuilder";
String owner;
String addDescriptor;
String toArrayDescriptor;
boolean arrayOfReferences = KotlinBuiltIns.isArray(outType);
if (arrayOfReferences) {
owner = "kotlin/jvm/internal/SpreadBuilder";
addDescriptor = "(Ljava/lang/Object;)V";
toArrayDescriptor = "([Ljava/lang/Object;)[Ljava/lang/Object;";
}
else {
String spreadBuilderClassName = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(elementType).getTypeName().getIdentifier() + "SpreadBuilder";
owner = "kotlin/jvm/internal/" + spreadBuilderClassName;
addDescriptor = "(" + elementType.getDescriptor() + ")V";
toArrayDescriptor = "()" + type.getDescriptor();
}
v.anew(Type.getObjectType(owner));
v.dup();
v.invokespecial(owner, "<init>", "()V", false);
v.iconst(size);
v.invokespecial(owner, "<init>", "(I)V", false);
for (int i = 0; i != size; ++i) {
v.dup();
ValueArgument argument = arguments.get(i);
@@ -2537,15 +2552,19 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
else {
gen(argument.getArgumentExpression(), elementType);
v.invokevirtual(owner, "add", "(Ljava/lang/Object;)Z", false);
v.pop();
v.invokevirtual(owner, "add", addDescriptor, false);
}
}
v.dup();
v.invokevirtual(owner, "size", "()I", false);
newArrayInstruction(outType);
v.invokevirtual(owner, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;", false);
v.checkcast(type);
if (arrayOfReferences) {
v.dup();
v.invokevirtual(owner, "size", "()I", false);
newArrayInstruction(outType);
v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
v.checkcast(type);
}
else {
v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
}
}
}
else {
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignature;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.lang.PrimitiveType;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Type;
@@ -1229,24 +1230,12 @@ public abstract class StackValue {
case Type.OBJECT:
case Type.ARRAY:
return OBJECT_REF_TYPE;
case Type.BYTE:
return Type.getObjectType("kotlin/jvm/internal/Ref$ByteRef");
case Type.SHORT:
return Type.getObjectType("kotlin/jvm/internal/Ref$ShortRef");
case Type.CHAR:
return Type.getObjectType("kotlin/jvm/internal/Ref$CharRef");
case Type.INT:
return Type.getObjectType("kotlin/jvm/internal/Ref$IntRef");
case Type.LONG:
return Type.getObjectType("kotlin/jvm/internal/Ref$LongRef");
case Type.BOOLEAN:
return Type.getObjectType("kotlin/jvm/internal/Ref$BooleanRef");
case Type.FLOAT:
return Type.getObjectType("kotlin/jvm/internal/Ref$FloatRef");
case Type.DOUBLE:
return Type.getObjectType("kotlin/jvm/internal/Ref$DoubleRef");
default:
throw new UnsupportedOperationException();
PrimitiveType primitiveType = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(type);
if (primitiveType == null) throw new UnsupportedOperationException();
String typeName = primitiveType.getTypeName().getIdentifier();
return Type.getObjectType("kotlin/jvm/internal/Ref$" + typeName + "Ref");
}
}
@@ -0,0 +1,93 @@
fun barB(vararg args: Byte) = args
fun barC(vararg args: Char) = args
fun barD(vararg args: Double) = args
fun barF(vararg args: Float) = args
fun barI(vararg args: Int) = args
fun barJ(vararg args: Long) = args
fun barS(vararg args: Short) = args
fun barZ(vararg args: Boolean) = args
fun sumInt(x: Int, vararg args: Int): Int {
var result = x
for(a in args) {
result += a
}
return result
}
fun sumFunOnParameters(x: Int, vararg args: Int, f: (Int) -> Int): Int {
var result = f(x)
for(a in args) {
result += f(a)
}
return result
}
fun concatParameters(vararg args: Int): String {
var result = ""
for(a in args) {
result += a.toString()
}
return result
}
fun box(): String {
val aB = ByteArray(3)
val aC = CharArray(3)
val aD = DoubleArray(3)
val aF = FloatArray(3)
val aI = IntArray(3)
aI[0] = 1
aI[1] = 2
aI[2] = 3
val bI = IntArray(2)
bI[0] = 4
bI[1] = 5
val aJ = LongArray(3)
val aS = ShortArray(3)
val aZ = BooleanArray(3)
if (barB(*aB, 23: Byte).size() != 4) return "fail: Byte"
if (barB(11: Byte, *aB, 23: Byte, *aB).size() != 8) return "fail: Byte"
if (barC(*aC, 'A').size() != 4) return "fail: Char"
if (barC('A', *aC, 'A', *aC).size() != 8) return "fail: Char"
if (barD(*aD, 2.3).size() != 4) return "fail: Double"
if (barD(*aD, *aD, 2.3).size() != 7) return "fail: Double"
if (barF(*aF, 2.3f).size() != 4) return "fail: Float"
if (barF(*aF, 2.3f, 1.1f).size() != 5) return "fail: Float"
if (barI(*aI, 23).size() != 4) return "fail: Int"
if (barI(11, 10, *aI, 23).size() != 6) return "fail: Int"
if (barI(100, *aI, *aI).size() != 7) return "fail: Int 3"
if (sumInt(100, *aI) != 106) return "fail: sumInt 1"
if (sumInt(100, *aI, 200) != 306) return "fail: sumInt 2"
if (sumInt(100, *aI, *aI) != 112) return "fail: sumInt 3"
if (sumFunOnParameters(100, *aI, 200) { 2*it } != 612) return "fail: sumFunOnParameters 1"
if (sumFunOnParameters(100, *aI, *aI) { 2*it } != 224) return "fail: sumFunOnParameters 2"
if (concatParameters(1,2,3) != "123") return "fail: concatParameters 1"
if (concatParameters(*aI) != "123") return "fail: concatParameters 2"
if (concatParameters(4, 5, *aI) != "45123") return "fail: concatParameters 3"
if (concatParameters(*aI, 4, 5) != "12345") return "fail: concatParameters 4"
if (concatParameters(*aI, *bI) != "12345") return "fail: concatParameters 5"
if (concatParameters(*aI, 7, 8, *bI) != "1237845") return "fail: concatParameters 6"
if (concatParameters(*aI, 7, *bI, *aI, 9) != "1237451239") return "fail: concatParameters 7"
if (barJ(*aJ, 23: Long).size() != 4) return "fail: Long"
if (barJ(*aJ, 23: Long, *aJ, *aJ).size() != 10) return "fail: Long"
if (barS(*aS, 23: Short).size() != 4) return "fail: Short"
if (barS(*aS, *aS, 23: Short, *aS).size() != 10) return "fail: Short"
if (barZ(*aZ, true).size() != 4) return "fail: Boolean"
if (barZ(false, *aZ, true, *aZ).size() != 8) return "fail: Boolean"
return "OK"
}
@@ -6874,6 +6874,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("kt6192.kt")
public void testKt6192() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/kt6192.kt");
doTest(fileName);
}
@TestMetadata("kt796_797.kt")
public void testKt796_797() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/kt796_797.kt");