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:
Dmitry Petrov
2021-04-13 14:35:18 +03:00
committed by TeamCityServer
parent 334d0a8b5a
commit 7d62f0b5aa
10 changed files with 192 additions and 23 deletions
@@ -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)
}
}