Do not copy immediately created arrays in spread arguments
E.g., 'foo(x = *intArrayOf(42))'. #KT-20462 Fixed
This commit is contained in:
@@ -2656,6 +2656,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return cur;
|
||||
}
|
||||
|
||||
private boolean canSkipArrayCopyForSpreadArgument(KtExpression spreadArgument) {
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt.getResolvedCall(spreadArgument, bindingContext);
|
||||
if (resolvedCall == null) return false;
|
||||
|
||||
CallableDescriptor calleeDescriptor = resolvedCall.getResultingDescriptor();
|
||||
return (calleeDescriptor instanceof ConstructorDescriptor) ||
|
||||
CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall) ||
|
||||
(DescriptorUtils.getFqName(calleeDescriptor).asString().equals("kotlin.arrayOfNulls"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull KotlinType outType) {
|
||||
@@ -2678,10 +2687,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (size == 1) {
|
||||
Type arrayType = getArrayType(arrayOfReferences ? AsmTypes.OBJECT_TYPE : elementType);
|
||||
return StackValue.operation(type, adapter -> {
|
||||
gen(arguments.get(0).getArgumentExpression(), type);
|
||||
v.dup();
|
||||
v.arraylength();
|
||||
v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
|
||||
KtExpression spreadArgument = arguments.get(0).getArgumentExpression();
|
||||
gen(spreadArgument, type);
|
||||
if (!canSkipArrayCopyForSpreadArgument(spreadArgument)) {
|
||||
v.dup();
|
||||
v.arraylength();
|
||||
v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
|
||||
}
|
||||
if (arrayOfReferences) {
|
||||
v.checkcast(type);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
fun booleanVararg(vararg xs: Boolean) {
|
||||
if (xs.size != 1 && xs[0] != true) throw AssertionError()
|
||||
}
|
||||
|
||||
fun byteVararg(vararg xs: Byte) {
|
||||
if (xs.size != 1 && xs[0] != 1.toByte()) throw AssertionError()
|
||||
}
|
||||
|
||||
fun shortVararg(vararg xs: Short) {
|
||||
if (xs.size != 1 && xs[0] != 1.toShort()) throw AssertionError()
|
||||
}
|
||||
|
||||
fun intVararg(vararg xs: Int) {
|
||||
if (xs.size != 1 && xs[0] != 1) throw AssertionError()
|
||||
}
|
||||
|
||||
fun longVararg(vararg xs: Long) {
|
||||
if (xs.size != 1 && xs[0] != 1L) throw AssertionError()
|
||||
}
|
||||
|
||||
fun floatVararg(vararg xs: Float) {
|
||||
if (xs.size != 1 && xs[0] != 1.0f) throw AssertionError()
|
||||
}
|
||||
|
||||
fun doubleVararg(vararg xs: Double) {
|
||||
if (xs.size != 1 && xs[0] != 1.0) throw AssertionError()
|
||||
}
|
||||
|
||||
fun anyVararg(vararg xs: Any?) {
|
||||
if (xs.size != 1 && (xs[0] != 1 && xs[0] != null)) throw AssertionError()
|
||||
}
|
||||
|
||||
fun <T> genericVararg(vararg xs: T) {
|
||||
if (xs.size != 1 && (xs[0] != 1 && xs[0] != null)) throw AssertionError()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
booleanVararg(*booleanArrayOf(true))
|
||||
booleanVararg(*BooleanArray(1))
|
||||
booleanVararg(*BooleanArray(1) { true })
|
||||
booleanVararg(xs = *booleanArrayOf(true))
|
||||
booleanVararg(xs = *BooleanArray(1))
|
||||
booleanVararg(xs = *BooleanArray(1) { true })
|
||||
|
||||
byteVararg(*byteArrayOf(1))
|
||||
byteVararg(*ByteArray(1))
|
||||
byteVararg(*ByteArray(1) { 1 })
|
||||
byteVararg(xs = *byteArrayOf(1))
|
||||
byteVararg(xs = *ByteArray(1))
|
||||
byteVararg(xs = *ByteArray(1) { 1 })
|
||||
|
||||
shortVararg(*shortArrayOf(1))
|
||||
shortVararg(*ShortArray(1))
|
||||
shortVararg(*ShortArray(1) { 1 })
|
||||
shortVararg(xs = *shortArrayOf(1))
|
||||
shortVararg(xs = *ShortArray(1))
|
||||
shortVararg(xs = *ShortArray(1) { 1 })
|
||||
|
||||
intVararg(*intArrayOf(1))
|
||||
intVararg(*IntArray(1))
|
||||
intVararg(*IntArray(1) { 1 })
|
||||
intVararg(xs = *intArrayOf(1))
|
||||
intVararg(xs = *IntArray(1))
|
||||
intVararg(xs = *IntArray(1) { 1 })
|
||||
|
||||
longVararg(*longArrayOf(1L))
|
||||
longVararg(*LongArray(1))
|
||||
longVararg(*LongArray(1) { 1L })
|
||||
longVararg(xs = *longArrayOf(1L))
|
||||
longVararg(xs = *LongArray(1))
|
||||
longVararg(xs = *LongArray(1) { 1L })
|
||||
|
||||
floatVararg(*floatArrayOf(1.0f))
|
||||
floatVararg(*FloatArray(1))
|
||||
floatVararg(*FloatArray(1) { 1.0f })
|
||||
floatVararg(xs = *floatArrayOf(1.0f))
|
||||
floatVararg(xs = *FloatArray(1))
|
||||
floatVararg(xs = *FloatArray(1) { 1.0f })
|
||||
|
||||
doubleVararg(*doubleArrayOf(1.0))
|
||||
doubleVararg(*DoubleArray(1))
|
||||
doubleVararg(*DoubleArray(1) { 1.0 })
|
||||
doubleVararg(xs = *doubleArrayOf(1.0))
|
||||
doubleVararg(xs = *DoubleArray(1))
|
||||
doubleVararg(xs = *DoubleArray(1) { 1.0 })
|
||||
|
||||
anyVararg(*arrayOf(1))
|
||||
anyVararg(*Array(1) { 1 })
|
||||
anyVararg(*arrayOfNulls(1))
|
||||
anyVararg(xs = *arrayOf(1))
|
||||
anyVararg(xs = *Array(1) { 1 })
|
||||
anyVararg(xs = *arrayOfNulls(1))
|
||||
|
||||
genericVararg(*arrayOf(1))
|
||||
genericVararg(*Array(1) { 1 })
|
||||
genericVararg(*arrayOfNulls<Int>(1))
|
||||
genericVararg(xs = *arrayOf(1))
|
||||
genericVararg(xs = *Array(1) { 1 })
|
||||
genericVararg(xs = *arrayOfNulls<Int>(1))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
fun booleanVararg(vararg xs: Boolean) {}
|
||||
fun byteVararg(vararg xs: Byte) {}
|
||||
fun shortVararg(vararg xs: Short) {}
|
||||
fun intVararg(vararg xs: Int) {}
|
||||
fun longVararg(vararg xs: Long) {}
|
||||
fun floatVararg(vararg xs: Float) {}
|
||||
fun doubleVararg(vararg xs: Double) {}
|
||||
fun anyVararg(vararg xs: Any?) {}
|
||||
fun <T> genericVararg(vararg xs: T) {}
|
||||
|
||||
fun test() {
|
||||
booleanVararg(*booleanArrayOf(true))
|
||||
booleanVararg(*BooleanArray(1))
|
||||
booleanVararg(*BooleanArray(1) { true })
|
||||
booleanVararg(xs = *booleanArrayOf(true))
|
||||
booleanVararg(xs = *BooleanArray(1))
|
||||
booleanVararg(xs = *BooleanArray(1) { true })
|
||||
|
||||
byteVararg(*byteArrayOf(1))
|
||||
byteVararg(*ByteArray(1))
|
||||
byteVararg(*ByteArray(1) { 1 })
|
||||
byteVararg(xs = *byteArrayOf(1))
|
||||
byteVararg(xs = *ByteArray(1))
|
||||
byteVararg(xs = *ByteArray(1) { 1 })
|
||||
|
||||
shortVararg(*shortArrayOf(1))
|
||||
shortVararg(*ShortArray(1))
|
||||
shortVararg(*ShortArray(1) { 1 })
|
||||
shortVararg(xs = *shortArrayOf(1))
|
||||
shortVararg(xs = *ShortArray(1))
|
||||
shortVararg(xs = *ShortArray(1) { 1 })
|
||||
|
||||
intVararg(*intArrayOf(1))
|
||||
intVararg(*IntArray(1))
|
||||
intVararg(*IntArray(1) { 1 })
|
||||
intVararg(xs = *intArrayOf(1))
|
||||
intVararg(xs = *IntArray(1))
|
||||
intVararg(xs = *IntArray(1) { 1 })
|
||||
|
||||
longVararg(*longArrayOf(1L))
|
||||
longVararg(*LongArray(1))
|
||||
longVararg(*LongArray(1) { 1L })
|
||||
longVararg(xs = *longArrayOf(1L))
|
||||
longVararg(xs = *LongArray(1))
|
||||
longVararg(xs = *LongArray(1) { 1L })
|
||||
|
||||
floatVararg(*floatArrayOf(1.0f))
|
||||
floatVararg(*FloatArray(1))
|
||||
floatVararg(*FloatArray(1) { 1.0f })
|
||||
floatVararg(xs = *floatArrayOf(1.0f))
|
||||
floatVararg(xs = *FloatArray(1))
|
||||
floatVararg(xs = *FloatArray(1) { 1.0f })
|
||||
|
||||
doubleVararg(*doubleArrayOf(1.0))
|
||||
doubleVararg(*DoubleArray(1))
|
||||
doubleVararg(*DoubleArray(1) { 1.0 })
|
||||
doubleVararg(xs = *doubleArrayOf(1.0))
|
||||
doubleVararg(xs = *DoubleArray(1))
|
||||
doubleVararg(xs = *DoubleArray(1) { 1.0 })
|
||||
|
||||
anyVararg(*arrayOf(1))
|
||||
anyVararg(*Array(1) { 1 })
|
||||
anyVararg(*arrayOfNulls(1))
|
||||
anyVararg(xs = *arrayOf(1))
|
||||
anyVararg(xs = *Array(1) { 1 })
|
||||
anyVararg(xs = *arrayOfNulls(1))
|
||||
|
||||
genericVararg(*arrayOf(1))
|
||||
genericVararg(*Array(1) { 1 })
|
||||
genericVararg(*arrayOfNulls<Int>(1))
|
||||
genericVararg(xs = *arrayOf(1))
|
||||
genericVararg(xs = *Array(1) { 1 })
|
||||
genericVararg(xs = *arrayOfNulls<Int>(1))
|
||||
}
|
||||
|
||||
// 0 copyOf
|
||||
// 0 clone
|
||||
+6
@@ -19688,6 +19688,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("doNotCopyImmediatelyCreatedArrays.kt")
|
||||
public void testDoNotCopyImmediatelyCreatedArrays() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt1978.kt")
|
||||
public void testKt1978() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/kt1978.kt");
|
||||
|
||||
@@ -19688,6 +19688,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("doNotCopyImmediatelyCreatedArrays.kt")
|
||||
public void testDoNotCopyImmediatelyCreatedArrays() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt1978.kt")
|
||||
public void testKt1978() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/kt1978.kt");
|
||||
|
||||
@@ -2202,6 +2202,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/varargs")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Varargs extends AbstractBytecodeTextTest {
|
||||
public void testAllFilesPresentInVarargs() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/varargs"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("doNotCopyImmediatelyCreatedArrays.kt")
|
||||
public void testDoNotCopyImmediatelyCreatedArrays() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/varargs/doNotCopyImmediatelyCreatedArrays.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/when")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -19688,6 +19688,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("doNotCopyImmediatelyCreatedArrays.kt")
|
||||
public void testDoNotCopyImmediatelyCreatedArrays() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt1978.kt")
|
||||
public void testKt1978() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/kt1978.kt");
|
||||
|
||||
@@ -23666,6 +23666,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("doNotCopyImmediatelyCreatedArrays.kt")
|
||||
public void testDoNotCopyImmediatelyCreatedArrays() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt1978.kt")
|
||||
public void testKt1978() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/vararg/kt1978.kt");
|
||||
|
||||
Reference in New Issue
Block a user