diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt index 22c9fef2521..7015bdd194b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt @@ -1,6 +1,7 @@ package org.jetbrains.kotlin.backend.common.ir import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.descriptors.replace import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.descriptors.ClassDescriptor @@ -8,9 +9,11 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.util.OperatorNameConventions // This is what Context collects about IR. @@ -92,6 +95,30 @@ open class Symbols(val context: T, private val symb val arrays = PrimitiveType.values().map { primitiveArrayClass(it) } + array + private fun arrayExtensionFun(type: KotlinType, name: String): IrSimpleFunctionSymbol { + val descriptor = builtInsPackage("kotlin") + .getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND) + .singleOrNull { it.valueParameters.isEmpty() + && (it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.defaultType == type } + ?: throw Error(type.toString()) + return symbolTable.referenceSimpleFunction(descriptor) + } + + + private 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") }) + val copyRangeTo = arrays.map { symbol -> val packageViewDescriptor = builtIns.builtInsModule.getPackage(KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME) val functionDescriptor = packageViewDescriptor.memberScope diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 4a8bdfbb6ac..4255b6daa90 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -63,6 +63,9 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.LOWER_STRING_CONCAT) { StringConcatenationLowering(context).lower(irFile) } + phaser.phase(KonanPhase.LOWER_DATA_CLASSES) { + DataClassOperatorsLowering(context).runOnFilePostfix(irFile) + } phaser.phase(KonanPhase.LOWER_ENUMS) { EnumClassLowering(context).run(irFile) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index 6000cd9f1ab..324f62dec20 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -50,6 +50,7 @@ enum class KonanPhase(val description: String, /* ... ... */ LOWER_TYPE_OPERATORS("Type operators lowering", LOWER_COROUTINES), /* ... ... */ BRIDGES_BUILDING("Bridges building", LOWER_COROUTINES), /* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"), + /* ... ... */ LOWER_DATA_CLASSES("Data classes lowering"), /* ... ... */ AUTOBOX("Autoboxing of primitive types", BRIDGES_BUILDING, LOWER_COROUTINES), /* ... */ BITCODE("LLVM BitCode Generation"), /* ... ... */ RTTI("RTTI Generation"), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt new file mode 100644 index 00000000000..1fe218a653c --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt @@ -0,0 +1,76 @@ +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.FunctionLoweringPass +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlock +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.makeNotNullable + +internal class DataClassOperatorsLowering(val context: Context): FunctionLoweringPass { + + private val irBuiltins = context.irModule!!.irBuiltins + + override fun lower(irFunction: IrFunction) { + irFunction.transformChildrenVoid(object: IrElementTransformerVoid() { + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + + if (expression.symbol != irBuiltins.dataClassArrayMemberToStringSymbol + && expression.symbol != irBuiltins.dataClassArrayMemberHashCodeSymbol) + return expression + + val argument = expression.getValueArgument(0)!! + val argumentType = argument.type.makeNotNullable() + val genericType = + if (argumentType.arguments.isEmpty()) + argumentType + else + (argumentType.constructor.declarationDescriptor as ClassDescriptor).defaultType + val isToString = expression.symbol == irBuiltins.dataClassArrayMemberToStringSymbol + val newSymbol = if (isToString) + context.ir.symbols.arrayContentToString[genericType]!! + else + context.ir.symbols.arrayContentHashCode[genericType]!! + + val startOffset = expression.startOffset + val endOffset = expression.endOffset + val irBuilder = context.createIrBuilder(irFunction.symbol, startOffset, endOffset) + + return irBuilder.run { + val typeArguments = + if (argumentType.arguments.isEmpty()) + emptyList() + else argumentType.arguments.map { it.type } + if (!argument.type.isMarkedNullable) { + irCall(newSymbol, typeArguments).apply { + extensionReceiver = argument + } + } else { + val tmp = scope.createTemporaryVariable(argument) + val call = irCall(newSymbol, typeArguments).apply { + extensionReceiver = irGet(tmp.symbol) + } + irBlock(argument) { + +tmp + +irIfThenElse(call.type, + irEqeqeq(irGet(tmp.symbol), irNull()), + if (isToString) + irString("null") + else + irInt(0), + call) + } + } + } + } + }) + } +} \ No newline at end of file