diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 682224f1e6d..f9de5029a88 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -41267,6 +41267,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("jvmKPackageCaching.kt") + public void testJvmKPackageCaching() throws Exception { + runTest("compiler/testData/codegen/box/reflection/jvmKPackageCaching.kt"); + } + + @Test + @TestMetadata("jvmKTypeCaching.kt") + public void testJvmKTypeCaching() throws Exception { + runTest("compiler/testData/codegen/box/reflection/jvmKTypeCaching.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/reflection/annotations") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/testData/codegen/box/reflection/jvmKPackageCaching.kt b/compiler/testData/codegen/box/reflection/jvmKPackageCaching.kt new file mode 100644 index 00000000000..b2c64b831c5 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/jvmKPackageCaching.kt @@ -0,0 +1,13 @@ +// TARGET_BACKEND: JVM_IR +// FULL_JDK +// WITH_REFLECT +import kotlin.jvm.internal.* + +class A +fun box(): String { + val pckg = Reflection.getOrCreateKotlinPackage(A::class.java) + System.gc() + val pckg2 = Reflection.getOrCreateKotlinPackage(A::class.java) + if (pckg === pckg2) return "OK" + return "Fail" +} diff --git a/compiler/testData/codegen/box/reflection/jvmKTypeCaching.kt b/compiler/testData/codegen/box/reflection/jvmKTypeCaching.kt new file mode 100644 index 00000000000..fcf8a48e9ab --- /dev/null +++ b/compiler/testData/codegen/box/reflection/jvmKTypeCaching.kt @@ -0,0 +1,13 @@ +// TARGET_BACKEND: JVM_IR +// FULL_JDK +// WITH_REFLECT + +class A + +fun box(): String { + val clz = A::class + System.gc() + val clz2 = A::class + if (clz === clz2) return "OK" + return "Fail" +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 8962562b0b7..55c6ae04a10 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -41267,6 +41267,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("jvmKPackageCaching.kt") + public void testJvmKPackageCaching() throws Exception { + runTest("compiler/testData/codegen/box/reflection/jvmKPackageCaching.kt"); + } + + @Test + @TestMetadata("jvmKTypeCaching.kt") + public void testJvmKTypeCaching() throws Exception { + runTest("compiler/testData/codegen/box/reflection/jvmKTypeCaching.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/reflection/annotations") @TestDataPath("$PROJECT_ROOT") diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/kClassCache.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ClassCaches.kt similarity index 68% rename from core/reflection.jvm/src/kotlin/reflect/jvm/internal/kClassCache.kt rename to core/reflection.jvm/src/kotlin/reflect/jvm/internal/ClassCaches.kt index 34dbeee4300..2b2a456095b 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/kClassCache.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ClassCaches.kt @@ -5,13 +5,19 @@ package kotlin.reflect.jvm.internal +import kotlin.reflect.KDeclarationContainer + private val K_CLASS_CACHE = createCache { KClassImpl(it) } +private val K_PACKAGE_CACHE = createCache { KPackageImpl(it) } // This function is invoked on each reflection access to Java classes, properties, etc. Performance is critical here. @Suppress("UNCHECKED_CAST") internal fun getOrCreateKotlinClass(jClass: Class): KClassImpl = K_CLASS_CACHE.get(jClass) as KClassImpl -internal fun clearKClassCache() { +internal fun getOrCreateKotlinPackage(jClass: Class): KDeclarationContainer = K_PACKAGE_CACHE.get(jClass) + +internal fun clearCaches() { K_CLASS_CACHE.clear() + K_PACKAGE_CACHE.clear() } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index 78588448e0e..c3afae864cd 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -37,7 +37,6 @@ import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.D internal class KPackageImpl( override val jClass: Class<*>, - @Suppress("unused") val usageModuleName: String? = null // may be useful for debug ) : KDeclarationContainerImpl() { private inner class Data : KDeclarationContainerImpl.Data() { private val kotlinClass: ReflectKotlinClass? by ReflectProperties.lazySoft { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java index c918f4ec4ac..1cfa691bc9c 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java @@ -32,17 +32,18 @@ public class ReflectionFactoryImpl extends ReflectionFactory { @Override public KDeclarationContainer getOrCreateKotlinPackage(Class javaClass, String moduleName) { - return new KPackageImpl(javaClass, moduleName); + // moduleName is unused deliberately and only left in public ABI + return ClassCachesKt.getOrCreateKotlinPackage(javaClass); } @Override public KClass getOrCreateKotlinClass(Class javaClass) { - return KClassCacheKt.getOrCreateKotlinClass(javaClass); + return ClassCachesKt.getOrCreateKotlinClass(javaClass); } @Override public KClass getOrCreateKotlinClass(Class javaClass, String internalName) { - return KClassCacheKt.getOrCreateKotlinClass(javaClass); + return ClassCachesKt.getOrCreateKotlinClass(javaClass); } @Override @@ -154,7 +155,7 @@ public class ReflectionFactoryImpl extends ReflectionFactory { // Misc public static void clearCaches() { - KClassCacheKt.clearKClassCache(); + ClassCachesKt.clearCaches(); ModuleByClassLoaderKt.clearModuleByClassLoaderCache(); } } diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Reflection.java b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Reflection.java index fb308bbe800..84b37fbf601 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Reflection.java +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Reflection.java @@ -52,6 +52,7 @@ public class Reflection { } public static KDeclarationContainer getOrCreateKotlinPackage(Class javaClass, String moduleName) { + // This signature cannot be removed as it is used in FunctionReferenceLowering.kt non-directly return factory.getOrCreateKotlinPackage(javaClass, moduleName); }