JVM_IR KT-45187 use Arrays.copyOf to copy an array in spread operator
Creating a new array (and copying data into it with System.arraycopy) doesn't work in generic case, because the actual array class depends on call site.
This commit is contained in:
committed by
TeamCityServer
parent
334d0a8b5a
commit
7d62f0b5aa
+6
@@ -40940,6 +40940,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/vararg/kt37779.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt45187.kt")
|
||||
public void testKt45187() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/vararg/kt45187.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt581.kt")
|
||||
public void testKt581() throws Exception {
|
||||
|
||||
@@ -204,6 +204,15 @@ open class BuiltinSymbolsBase(protected val irBuiltIns: IrBuiltIns, protected va
|
||||
val doubleArray = primitiveArrayClass(PrimitiveType.DOUBLE)
|
||||
val booleanArray = primitiveArrayClass(PrimitiveType.BOOLEAN)
|
||||
|
||||
val byteArrayType get() = byteArray.owner.defaultType
|
||||
val charArrayType get() = charArray.owner.defaultType
|
||||
val shortArrayType get() = shortArray.owner.defaultType
|
||||
val intArrayType get() = intArray.owner.defaultType
|
||||
val longArrayType get() = longArray.owner.defaultType
|
||||
val floatArrayType get() = floatArray.owner.defaultType
|
||||
val doubleArrayType get() = doubleArray.owner.defaultType
|
||||
val booleanArrayType get() = booleanArray.owner.defaultType
|
||||
|
||||
val unsignedArrays = UnsignedType.values().mapNotNull { unsignedType ->
|
||||
unsignedArrayClass(unsignedType)?.let { unsignedType to it }
|
||||
}.toMap()
|
||||
|
||||
@@ -23,12 +23,12 @@ import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
|
||||
@@ -51,6 +51,7 @@ class JvmSymbols(
|
||||
private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions"))
|
||||
private val kotlinReflectPackage: IrPackageFragment = createPackage(FqName("kotlin.reflect"))
|
||||
private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
|
||||
private val javaUtilPackage: IrPackageFragment = createPackage(FqName("java.util"))
|
||||
|
||||
// Special package for functions representing dynamic symbols referenced by 'INVOKEDYNAMIC' instruction - e.g.,
|
||||
// 'get(Ljava/lang/String;)Ljava/util/function/Supplier;'
|
||||
@@ -90,6 +91,7 @@ class JvmSymbols(
|
||||
"kotlin.jvm" -> kotlinJvmPackage
|
||||
"kotlin.reflect" -> kotlinReflectPackage
|
||||
"java.lang" -> javaLangPackage
|
||||
"java.util" -> javaUtilPackage
|
||||
else -> error("Other packages are not supported yet: $fqName")
|
||||
}
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
@@ -548,6 +550,7 @@ class JvmSymbols(
|
||||
}.symbol
|
||||
|
||||
val arrayOfAnyType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyType)
|
||||
val arrayOfAnyNType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType)
|
||||
|
||||
// Intrinsic to represent closure creation using INVOKEDYNAMIC with LambdaMetafactory.{metafactory, altMetafactory}
|
||||
// as a bootstrap method.
|
||||
@@ -742,13 +745,40 @@ class JvmSymbols(
|
||||
}
|
||||
}
|
||||
|
||||
private val systemClass: IrClassSymbol = createClass(FqName("java.lang.System")) { klass ->
|
||||
klass.addFunction("arraycopy", irBuiltIns.unitType, isStatic = true).apply {
|
||||
addValueParameter("src", irBuiltIns.anyNType)
|
||||
addValueParameter("srcPos", irBuiltIns.intType)
|
||||
addValueParameter("dest", irBuiltIns.anyNType)
|
||||
addValueParameter("destPos", irBuiltIns.intType)
|
||||
addValueParameter("length", irBuiltIns.intType)
|
||||
private val arraysCopyOfFunctions = HashMap<IrSimpleType, IrSimpleFunction>()
|
||||
|
||||
private fun IrClass.addArraysCopyOfFunction(arrayType: IrSimpleType) {
|
||||
addFunction("copyOf", arrayType, isStatic = true).apply {
|
||||
addValueParameter("original", arrayType)
|
||||
addValueParameter("newLength", irBuiltIns.intType)
|
||||
arraysCopyOfFunctions[arrayType] = this
|
||||
}
|
||||
}
|
||||
|
||||
val arraysClass: IrClassSymbol =
|
||||
createClass(FqName("java.util.Arrays")) { irClass ->
|
||||
irClass.addArraysCopyOfFunction(booleanArrayType)
|
||||
irClass.addArraysCopyOfFunction(byteArrayType)
|
||||
irClass.addArraysCopyOfFunction(charArrayType)
|
||||
irClass.addArraysCopyOfFunction(shortArrayType)
|
||||
irClass.addArraysCopyOfFunction(intArrayType)
|
||||
irClass.addArraysCopyOfFunction(longArrayType)
|
||||
irClass.addArraysCopyOfFunction(floatArrayType)
|
||||
irClass.addArraysCopyOfFunction(doubleArrayType)
|
||||
|
||||
// public static <T> T[] copyOf(T[] original, int newLength)
|
||||
irClass.addArraysCopyOfFunction(arrayOfAnyNType)
|
||||
}
|
||||
|
||||
fun getArraysCopyOfFunction(arrayType: IrSimpleType): IrSimpleFunctionSymbol {
|
||||
val copyOf = arraysCopyOfFunctions[arrayType]
|
||||
return when {
|
||||
copyOf != null ->
|
||||
copyOf.symbol
|
||||
arrayType.classifierOrFail == array ->
|
||||
arraysCopyOfFunctions[arrayOfAnyNType]!!.symbol
|
||||
else ->
|
||||
throw AssertionError("Array type expected: ${arrayType.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,8 +828,6 @@ class JvmSymbols(
|
||||
val remainderUnsignedLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("remainderUnsigned")
|
||||
val toUnsignedStringLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("toUnsignedString")
|
||||
|
||||
val systemArraycopy: IrSimpleFunctionSymbol = systemClass.functionByName("arraycopy")
|
||||
|
||||
val signatureStringIntrinsic: IrSimpleFunctionSymbol =
|
||||
irFactory.buildFun {
|
||||
name = Name.special("<signature-string>")
|
||||
|
||||
@@ -11,10 +11,7 @@ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.getArrayElementType
|
||||
import org.jetbrains.kotlin.ir.types.isBoxedArray
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.getPropertyGetter
|
||||
@@ -105,16 +102,12 @@ class IrArrayBuilder(val builder: JvmIrBuilder, val arrayType: IrType) {
|
||||
return builder.irBlock {
|
||||
val spreadVar = if (spread is IrGetValue) spread.symbol.owner else irTemporary(spread)
|
||||
val size = unwrappedArrayType.classOrNull!!.getPropertyGetter("size")!!
|
||||
fun getSize() = irCall(size).apply { dispatchReceiver = irGet(spreadVar) }
|
||||
val result = irTemporary(newArray(getSize()))
|
||||
+irCall(builder.irSymbols.systemArraycopy).apply {
|
||||
val arrayCopyOf = builder.irSymbols.getArraysCopyOfFunction(unwrappedArrayType as IrSimpleType)
|
||||
// TODO consider using System.arraycopy if the requested array type is non-generic.
|
||||
+irCall(arrayCopyOf).apply {
|
||||
putValueArgument(0, coerce(irGet(spreadVar), unwrappedArrayType))
|
||||
putValueArgument(1, irInt(0))
|
||||
putValueArgument(2, irGet(result))
|
||||
putValueArgument(3, irInt(0))
|
||||
putValueArgument(4, getSize())
|
||||
putValueArgument(1, irCall(size).apply { dispatchReceiver = irGet(spreadVar) })
|
||||
}
|
||||
+irGet(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
fun box(): String =
|
||||
object : A<Void, Void>() {
|
||||
override fun f(vararg params: Void): Void? = null
|
||||
}.execute()
|
||||
|
||||
abstract class A<P, R> {
|
||||
protected abstract fun f(vararg params: P): R?
|
||||
|
||||
fun execute(vararg params: P): String =
|
||||
if (f(*params) == null) "OK" else "Fail"
|
||||
}
|
||||
+49
-1
@@ -8,7 +8,15 @@ fun <T> copyArray(vararg data: T): Array<out T> = data
|
||||
|
||||
inline fun <reified T> reifiedCopyArray(vararg data: T): Array<out T> = data
|
||||
|
||||
fun copyBooleanArray(vararg data: Boolean): BooleanArray = data
|
||||
fun copyByteArray(vararg data: Byte): ByteArray = data
|
||||
fun copyCharArray(vararg data: Char): CharArray = data
|
||||
fun copyShortArray(vararg data: Short): ShortArray = data
|
||||
fun copyIntArray(vararg data: Int): IntArray = data
|
||||
fun copyLongArray(vararg data: Long): LongArray = data
|
||||
fun copyFloatArray(vararg data: Float): FloatArray = data
|
||||
fun copyDoubleArray(vararg data: Double): DoubleArray = data
|
||||
fun copyStringArray(vararg data: String): Array<out String> = data
|
||||
|
||||
fun box(): String {
|
||||
val sarr = arrayOf("OK")
|
||||
@@ -21,11 +29,51 @@ fun box(): String {
|
||||
rsarr[0] = "Array was not copied"
|
||||
assertEquals(rsarr2[0], "OK", "Failed: Array<String>, reified copy")
|
||||
|
||||
val boolArray = booleanArrayOf(true)
|
||||
val boolArray2 = copyBooleanArray(*boolArray)
|
||||
boolArray[0] = false
|
||||
assertEquals(boolArray2[0], true, "Failed: BooleanArray")
|
||||
|
||||
val byteArray = byteArrayOf(1)
|
||||
val byteArray2 = copyByteArray(*byteArray)
|
||||
byteArray[0] = 42
|
||||
assertEquals(1, byteArray2[0], "Failed: ByteArray")
|
||||
|
||||
val charArray = charArrayOf('a')
|
||||
val charArray2 = copyCharArray(*charArray)
|
||||
charArray[0] = 'b'
|
||||
assertEquals(charArray2[0], 'a', "Failed: CharArray")
|
||||
|
||||
val shortArray = shortArrayOf(1)
|
||||
val shortArray2 = copyShortArray(*shortArray)
|
||||
shortArray[0] = 42
|
||||
assertEquals(1, shortArray2[0], "Failed: ShortArray")
|
||||
|
||||
val iarr = IntArray(1)
|
||||
iarr[0] = 1
|
||||
val iarr2 = copyIntArray(*iarr)
|
||||
iarr[0] = 42
|
||||
assertEquals(iarr2[0], 1, "Failed: IntArray")
|
||||
assertEquals(1, iarr2[0], "Failed: IntArray")
|
||||
|
||||
val longArray = longArrayOf(1L)
|
||||
val longArray2 = copyLongArray(*longArray)
|
||||
longArray[0] = 42L
|
||||
assertEquals(1L, longArray2[0], "Failed: LongArray")
|
||||
|
||||
val floatArray = floatArrayOf(1.0f)
|
||||
val floatArray2 = copyFloatArray(*floatArray)
|
||||
floatArray[0] = 42.0f
|
||||
assertEquals(1.0f, floatArray2[0], "Failed: FloatArray")
|
||||
|
||||
val doubleArray = doubleArrayOf(1.0)
|
||||
val doubleArray2 = copyDoubleArray(*doubleArray)
|
||||
doubleArray[0] = 42.0
|
||||
assertEquals(1.0, doubleArray2[0], "Failed: DoubleArray")
|
||||
|
||||
val stringArray = arrayOf("abc")
|
||||
val stringArray2 = copyStringArray(*stringArray)
|
||||
stringArray[0] = "def"
|
||||
assertEquals("abc", stringArray2[0], "Failed: Array<String>")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
FILE fqName:<root> fileName:/kt45853.kt
|
||||
CLASS CLASS name:A modality:ABSTRACT visibility:public superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.A
|
||||
CONSTRUCTOR visibility:public <> () returnType:<root>.A [primary]
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:A modality:ABSTRACT visibility:public superTypes:[kotlin.Any]'
|
||||
PROPERTY name:a visibility:public modality:ABSTRACT [val]
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-a> visibility:public modality:ABSTRACT <> ($this:<root>.A) returnType:<root>.A?
|
||||
correspondingProperty: PROPERTY name:a visibility:public modality:ABSTRACT [val]
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.A
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
|
||||
overridden:
|
||||
public open fun hashCode (): kotlin.Int declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
|
||||
overridden:
|
||||
public open fun toString (): kotlin.String declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
CLASS CLASS name:B modality:FINAL visibility:public superTypes:[<root>.AX]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.B
|
||||
CONSTRUCTOR visibility:public <> () returnType:<root>.B [primary]
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.AX'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:B modality:FINAL visibility:public superTypes:[<root>.AX]'
|
||||
FUN name:getA visibility:public modality:FINAL <> ($this:<root>.B) returnType:<root>.X?
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.B
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun getA (): <root>.X? declared in <root>.B'
|
||||
CALL 'public open fun <get-a> (): @[FlexibleNullability] <root>.AX? declared in <root>.AX' superQualifier='CLASS IR_EXTERNAL_JAVA_DECLARATION_STUB CLASS name:AX modality:ABSTRACT visibility:public superTypes:[<root>.A; <root>.X]' type=@[FlexibleNullability] <root>.AX? origin=GET_PROPERTY
|
||||
$this: GET_VAR '<this>: <root>.B declared in <root>.B.getA' type=<root>.B origin=null
|
||||
PROPERTY FAKE_OVERRIDE name:a visibility:public modality:OPEN [fake_override,val]
|
||||
FUN FAKE_OVERRIDE name:<get-a> visibility:public modality:OPEN <> ($this:<root>.AX) returnType:@[FlexibleNullability] <root>.AX? [fake_override]
|
||||
correspondingProperty: PROPERTY FAKE_OVERRIDE name:a visibility:public modality:OPEN [fake_override,val]
|
||||
overridden:
|
||||
public open fun <get-a> (): @[FlexibleNullability] <root>.AX? declared in <root>.AX
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.AX
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in <root>.AX
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
|
||||
overridden:
|
||||
public open fun hashCode (): kotlin.Int [fake_override] declared in <root>.AX
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
|
||||
overridden:
|
||||
public open fun toString (): kotlin.String [fake_override] declared in <root>.AX
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
+6
@@ -40922,6 +40922,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/vararg/kt37779.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt45187.kt")
|
||||
public void testKt45187() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/vararg/kt45187.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt581.kt")
|
||||
public void testKt581() throws Exception {
|
||||
|
||||
+6
@@ -40940,6 +40940,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/vararg/kt37779.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt45187.kt")
|
||||
public void testKt45187() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/vararg/kt45187.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt581.kt")
|
||||
public void testKt581() throws Exception {
|
||||
|
||||
+5
@@ -32907,6 +32907,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/vararg/kt37779.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt45187.kt")
|
||||
public void testKt45187() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/vararg/kt45187.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt581.kt")
|
||||
public void testKt581() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/vararg/kt581.kt");
|
||||
|
||||
Reference in New Issue
Block a user