IR: make vararg lowering more specific in array type creation (e.g. instaed of Array<Int> use IntArray)
This commit is contained in:
committed by
vvlevchenko
parent
1eebae5c4e
commit
be75e1bce9
+70
-28
@@ -1,13 +1,12 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.lower
|
package org.jetbrains.kotlin.backend.konan.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
|
||||||
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
|
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanPlatform
|
import org.jetbrains.kotlin.backend.konan.KonanPlatform
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.ir2string
|
import org.jetbrains.kotlin.backend.konan.ir.ir2string
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering.Companion.kIntType
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
@@ -16,7 +15,8 @@ import org.jetbrains.kotlin.ir.expressions.*
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
@@ -59,7 +59,6 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
|
|||||||
|
|
||||||
private fun blockPerVararg(expression: IrCall, owner: FunctionDescriptor): Map<ValueParameterDescriptor, IrBlock> {
|
private fun blockPerVararg(expression: IrCall, owner: FunctionDescriptor): Map<ValueParameterDescriptor, IrBlock> {
|
||||||
val varargArgs = mutableMapOf<ValueParameterDescriptor, IrBlock>()
|
val varargArgs = mutableMapOf<ValueParameterDescriptor, IrBlock>()
|
||||||
val arrayConstructor = kArrayType.constructors.find { it.valueParameters.size == 1 }!!
|
|
||||||
val scope = owner.scope()
|
val scope = owner.scope()
|
||||||
val calleeDescriptor = expression.descriptor
|
val calleeDescriptor = expression.descriptor
|
||||||
calleeDescriptor.valueParameters
|
calleeDescriptor.valueParameters
|
||||||
@@ -73,10 +72,12 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
|
|||||||
log("skipped vararg expression because it's string array literal")
|
log("skipped vararg expression because it's string array literal")
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
val block = irBlock(kArrayType.defaultType)
|
val arrayHandle = arrayType(type)
|
||||||
|
val arrayConstructor = arrayHandle.arrayDescriptor.constructors.find { it.valueParameters.size == 1 }!!
|
||||||
|
val block = irBlock(arrayHandle.arrayDescriptor.defaultType)
|
||||||
val arrayConstructorCall = irCall(
|
val arrayConstructorCall = irCall(
|
||||||
descriptor = arrayConstructor,
|
descriptor = arrayConstructor,
|
||||||
typeArguments = mapOf(arrayConstructor.typeParameters[0] to type))
|
typeArguments = typeArgument(arrayConstructor, type))
|
||||||
|
|
||||||
if (parameterExpression == null) {
|
if (parameterExpression == null) {
|
||||||
arrayConstructorCall.putValueArgument(0, kIntZero)
|
arrayConstructorCall.putValueArgument(0, kIntZero)
|
||||||
@@ -90,7 +91,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
|
|||||||
block.statements.add(initVar)
|
block.statements.add(initVar)
|
||||||
it to initVar
|
it to initVar
|
||||||
}.toMap()
|
}.toMap()
|
||||||
arrayConstructorCall.putValueArgument(0, calculateArraySize(hasSpreadElement, scope, parameterExpression, vars))
|
arrayConstructorCall.putValueArgument(0, calculateArraySize(arrayHandle, hasSpreadElement, scope, parameterExpression, vars))
|
||||||
val arrayTmpVariable = scope.createTemporaryVariable(arrayConstructorCall, "__array\$", true)
|
val arrayTmpVariable = scope.createTemporaryVariable(arrayConstructorCall, "__array\$", true)
|
||||||
val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "__index\$", true)
|
val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "__index\$", true)
|
||||||
block.statements.add(arrayTmpVariable)
|
block.statements.add(arrayTmpVariable)
|
||||||
@@ -103,7 +104,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
|
|||||||
val dst = vars[element]!!
|
val dst = vars[element]!!
|
||||||
if (element !is IrSpreadElement) {
|
if (element !is IrSpreadElement) {
|
||||||
val setArrayElementCall = irCall(
|
val setArrayElementCall = irCall(
|
||||||
descriptor = kArraySetFunctionDescriptor,
|
descriptor = arrayHandle.setMethodDescriptor,
|
||||||
typeArguments = null
|
typeArguments = null
|
||||||
)
|
)
|
||||||
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.descriptor)
|
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.descriptor)
|
||||||
@@ -114,9 +115,9 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
|
|||||||
block.statements.add(incrementVariable(indexTmpVariable.descriptor, kIntOne))
|
block.statements.add(incrementVariable(indexTmpVariable.descriptor, kIntOne))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(irGet(dst.descriptor)), "__length\$")
|
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst.descriptor)), "__length\$")
|
||||||
block.statements.add(arraySizeVariable)
|
block.statements.add(arraySizeVariable)
|
||||||
val copyCall = irCall(kCopyRangeToDescriptor, null).apply {
|
val copyCall = irCall(arrayHandle.copyRangeToDescriptor, null).apply {
|
||||||
extensionReceiver = irGet(dst.descriptor)
|
extensionReceiver = irGet(dst.descriptor)
|
||||||
putValueArgument(0, irGet(arrayTmpVariable.descriptor)) /* destination */
|
putValueArgument(0, irGet(arrayTmpVariable.descriptor)) /* destination */
|
||||||
putValueArgument(1, kIntZero) /* fromIndex */
|
putValueArgument(1, kIntZero) /* fromIndex */
|
||||||
@@ -138,6 +139,26 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
|
|||||||
return varargArgs
|
return varargArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun typeArgument(arrayConstructor: ClassConstructorDescriptor, type: KotlinType):Map<TypeParameterDescriptor, KotlinType>? {
|
||||||
|
return if (!arrayConstructor.typeParameters.isEmpty())
|
||||||
|
mapOf(arrayConstructor.typeParameters.first() to type)
|
||||||
|
else
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun arrayType(type: KotlinType): ArrayHandle {
|
||||||
|
return when {
|
||||||
|
KotlinBuiltIns.isByte(type) -> kByteArrayHandler
|
||||||
|
KotlinBuiltIns.isShort(type) -> kShortArrayHandler
|
||||||
|
KotlinBuiltIns.isChar(type) -> kCharArrayHandler
|
||||||
|
KotlinBuiltIns.isInt(type) -> kIntArrayHandler
|
||||||
|
KotlinBuiltIns.isLong(type) -> kLongArrayHandler
|
||||||
|
KotlinBuiltIns.isFloat(type) -> kFloatArrayHandler
|
||||||
|
KotlinBuiltIns.isDouble(type) -> kDoubleArrayHandler
|
||||||
|
else -> kArrayHandler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Offset.intPlus() = irCall(kIntPlusDescriptor, null)
|
private fun Offset.intPlus() = irCall(kIntPlusDescriptor, null)
|
||||||
private fun Offset.increment(expression: IrExpression, value: IrExpression): IrExpression {
|
private fun Offset.increment(expression: IrExpression, value: IrExpression): IrExpression {
|
||||||
return intPlus().apply {
|
return intPlus().apply {
|
||||||
@@ -152,22 +173,22 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
|
|||||||
putValueArgument(0, value)
|
putValueArgument(0, value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
private fun calculateArraySize(hasSpreadElement: Boolean, scope:Scope, expression: IrVararg, vars: Map<IrVarargElement, IrVariable>): IrExpression? {
|
private fun calculateArraySize(arrayHandle: ArrayHandle, hasSpreadElement: Boolean, scope:Scope, expression: IrVararg, vars: Map<IrVarargElement, IrVariable>): IrExpression? {
|
||||||
offset(expression, scope) {
|
offset(expression, scope) {
|
||||||
if (!hasSpreadElement)
|
if (!hasSpreadElement)
|
||||||
return irConstInt(expression.elements.size)
|
return irConstInt(expression.elements.size)
|
||||||
val notSpreadElementCount = expression.elements.filter { it !is IrSpreadElement}.size
|
val notSpreadElementCount = expression.elements.filter { it !is IrSpreadElement}.size
|
||||||
val initialValue = irConstInt(notSpreadElementCount) as IrExpression
|
val initialValue = irConstInt(notSpreadElementCount) as IrExpression
|
||||||
return vars.filter{it.key is IrSpreadElement}.toList().fold( initial = initialValue) { result, it ->
|
return vars.filter{it.key is IrSpreadElement}.toList().fold( initial = initialValue) { result, it ->
|
||||||
val arraySize = irArraySize(irGet(it.second.descriptor))
|
val arraySize = irArraySize(arrayHandle, irGet(it.second.descriptor))
|
||||||
increment(result, arraySize)
|
increment(result, arraySize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Offset.irArraySize(expression: IrExpression): IrExpression {
|
private fun Offset.irArraySize(arrayHandle: ArrayHandle, expression: IrExpression): IrExpression {
|
||||||
val arraySize = irCall((kArraySizeFunctionDescriptor as PropertyDescriptor).getter as FunctionDescriptor, null).apply {
|
val arraySize = irCall((arrayHandle.sizeDescriptor as PropertyDescriptor).getter as FunctionDescriptor, null).apply {
|
||||||
dispatchReceiver = expression
|
dispatchReceiver = expression
|
||||||
}
|
}
|
||||||
return arraySize
|
return arraySize
|
||||||
@@ -180,24 +201,45 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
|
|||||||
context.log("VARARG-INJECTOR: $msg")
|
context.log("VARARG-INJECTOR: $msg")
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
data class ArrayHandle(val arrayDescriptor:ClassDescriptor,
|
||||||
val kArrayType = KonanPlatform.builtIns.array
|
val setMethodDescriptor: FunctionDescriptor,
|
||||||
val kCollectionsPackageDescriptor = KonanPlatform.builtIns.builtInsModule.getPackage(FqName("kotlin.collections")).memberScope
|
val sizeDescriptor:DeclarationDescriptor,
|
||||||
val kCopyRangeToDescriptor = DescriptorUtils.getAllDescriptors(kCollectionsPackageDescriptor).filter {
|
val copyRangeToDescriptor:FunctionDescriptor)
|
||||||
it.name.asString() == "copyRangeTo"
|
val kKotlinPackage = context.builtIns.builtInsModule.getPackage(FqName("kotlin"))
|
||||||
&& DescriptorUtils.getClassDescriptorForType((it as FunctionDescriptor).extensionReceiverParameter!!.type) == kArrayType}.first() as CallableDescriptor
|
val kByteArrayHandler = handle(arrayClassDescriptor("ByteArray"))
|
||||||
val unsubstitutedMemberScope = kArrayType.unsubstitutedMemberScope
|
val kCharArrayHandler = handle(arrayClassDescriptor("CharArray"))
|
||||||
val kArraySetFunctionDescriptor = DescriptorUtils.getFunctionByName(unsubstitutedMemberScope, Name.identifier("set"))
|
val kShortArrayHandler = handle(arrayClassDescriptor("ShortArray"))
|
||||||
val kArraySizeFunctionDescriptor = DescriptorUtils.getAllDescriptors(unsubstitutedMemberScope).find { it.name.asString() == "size" }
|
val kIntArrayHandler = handle(arrayClassDescriptor("IntArray"))
|
||||||
val kInt = KonanPlatform.builtIns.int
|
val kLongArrayHandler = handle(arrayClassDescriptor("LongArray"))
|
||||||
val kIntType = KonanPlatform.builtIns.intType
|
val kFloatArrayHandler = handle(arrayClassDescriptor("FloatArray"))
|
||||||
val kIntPlusDescriptor = DescriptorUtils.getAllDescriptors(kInt.unsubstitutedMemberScope).find {
|
val kDoubleArrayHandler = handle(arrayClassDescriptor("DoubleArray"))
|
||||||
|
val kArrayHandler = handle(context.builtIns.array)
|
||||||
|
|
||||||
|
val kInt = context.builtIns.int
|
||||||
|
val kIntType = context.builtIns.intType
|
||||||
|
val kIntPlusDescriptor = DescriptorUtils.getAllDescriptors(kInt.unsubstitutedMemberScope).find {
|
||||||
it.name.asString() == "plus"
|
it.name.asString() == "plus"
|
||||||
&& (it as FunctionDescriptor).valueParameters[0].type == kIntType} as FunctionDescriptor
|
&& (it as FunctionDescriptor).valueParameters[0].type == kIntType} as FunctionDescriptor
|
||||||
|
|
||||||
|
private fun handle(descriptor:ClassDescriptor) = ArrayHandle(
|
||||||
|
arrayDescriptor = descriptor,
|
||||||
|
setMethodDescriptor = setMethodDescriptor(descriptor),
|
||||||
|
sizeDescriptor = sizeMethodDescriptor(descriptor)!!,
|
||||||
|
copyRangeToDescriptor = copyRangeToFunctionDescriptor(descriptor))
|
||||||
|
|
||||||
|
private fun copyRangeToFunctionDescriptor(descriptor:ClassDescriptor):FunctionDescriptor {
|
||||||
|
val packageViewDescriptor = KonanPlatform.builtIns.builtInsModule.getPackage(FqName("kotlin.collections"))
|
||||||
|
return packageViewDescriptor.memberScope.getContributedFunctions(Name.identifier("copyRangeTo"), NoLookupLocation.FROM_BACKEND).filter {
|
||||||
|
it.extensionReceiverParameter != null && DescriptorUtils.getClassDescriptorForType(it.extensionReceiverParameter!!.type) == descriptor
|
||||||
|
}.first()
|
||||||
}
|
}
|
||||||
|
private fun setMethodDescriptor(descriptor:ClassDescriptor) = methodDescriptor(descriptor, "set")
|
||||||
|
private fun sizeMethodDescriptor(descriptor:ClassDescriptor) = descriptor(descriptor, "size")
|
||||||
|
private fun methodDescriptor(descriptor:ClassDescriptor, methodName:String) = DescriptorUtils.getFunctionByName(descriptor.unsubstitutedMemberScope, Name.identifier(methodName))
|
||||||
|
private fun arrayClassDescriptor(name:String) = kKotlinPackage.memberScope.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||||
|
private fun descriptor(descriptor: ClassDescriptor, name:String) = DescriptorUtils.getAllDescriptors(descriptor.unsubstitutedMemberScope).find{it.name.asString() == name}
|
||||||
inline internal fun <R> offset(ir:IrElement, scope:Scope, block: Offset.() -> R):R = offset(irContext, scope, ir.startOffset, ir.endOffset, block)
|
inline internal fun <R> offset(ir:IrElement, scope:Scope, block: Offset.() -> R):R = offset(irContext, scope, ir.startOffset, ir.endOffset, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Offset(context:IrGeneratorContext, scope: Scope, startOffset:Int, endOfset:Int) : IrBuilderWithScope(context, scope, startOffset, endOfset) {
|
internal class Offset(context:IrGeneratorContext, scope: Scope, startOffset:Int, endOfset:Int) : IrBuilderWithScope(context, scope, startOffset, endOfset) {
|
||||||
val kIntZero = irConstInt(0)
|
val kIntZero = irConstInt(0)
|
||||||
val kIntOne = irConstInt(1)
|
val kIntOne = irConstInt(1)
|
||||||
@@ -208,7 +250,7 @@ internal class Offset(context:IrGeneratorContext, scope: Scope, startOffset:Int,
|
|||||||
|
|
||||||
internal fun CallableDescriptor.scope() = Scope(this)
|
internal fun CallableDescriptor.scope() = Scope(this)
|
||||||
|
|
||||||
private fun Offset.irConstInt(value: Int): IrConst<Int> = irConst<Int>(kind = IrConstKind.Int, value = value, type = kIntType)
|
private fun Offset.irConstInt(value: Int): IrConst<Int> = irConst<Int>(kind = IrConstKind.Int, value = value, type = KonanPlatform.builtIns.intType)
|
||||||
private fun <T> Offset.irConst(kind: IrConstKind<T>, value: T, type: KotlinType): IrConst<T> = IrConstImpl<T>(startOffset, endOffset,type, kind,value)
|
private fun <T> Offset.irConst(kind: IrConstKind<T>, value: T, type: KotlinType): IrConst<T> = IrConstImpl<T>(startOffset, endOffset,type, kind,value)
|
||||||
private fun Offset.irBlock(type: KotlinType): IrBlock = IrBlockImpl(startOffset, endOffset, type)
|
private fun Offset.irBlock(type: KotlinType): IrBlock = IrBlockImpl(startOffset, endOffset, type)
|
||||||
private fun Offset.irCall(descriptor: CallableDescriptor, typeArguments: Map<TypeParameterDescriptor, KotlinType>?): IrCall = IrCallImpl(startOffset, endOffset, descriptor, typeArguments)
|
private fun Offset.irCall(descriptor: CallableDescriptor, typeArguments: Map<TypeParameterDescriptor, KotlinType>?): IrCall = IrCallImpl(startOffset, endOffset, descriptor, typeArguments)
|
||||||
|
|||||||
Reference in New Issue
Block a user