From e923c657044a787172754bec7baf108c54539fd1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 1 Aug 2018 12:16:21 +0300 Subject: [PATCH] backend.common: improve support for unsigned types --- .../jetbrains/kotlin/backend/common/ir/Ir.kt | 30 +++-- .../backend/common/lower/VarargLowering.kt | 106 +++++++++++------- 2 files changed, 78 insertions(+), 58 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt index 63842823fa9..d3536131f86 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt @@ -2,8 +2,10 @@ package org.jetbrains.kotlin.backend.common.ir import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrModuleFragment @@ -109,6 +111,10 @@ abstract class Symbols(val context: T, private val private fun primitiveArrayClass(type: PrimitiveType) = symbolTable.referenceClass(builtIns.getPrimitiveArrayClassDescriptor(type)) + private fun unsignedArrayClass(unsignedType: UnsignedType) = + builtIns.builtInsModule.findClassAcrossModuleDependencies(unsignedType.arrayClassId) + ?.let { symbolTable.referenceClass(it) } + val byteArray = primitiveArrayClass(PrimitiveType.BYTE) val charArray = primitiveArrayClass(PrimitiveType.CHAR) val shortArray = primitiveArrayClass(PrimitiveType.SHORT) @@ -118,7 +124,14 @@ abstract class Symbols(val context: T, private val val doubleArray = primitiveArrayClass(PrimitiveType.DOUBLE) val booleanArray = primitiveArrayClass(PrimitiveType.BOOLEAN) - val arrays = PrimitiveType.values().map { primitiveArrayClass(it) } + array + val unsignedArrays = UnsignedType.values().mapNotNull { unsignedType -> + unsignedArrayClass(unsignedType)?.let { unsignedType to it } + }.toMap() + + + val primitiveArrays = PrimitiveType.values().associate { it to primitiveArrayClass(it) } + + val arrays = primitiveArrays.values + unsignedArrays.values + array protected fun arrayExtensionFun(type: KotlinType, name: String): IrSimpleFunctionSymbol { val descriptor = builtInsPackage("kotlin") @@ -131,21 +144,6 @@ abstract class Symbols(val context: T, private val return symbolTable.referenceSimpleFunction(descriptor) } - - protected val arrayTypes = arrayOf( - builtIns.getPrimitiveArrayKotlinType(PrimitiveType.BYTE), - builtIns.getPrimitiveArrayKotlinType(PrimitiveType.CHAR), - builtIns.getPrimitiveArrayKotlinType(PrimitiveType.SHORT), - builtIns.getPrimitiveArrayKotlinType(PrimitiveType.INT), - builtIns.getPrimitiveArrayKotlinType(PrimitiveType.LONG), - builtIns.getPrimitiveArrayKotlinType(PrimitiveType.FLOAT), - builtIns.getPrimitiveArrayKotlinType(PrimitiveType.DOUBLE), - builtIns.getPrimitiveArrayKotlinType(PrimitiveType.BOOLEAN), - builtIns.array.defaultType - ) -// val arrayContentToString = arrayTypes.associateBy({ it }, { arrayExtensionFun(it, "contentToString") }) -// val arrayContentHashCode = arrayTypes.associateBy({ it }, { arrayExtensionFun(it, "contentHashCode") }) - abstract val copyRangeTo: Map val intAnd = symbolTable.referenceSimpleFunction( diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/VarargLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/VarargLowering.kt index 24491e1e08d..8cff236accb 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/VarargLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/VarargLowering.kt @@ -20,8 +20,8 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString import org.jetbrains.kotlin.backend.common.ir.ir2string -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl 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.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* @@ -109,13 +108,7 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De val type = expression.varargElementType log { "$expression: array type:$type, is array of primitives ${!expression.type.isArray()}" } val arrayHandle = arrayType(expression.type) - val arrayConstructor = arrayHandle.arraySymbol.owner.constructors.find { it.valueParameters.size == 1 }!! val block = irBlock(expression.type) - val arrayConstructorCall = irCall(arrayConstructor) - - if (arrayConstructor.typeParameters.isNotEmpty()) { - arrayConstructorCall.putTypeArgument(0, expression.varargElementType) - } val vars = expression.elements.map { val initVar = scope.createTemporaryVariable( @@ -124,8 +117,10 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De block.statements.add(initVar) it to initVar }.toMap() - arrayConstructorCall.putValueArgument(0, calculateArraySize(arrayHandle, hasSpreadElement, scope, expression, vars)) - val arrayTmpVariable = scope.createTemporaryVariable(arrayConstructorCall, "array".synthesizedString, true) + val arraySize = calculateArraySize(arrayHandle, hasSpreadElement, scope, expression, vars) + val array = arrayHandle.createArray(this, expression.varargElementType, arraySize) + + val arrayTmpVariable = scope.createTemporaryVariable(array, "array".synthesizedString, true) val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "index".synthesizedString, true) block.statements.add(arrayTmpVariable) if (hasSpreadElement) { @@ -173,18 +168,8 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De private val intPlusInt = symbols.intPlusInt.owner private fun arrayType(type: IrType): ArrayHandle { - val primitiveType = KotlinBuiltIns.getPrimitiveArrayType(type.classifierOrFail.descriptor) - return when (primitiveType) { - PrimitiveType.BYTE -> kByteArrayHandler - PrimitiveType.SHORT -> kShortArrayHandler - PrimitiveType.CHAR -> kCharArrayHandler - PrimitiveType.INT -> kIntArrayHandler - PrimitiveType.LONG -> kLongArrayHandler - PrimitiveType.FLOAT -> kFloatArrayHandler - PrimitiveType.DOUBLE -> kDoubleArrayHandler - PrimitiveType.BOOLEAN -> kBooleanArrayHandler - else -> kArrayHandler - } + val arrayClass = type.classifierOrFail + return arrayToHandle[arrayClass] ?: error(arrayClass.descriptor) } private fun IrBuilderWithScope.intPlus() = irCall(intPlusInt) @@ -201,7 +186,7 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De putValueArgument(0, value) }) } - private fun calculateArraySize(arrayHandle: ArrayHandle, hasSpreadElement: Boolean, scope:Scope, expression: IrVararg, vars: Map): IrExpression? { + private fun calculateArraySize(arrayHandle: ArrayHandle, hasSpreadElement: Boolean, scope:Scope, expression: IrVararg, vars: Map): IrExpression { context.createIrBuilder(scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run { if (!hasSpreadElement) return irConstInt(expression.elements.size) @@ -228,27 +213,64 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De context.log { "VARARG-INJECTOR: ${msg()}" } } - data class ArrayHandle(val arraySymbol: IrClassSymbol, - val setMethodSymbol: IrFunctionSymbol, - val sizeGetterSymbol: IrFunctionSymbol, - val copyRangeToSymbol: IrFunctionSymbol) + abstract inner class ArrayHandle(val arraySymbol: IrClassSymbol) { + val setMethodSymbol = arraySymbol.functions.single { it.descriptor.name == OperatorNameConventions.SET } + val sizeGetterSymbol = arraySymbol.getPropertyGetter("size")!! + val copyRangeToSymbol = symbols.copyRangeTo[arraySymbol.descriptor]!! + protected val singleParameterConstructor = + arraySymbol.owner.constructors.find { it.valueParameters.size == 1 }!! - val kByteArrayHandler = handle(symbols.byteArray) - val kCharArrayHandler = handle(symbols.charArray) - val kShortArrayHandler = handle(symbols.shortArray) - val kIntArrayHandler = handle(symbols.intArray) - val kLongArrayHandler = handle(symbols.longArray) - val kFloatArrayHandler = handle(symbols.floatArray) - val kDoubleArrayHandler = handle(symbols.doubleArray) - val kBooleanArrayHandler = handle(symbols.booleanArray) - val kArrayHandler = handle(symbols.array) + abstract fun createArray(builder: IrBuilderWithScope, elementType: IrType, size: IrExpression): IrExpression + } - private fun handle(symbol: IrClassSymbol) = ArrayHandle( - arraySymbol = symbol, - setMethodSymbol = symbol.functions.single { it.descriptor.name == OperatorNameConventions.SET }, - sizeGetterSymbol = symbol.getPropertyGetter("size")!!, - copyRangeToSymbol = symbols.copyRangeTo[symbol.descriptor]!! - ) + inner class ReferenceArrayHandle : ArrayHandle(symbols.array) { + override fun createArray(builder: IrBuilderWithScope, elementType: IrType, size: IrExpression): IrExpression { + return builder.irCall(singleParameterConstructor).apply { + putTypeArgument(0, elementType) + putValueArgument(0, size) + } + } + } + + inner class PrimitiveArrayHandle(primitiveType: PrimitiveType) + : ArrayHandle(symbols.primitiveArrays[primitiveType]!!) { + + override fun createArray(builder: IrBuilderWithScope, elementType: IrType, size: IrExpression): IrExpression { + return builder.irCall(singleParameterConstructor).apply { + putValueArgument(0, size) + } + } + } + + inner class UnsignedArrayHandle( + arraySymbol: IrClassSymbol, + private val wrappedArrayHandle: PrimitiveArrayHandle + ) : ArrayHandle(arraySymbol) { + + override fun createArray(builder: IrBuilderWithScope, elementType: IrType, size: IrExpression): IrExpression { + val wrappedArray = wrappedArrayHandle.createArray(builder, elementType, size) + return builder.irCall(singleParameterConstructor).apply { + putValueArgument(0, wrappedArray) + } + } + } + + private val primitiveArrayHandles = PrimitiveType.values().associate { it to PrimitiveArrayHandle(it) } + + private val unsignedArrayHandles = UnsignedType.values().mapNotNull { unsignedType -> + symbols.unsignedArrays[unsignedType]?.let { + val primitiveType = when (unsignedType) { + UnsignedType.UBYTE -> PrimitiveType.BYTE + UnsignedType.USHORT -> PrimitiveType.SHORT + UnsignedType.UINT -> PrimitiveType.INT + UnsignedType.ULONG -> PrimitiveType.LONG + } + UnsignedArrayHandle(it, primitiveArrayHandles[primitiveType]!!) + } + } + + val arrayToHandle = + (primitiveArrayHandles.values + unsignedArrayHandles + ReferenceArrayHandle()).associateBy { it.arraySymbol } }