[K/N] Transform constant varargs to ConstantValue

This commit is contained in:
Pavel Kunyavskiy
2021-07-16 15:31:58 +03:00
committed by Space
parent 0d11a61fb2
commit e4a4cd3e16
3 changed files with 125 additions and 18 deletions
@@ -10,12 +10,8 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.isImmutable
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
val IrBuilderWithScope.parent get() = scope.getLocalDeclarationParent()
@@ -378,3 +374,51 @@ inline fun IrBuilderWithScope.irBlockBody(
endOffset
).blockBody(body)
fun IrBuilderWithScope.irConstantPrimitive(value: IrConst<*>) =
IrConstantPrimitiveImpl(startOffset, endOffset, value)
fun IrBuilderWithScope.irConstantArray(type: IrType, elements: List<IrConstantValue>) =
IrConstantArrayImpl(
startOffset, endOffset,
type,
elements
)
fun IrBuilderWithScope.irConstantObject(
constructor: IrConstructorSymbol,
arguments: List<IrConstantValue>,
typeArguments: List<IrType> = emptyList()
): IrConstantValue {
return IrConstantObjectImpl(
startOffset, endOffset,
constructor,
arguments,
typeArguments,
)
}
fun IrBuilderWithScope.irConstantObject(
clazz: IrClass,
arguments: List<IrConstantValue>,
typeArguments: List<IrType> = emptyList()
): IrConstantValue {
return irConstantObject(clazz.primaryConstructor?.symbol!!, arguments, typeArguments)
}
fun IrBuilderWithScope.irConstantObject(
clazz: IrClass,
elements: Map<String, IrConstantValue>,
typeArguments: List<IrType> = emptyList()
): IrConstantValue {
return irConstantObject(
clazz,
clazz.primaryConstructor!!.symbol.owner.valueParameters.also {
require(it.size == elements.size) {
"Wrong number of values provided for ${clazz.name} construction: ${elements.size} instead of ${it.size}"
}
}.map {
elements[it.name.asString()] ?: error("No value for field named ${it.name} provided")
},
typeArguments
)
}
@@ -325,6 +325,7 @@ internal class KonanSymbols(
}
val copyInto = arrayToExtensionSymbolMap("copyInto")
val copyOf = arrayToExtensionSymbolMap("copyOf") { it.valueParameters.isEmpty() }
val arrayGet = arrays.associateWith { it.descriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("get"), NoLookupLocation.FROM_BACKEND)
@@ -34,13 +34,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isArray
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -108,11 +103,27 @@ internal class VarargInjectionLowering constructor(val context: KonanBackendCont
expression.transformChildrenVoid(transformer)
val hasSpreadElement = hasSpreadElement(expression)
val type = expression.varargElementType
val arrayHandle = arrayType(expression.type)
val irBuilder = context.createIrBuilder(owner, expression.startOffset, expression.endOffset)
val isConstantVararg = expression.elements.all {
it is IrConst<*> || it is IrConstantValue
}
if (isConstantVararg) {
return irBuilder.irCall(
arrayHandle.copyOfSymbol,
).apply {
extensionReceiver = arrayHandle.createStatic(irBuilder, type, expression.elements.map {
when (it) {
is IrConst<*> -> irBuilder.irConstantPrimitive(it)
is IrConstantValue -> it
else -> throw IllegalStateException("Try to initialize vararg constantly, when it's impossible")
}
})
}
}
return irBuilder.irBlock(expression, null, expression.type) {
val type = expression.varargElementType
log { "$expression: array type:$type, is array of primitives ${!expression.type.isArray()}" }
val arrayHandle = arrayType(expression.type)
val vars = expression.elements.map {
it to irTemporary(
@@ -217,10 +228,15 @@ internal class VarargInjectionLowering constructor(val context: KonanBackendCont
}
val sizeGetterSymbol = arraySymbol.getPropertyGetter("size")!!
val copyIntoSymbol = symbols.copyInto[arraySymbol]!!
val copyOfSymbol = symbols.copyOf[arraySymbol]!!
protected val singleParameterConstructor =
arraySymbol.owner.constructors.find { it.valueParameters.size == 1 }!!
arraySymbol.owner.constructors.find { it.valueParameters.size == 1 }!!
abstract fun createArray(builder: IrBuilderWithScope, elementType: IrType, size: IrExpression): IrExpression
abstract fun createStatic(
builder: IrBuilderWithScope,
elementType: IrType,
values: List<IrConstantValue>): IrConstantValue
}
inner class ReferenceArrayHandle : ArrayHandle(symbols.array) {
@@ -230,6 +246,16 @@ internal class VarargInjectionLowering constructor(val context: KonanBackendCont
putValueArgument(0, size)
}
}
override fun createStatic(
builder: IrBuilderWithScope,
elementType: IrType,
values: List<IrConstantValue>): IrConstantValue {
return builder.irConstantArray(
arraySymbol.typeWith(listOf(elementType)),
values
)
}
}
inner class PrimitiveArrayHandle(primitiveType: PrimitiveType)
@@ -240,11 +266,18 @@ internal class VarargInjectionLowering constructor(val context: KonanBackendCont
putValueArgument(0, size)
}
}
override fun createStatic(builder: IrBuilderWithScope, elementType: IrType, values: List<IrConstantValue>): IrConstantValue {
return builder.irConstantArray(
arraySymbol.defaultType,
values
)
}
}
inner class UnsignedArrayHandle(
arraySymbol: IrClassSymbol,
private val wrappedArrayHandle: PrimitiveArrayHandle
arraySymbol: IrClassSymbol,
private val wrappedArrayHandle: PrimitiveArrayHandle
) : ArrayHandle(arraySymbol) {
override fun createArray(builder: IrBuilderWithScope, elementType: IrType, size: IrExpression): IrExpression {
@@ -253,6 +286,35 @@ internal class VarargInjectionLowering constructor(val context: KonanBackendCont
putValueArgument(0, wrappedArray)
}
}
override fun createStatic(builder: IrBuilderWithScope, elementType: IrType, values: List<IrConstantValue>): IrConstantValue {
val casted = values.map {
require(it.type == elementType)
when (it) {
is IrConstantPrimitive -> {
val castedConst = when (it.value.kind) {
IrConstKind.Byte -> IrConstImpl.byte(it.startOffset, it.endOffset, symbols.byte.defaultType, it.value.value as Byte)
IrConstKind.Short -> IrConstImpl.short(it.startOffset, it.endOffset, symbols.short.defaultType, it.value.value as Short)
IrConstKind.Int -> IrConstImpl.int(it.startOffset, it.endOffset, symbols.int.defaultType, it.value.value as Int)
IrConstKind.Long -> IrConstImpl.long(it.startOffset, it.endOffset, symbols.long.defaultType, it.value.value as Long)
else -> error("Unsupported unsigned constant")
}
builder.irConstantPrimitive(castedConst)
}
is IrConstantObject -> {
it.valueArguments.singleOrNull()
?: error("Constant of type ${it.type.render()} is expected to have exactly one field")
}
else -> error("unsigned integer can't be represented as ${it::class.qualifiedName}")
}
}
return builder.irConstantObject(
arraySymbol.owner,
mapOf(
"storage" to wrappedArrayHandle.createStatic(builder, elementType, casted)
)
)
}
}
private val primitiveArrayHandles = PrimitiveType.values().associate { it to PrimitiveArrayHandle(it) }