diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 17ba8ed6cf0..2bf0aec03df 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2656,6 +2656,15 @@ public class ExpressionCodegen extends KtVisitor impleme return cur; } + private boolean canSkipArrayCopyForSpreadArgument(KtExpression spreadArgument) { + ResolvedCall 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 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); } diff --git a/compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt b/compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt new file mode 100644 index 00000000000..6cc4d47dc23 --- /dev/null +++ b/compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt @@ -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 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(1)) + genericVararg(xs = *arrayOf(1)) + genericVararg(xs = *Array(1) { 1 }) + genericVararg(xs = *arrayOfNulls(1)) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/varargs/doNotCopyImmediatelyCreatedArrays.kt b/compiler/testData/codegen/bytecodeText/varargs/doNotCopyImmediatelyCreatedArrays.kt new file mode 100644 index 00000000000..fece3a4b4b6 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/varargs/doNotCopyImmediatelyCreatedArrays.kt @@ -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 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(1)) + genericVararg(xs = *arrayOf(1)) + genericVararg(xs = *Array(1) { 1 }) + genericVararg(xs = *arrayOfNulls(1)) +} + +// 0 copyOf +// 0 clone \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index da495a1c126..78a92cd8495 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 315fdb42ca4..70f29ac434a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 73879200d6f..86d8f514ed4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -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) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index f4f8af9a1e3..3effa38f59f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index bd63ea2bcd9..f32ad268026 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -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");