diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt index 66662307f8a..219b339516f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt @@ -65,7 +65,7 @@ internal fun produceOutput(context: Context, phaser: PhaseManager) { val abiVersion = context.config.currentAbiVersion val target = context.config.target val nopack = config.getBoolean(KonanConfigKeys.NOPACK) - val manifest = config.get(KonanConfigKeys.MANIFEST_FILE) + val manifestProperties = context.config.manifestProperties val library = buildLibrary( context.config.nativeLibraries, @@ -78,7 +78,7 @@ internal fun produceOutput(context: Context, phaser: PhaseManager) { libraryName, llvmModule, nopack, - manifest, + manifestProperties, context.dataFlowGraph) context.library = library diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 30cc89c70d2..72a88660033 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.library.defaultResolver import org.jetbrains.kotlin.konan.library.libraryResolver +import org.jetbrains.kotlin.konan.properties.loadProperties import org.jetbrains.kotlin.konan.target.* class KonanConfig(val project: Project, val configuration: CompilerConfiguration) { @@ -103,6 +104,12 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration internal val friendModuleFiles: Set = configuration.get(KonanConfigKeys.FRIEND_MODULES)?.map { File(it) }?.toSet() ?: emptySet() + + internal val manifestProperties = configuration.get(KonanConfigKeys.MANIFEST_FILE)?.let { + File(it).loadProperties() + } + + internal val isInteropStubs: Boolean get() = manifestProperties?.getProperty("interop") == "true" } fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt index ae3c64b1e8f..f4e299b9088 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.library import llvm.LLVMModuleRef import org.jetbrains.kotlin.konan.library.KonanLibrary +import java.util.* const val KLIB_CURRENT_ABI_VERSION = 1 @@ -16,7 +17,7 @@ interface KonanLibraryWriter { fun addIncludedBinary(library: String) fun addKotlinBitcode(llvmModule: LLVMModuleRef) fun addLinkDependencies(libraries: List) - fun addManifestAddend(path: String) + fun addManifestAddend(properties: Properties) fun addDataFlowGraph(dataFlowGraph: ByteArray) val mainBitcodeFileName: String fun commit() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt index d252d6414ca..0737a0dec3b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt @@ -88,8 +88,7 @@ class LibraryWriterImpl( } } - override fun addManifestAddend(path: String) { - val properties = File(path).loadProperties() + override fun addManifestAddend(properties: Properties) { manifestProperties.putAll(properties) } @@ -117,7 +116,7 @@ internal fun buildLibrary( moduleName: String, llvmModule: LLVMModuleRef, nopack: Boolean, - manifest: String?, + manifestProperties: Properties?, dataFlowGraph: ByteArray?): KonanLibraryWriter { val library = LibraryWriterImpl(output, moduleName, abiVersion, target, nopack) @@ -130,7 +129,7 @@ internal fun buildLibrary( included.forEach { library.addIncludedBinary(it) } - manifest ?.let { library.addManifestAddend(it) } + manifestProperties?.let { library.addManifestAddend(it) } library.addLinkDependencies(linkDependencies) dataFlowGraph?.let { library.addDataFlowGraph(it) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt index d9b8f5c4953..ca394d850a9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt @@ -674,6 +674,39 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme } } + override fun visitProperty(declaration: IrProperty): IrStatement { + val backingField = declaration.backingField + return if (declaration.isConst && backingField?.isStatic == true && context.config.isInteropStubs) { + // Transform top-level `const val x = 42` to `val x get() = 42`. + // Generally this transformation is just an optimization to ensure that interop constants + // don't require any storage and/or initialization at program startup. + // Also it is useful due to uncertain design of top-level stored properties in Kotlin/Native. + val initializer = backingField.initializer!!.expression + declaration.backingField = null + + val getter = declaration.getter!! + val getterBody = getter.body!! as IrBlockBody + getterBody.statements.clear() + getterBody.statements += IrReturnImpl( + declaration.startOffset, + declaration.endOffset, + context.irBuiltIns.nothingType, + getter.symbol, + initializer + ) + // Note: in interop stubs const val initializer is either `IrConst` or quite simple expression, + // so it is ok to compute it every time. + + assert(declaration.setter == null) + assert(!declaration.isVar) + + declaration.transformChildrenVoid() + declaration + } else { + super.visitProperty(declaration) + } + } + private fun IrBuilderWithScope.callAllocAndInit( classPtr: IrExpression, initMethodInfo: ObjCMethodInfo,