diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 67b206cb15a..f91e9c805e3 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -38,7 +38,7 @@ import kotlin.reflect.KFunction import kotlin.reflect.KotlinReflectionInternalError internal class KClassImpl(override val jClass: Class) : KDeclarationContainerImpl(), KClass, KAnnotatedElementImpl { - val descriptor by ReflectProperties.lazySoft { + private val descriptor_ = ReflectProperties.lazySoft { val classId = classId val descriptor = @@ -48,6 +48,9 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration descriptor ?: throw KotlinReflectionInternalError("Class not resolved: $jClass") } + val descriptor: ClassDescriptor + get() = descriptor_() + override val annotated: Annotated get() = descriptor private val classId: ClassId get() = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass) @@ -138,7 +141,7 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration }.filterNotNull().map { KClassImpl(it) } @Suppress("UNCHECKED_CAST") - override val objectInstance: T? by ReflectProperties.lazy { + private val objectInstance_ = ReflectProperties.lazy { val descriptor = descriptor if (descriptor.kind != ClassKind.OBJECT) return@lazy null @@ -151,6 +154,9 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration field.get(null) as T } + override val objectInstance: T? + get() = objectInstance_() + override fun equals(other: Any?): Boolean = other is KClassImpl<*> && jClass == other.jClass diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt index bf05b74c2e7..0d6b00b99cf 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.structure.reflect.classId import org.jetbrains.kotlin.load.java.structure.reflect.createArrayType import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader +import org.jetbrains.kotlin.load.kotlin.reflect.RuntimeModuleData import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.JetScope @@ -36,11 +37,16 @@ import kotlin.reflect.KCallable import kotlin.reflect.KotlinReflectionInternalError internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer { + // NB: be careful not to introduce delegated properties in this class and subclasses, there are problems with circular dependencies + // Note: this is stored here on a soft reference to prevent GC from destroying the weak reference to it in the moduleByClassLoader cache - val moduleData by ReflectProperties.lazySoft { + private val moduleData_ = ReflectProperties.lazySoft { jClass.getOrCreateModule() } + val moduleData: RuntimeModuleData + get() = moduleData_() + abstract val constructorDescriptors: Collection abstract fun getProperties(name: Name): Collection 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 d927d8b576f..3088d471672 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -28,13 +28,14 @@ import kotlin.reflect.KCallable import kotlin.reflect.KPackage internal class KPackageImpl(override val jClass: Class<*>, val moduleName: String) : KDeclarationContainerImpl(), KPackage { - val descriptor by ReflectProperties.lazySoft { - val moduleData = moduleData - moduleData.packageFacadeProvider.registerModule(moduleName) - moduleData.module.getPackage(jClass.classId.packageFqName) + private val descriptor = ReflectProperties.lazySoft { + with(moduleData) { + packageFacadeProvider.registerModule(moduleName) + module.getPackage(jClass.classId.packageFqName) + } } - internal val scope: JetScope get() = descriptor.memberScope + internal val scope: JetScope get() = descriptor().memberScope override val members: Collection> get() = getMembers(scope, declaredOnly = false, nonExtensions = true, extensions = true).toList() diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java index 926a87d2874..09ebcd7b04e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectProperties.java @@ -23,15 +23,16 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; -/** - * The fact that this is a Java class is used in reflection implementation classes: otherwise if it were a Kotlin class, KClassImpl() - * instance would have been invoked in its static initializer (to create and cache $kotlinClass field), resulting in infinite recursion. - */ /* package */ class ReflectProperties { public static abstract class Val { private static final Object NULL_VALUE = new Object() {}; - public abstract T get(Object instance, Object metadata); + @SuppressWarnings("UnusedParameters") + public T get(Object instance, Object metadata) { + return invoke(); + } + + public abstract T invoke(); protected Object escape(T value) { return value == null ? NULL_VALUE : value; @@ -53,7 +54,7 @@ import java.lang.ref.WeakReference; } @Override - public T get(Object instance, Object metadata) { + public T invoke() { Object cached = value; if (cached != null) { return unescape(cached); @@ -80,7 +81,7 @@ import java.lang.ref.WeakReference; } @Override - public T get(Object instance, Object metadata) { + public T invoke() { SoftReference cached = value; if (cached != null) { Object result = cached.get(); @@ -107,7 +108,7 @@ import java.lang.ref.WeakReference; } @Override - public T get(Object instance, Object metadata) { + public T invoke() { WeakReference cached = value; if (cached != null) { Object result = cached.get();