diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt index 04e0db9bc6e..30cce0a1ce5 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt @@ -33,4 +33,5 @@ object KonanFqNames { val hasFinalizer = FqName("kotlin.native.internal.HasFinalizer") val hasFreezeHook = FqName("kotlin.native.internal.HasFreezeHook") val gcUnsafeCall = FqName("kotlin.native.internal.GCUnsafeCall") + val eagerInitialization = FqName("kotlin.native.EagerInitialization") } 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 d2a9828fca2..05fff2c2724 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 @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.konan.cgen.CBridgeOrigin import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.llvm.coverage.LLVMCoverageInstrumentation +import org.jetbrains.kotlin.backend.konan.lower.* import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER @@ -370,6 +371,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { require(kPropertiesField == null) { "Expected at most one kProperties field" } diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 5068ab779d3..b5d5c3b7a4b 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -1485,6 +1485,26 @@ standaloneTest("initializers_globalInitedBeforeThreadLocal") { source = "codegen/initializers/globalInitedBeforeThreadLocal.kt" } +standaloneTest("initializers_eagerInitializationGlobal1") { + enabled = project.globalTestArgs.contains('-Xir-property-lazy-initialization') + source = "codegen/initializers/eagerInitializationGlobal1.kt" +} + +standaloneTest("initializers_eagerInitializationGlobal2") { + enabled = project.globalTestArgs.contains('-Xir-property-lazy-initialization') + source = "codegen/initializers/eagerInitializationGlobal2.kt" +} + +standaloneTest("initializers_eagerInitializationThreadLocal1") { + enabled = project.globalTestArgs.contains('-Xir-property-lazy-initialization') + source = "codegen/initializers/eagerInitializationThreadLocal1.kt" +} + +standaloneTest("initializers_eagerInitializationThreadLocal2") { + enabled = project.globalTestArgs.contains('-Xir-property-lazy-initialization') + source = "codegen/initializers/eagerInitializationThreadLocal2.kt" +} + standaloneTest("initializers_workers1") { source = "codegen/initializers/workers1.kt" goldValue = "42\n3\n" diff --git a/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationGlobal1.kt b/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationGlobal1.kt new file mode 100644 index 00000000000..608a5128c03 --- /dev/null +++ b/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationGlobal1.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +// FILE: lib.kt +var z1 = false +var z2 = false + +// FILE: lib2.kt +import kotlin.test.* + +@OptIn(kotlin.ExperimentalStdlibApi::class) +@EagerInitialization +val x = foo() + +private fun foo(): Int { + z1 = true + return 42 +} + +// Will be initialized since [x]'s initializer calls a function from the file. +val y = run { z2 = true; 117 } + +// FILE: main.kt +import kotlin.test.* + +fun main() { + assertTrue(z1) + assertTrue(z2) +} diff --git a/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationGlobal2.kt b/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationGlobal2.kt new file mode 100644 index 00000000000..6c3554171d0 --- /dev/null +++ b/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationGlobal2.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +// FILE: lib.kt +var z1 = false +var z2 = false + +// FILE: lib2.kt +import kotlin.test.* + +@OptIn(kotlin.ExperimentalStdlibApi::class) +@EagerInitialization +val x = run { z1 = true; 42 } + +// Won't be initialized (cause no function from the file will be called during [x] initialization). +val y = run { z2 = true; 117 } + +// FILE: main.kt +import kotlin.test.* + +fun main() { + assertTrue(z1) + assertFalse(z2) +} diff --git a/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationThreadLocal1.kt b/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationThreadLocal1.kt new file mode 100644 index 00000000000..a672fc0e59d --- /dev/null +++ b/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationThreadLocal1.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +// FILE: lib.kt +@ThreadLocal +var z1 = false +var z2 = false +@ThreadLocal +var z3 = false + +// FILE: lib2.kt +import kotlin.test.* + +@OptIn(kotlin.ExperimentalStdlibApi::class) +@EagerInitialization +@ThreadLocal +val x = foo() + +private fun foo(): Int { + z1 = true + return 42 +} + +// Both will be initialized since [x]'s initializer calls a function from the file. +val y1 = run { z2 = true; 117 } + +@ThreadLocal +val y2 = run { z3 = true; 117 } + +// FILE: main.kt +import kotlin.test.* + +fun main() { + assertTrue(z1) + assertTrue(z2) + assertTrue(z3) +} diff --git a/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationThreadLocal2.kt b/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationThreadLocal2.kt new file mode 100644 index 00000000000..617a8a83dc4 --- /dev/null +++ b/kotlin-native/backend.native/tests/codegen/initializers/eagerInitializationThreadLocal2.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +// FILE: lib.kt +@ThreadLocal +var z1 = false +var z2 = false +@ThreadLocal +var z3 = false + +// FILE: lib2.kt +import kotlin.test.* + +@OptIn(kotlin.ExperimentalStdlibApi::class) +@EagerInitialization +@ThreadLocal +val x = run { z1 = true; 42 } + +// Won't be initialized (cause no function from the file will be called during [x] initialization). +val y1 = run { z2 = true; 117 } + +@ThreadLocal +val y2 = run { z3 = true; 117 } + +// FILE: main.kt +import kotlin.test.* + +fun main() { + assertTrue(z1) + assertFalse(z2) + assertFalse(z3) +}