diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 51e7d1712ae..3e83b8b4ac8 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -377,6 +377,7 @@ internal abstract class KonanSymbols( private fun reflectionClass(name: String) = irBuiltIns.findClass(Name.identifier(name), StandardNames.KOTLIN_REFLECT_FQ_NAME)!! val kFunctionImpl = internalClass("KFunctionImpl") + val kFunctionDescription = internalClass("KFunctionDescription") val kSuspendFunctionImpl = internalClass("KSuspendFunctionImpl") val kMutableProperty0 = reflectionClass("KMutableProperty0") diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 8bdc7523d10..a67b6ca90b3 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1895,27 +1895,43 @@ internal class CodeGeneratorVisitor( intrinsicGenerator.evaluateConstantConstructorFields(value, value.valueArguments.map { evaluateConstantValue(it) }) } else { val fields = context.getLayoutBuilder(constructedClass).getFields(llvm) - val valueParameters = value.constructor.owner.valueParameters.associateBy { it.name.toString() } + val constructor = value.constructor.owner + val valueParameters = constructor.valueParameters.associateBy { it.name.toString() } + // support of initilaization of object in following case: + // open class Base(val field: ...) + // Child(val otherField: ...) : Base(constantValue) + // + // Child(constantValue) could be initialized constantly. This is required for function references. + val delegatedCallConstants = constructor.body?.statements + ?.filterIsInstance() + ?.singleOrNull() + ?.getArgumentsWithIr() + ?.filter { it.second is IrConstantValue } + ?.associate { it.first.name.toString() to it.second } + .orEmpty() fields.map { field -> - if (field.isConst) { - val init = field.irField!!.initializer?.expression - require(field.name !in valueParameters) { - "Constant field ${field.name} of class ${constructedClass.name} shouldn't be a constructor parameter" - } - when (init) { - is IrConst<*> -> evaluateConst(init) - is IrConstantValue -> evaluateConstantValue(init) - null -> error("Constant field ${field.name} of class ${constructedClass.name} should have initializer") - else -> error("Unexpected constant initializer type: ${init::class}") + val init = if (field.isConst) { + field.irField!!.initializer?.expression.also { + require(field.name !in valueParameters) { + "Constant field ${field.name} of class ${constructedClass.name} shouldn't be a constructor parameter" + } } } else { val index = valueParameters[field.name]?.index - ?: error("Bad statically initialized object: field ${field.name} value not set in ${constructedClass.name}") - evaluateConstantValue(value.valueArguments[index]) + if (index != null) + value.valueArguments[index] + else + delegatedCallConstants[field.name] + } + when (init) { + is IrConst<*> -> evaluateConst(init) + is IrConstantValue -> evaluateConstantValue(init) + null -> error("Bad statically initialized object: field ${field.name} value not set in ${constructedClass.name}") + else -> error("Unexpected constant initializer type: ${init::class}") } }.also { - require(it.size == value.valueArguments.size + fields.count { it.isConst }) { - "Bad statically initialized object of class ${constructedClass.name}: too many fields" + require(it.size == value.valueArguments.size + fields.count { it.isConst } + delegatedCallConstants.size) { + "Bad statically initialized object of class ${constructedClass.name}: not all arguments are used" } } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt index 3ac8cc8de67..39af6f31299 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt @@ -310,6 +310,7 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt } private val kFunctionImplSymbol = symbols.kFunctionImpl + private val kFunctionDescriptionSymbol = symbols.kFunctionDescription private val kFunctionImplConstructorSymbol = kFunctionImplSymbol.constructors.single() private val kSuspendFunctionImplSymbol = symbols.kSuspendFunctionImpl private val kSuspendFunctionImplConstructorSymbol = kSuspendFunctionImplSymbol.constructors.single() @@ -384,15 +385,6 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt addOverrideInner(name) { _ -> value() } } - val kTypeGenerator = KTypeGenerator(context, irFile, functionReference) - addOverride("computeReturnType") { with(kTypeGenerator) { irKType(referencedFunction.returnType) } } - addOverride("computeArity") { irInt(unboundFunctionParameters.size + if (functionReferenceTarget.isSuspend) 1 else 0) } - addOverride("computeFlags") { irInt(getFlags()) } - val name = ((functionReferenceTarget as? IrSimpleFunction)?.attributeOwnerId as? IrSimpleFunction)?.name - ?: functionReferenceTarget.name - addOverride("computeName") { irString(name.asString()) } - addOverride("computeFqName") { irString(getFqName()) } - listOfNotNull( functionReference.symbol.owner.dispatchReceiverParameter, @@ -435,11 +427,15 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody { val superConstructor = when { - this@FunctionReferenceBuilder.isSuspend -> kSuspendFunctionImplConstructorSymbol.owner isLambda -> irBuiltIns.anyClass.owner.constructors.single() + this@FunctionReferenceBuilder.isSuspend -> kSuspendFunctionImplConstructorSymbol.owner else -> kFunctionImplConstructorSymbol.owner } - +irDelegatingConstructorCall(superConstructor) + +irDelegatingConstructorCall(superConstructor).apply { + if (!isLambda) { + putValueArgument(0, getDescription()) + } + } +IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType) // Save all arguments to fields. boundFunctionParameters.forEachIndexed { index, parameter -> @@ -465,6 +461,21 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt return BuiltFunctionReference(clazz, expression) } + private fun IrBuilderWithScope.getDescription() : IrConstantValue { + val kTypeGenerator = KTypeGenerator(this@FunctionReferenceBuilder.context, irFile, functionReference) + + return irConstantObject( + kFunctionDescriptionSymbol.owner, + mapOf( + "flags" to irConstantPrimitive(irInt(getFlags())), + "arity" to irConstantPrimitive(irInt(getArity())), + "fqName" to irConstantPrimitive(irString(getFqName())), + "name" to irConstantPrimitive(irString(getName().asString())), + "returnType" to with(kTypeGenerator) { irKType(referencedFunction.returnType) } + ) + ) + } + // this value is used only for hashCode and equals, to distinguish different wrappers on same functions private fun getFlags() = listOfNotNull( @@ -481,6 +492,12 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt else functionReferenceTarget.computeFullName() + private fun getName() = + ((functionReferenceTarget as? IrSimpleFunction)?.attributeOwnerId as? IrSimpleFunction)?.name + ?: functionReferenceTarget.name + + private fun getArity() = unboundFunctionParameters.size + if (functionReferenceTarget.isSuspend) 1 else 0 + private fun isFunInterfaceConstructorAdapter() = referencedFunction.origin == IrDeclarationOrigin.ADAPTER_FOR_FUN_INTERFACE_CONSTRUCTOR diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KFunctionImpl.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KFunctionImpl.kt index b99de3b0fbf..5c5e0e6fd3c 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KFunctionImpl.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KFunctionImpl.kt @@ -8,20 +8,23 @@ package kotlin.native.internal import kotlin.reflect.KFunction import kotlin.reflect.KType -@FixmeReflection -internal abstract class KFunctionImpl: KFunction { - final override val returnType get() = computeReturnType() - val flags get() = computeFlags() - val arity get() = computeArity() - val fqName get() = computeFqName() - val receiver get() = computeReceiver() - final override val name get() = computeName() +internal class KFunctionDescription( + val flags: Int, + val arity: Int, + val fqName: String, + val name: String, + val returnType: KType +) + +@FixmeReflection +internal abstract class KFunctionImpl(val description: KFunctionDescription): KFunction { + final override val returnType get() = description.returnType + val flags get() = description.flags + val arity get() = description.arity + val fqName get() = description.fqName + val receiver get() = computeReceiver() + final override val name get() = description.name - abstract fun computeReturnType() : KType - abstract fun computeFlags() : Int - abstract fun computeArity() : Int - abstract fun computeFqName() : String - abstract fun computeName() : String open fun computeReceiver(): Any? = null override fun equals(other: Any?): Boolean { diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KSuspendFunctionImpl.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KSuspendFunctionImpl.kt index 767fe951c9a..8939179d2d3 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KSuspendFunctionImpl.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KSuspendFunctionImpl.kt @@ -10,6 +10,6 @@ import kotlin.reflect.KFunction import kotlin.reflect.KClass @FixmeReflection -internal abstract class KSuspendFunctionImpl: KFunctionImpl() { +internal abstract class KSuspendFunctionImpl(description: KFunctionDescription): KFunctionImpl(description) { override fun toString() = "suspend function $name" }