Reflection: refactor property construction and fix memory leak
Properties obtained by KClass.properties were having strong references to descriptors (captured by closures, which are strongly retained by DescriptorBasedProperty). Support initial value in lazy soft properties
This commit is contained in:
@@ -18,6 +18,7 @@ package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.desc
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
@@ -26,10 +27,22 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
|
||||
abstract class DescriptorBasedProperty(computeDescriptor: () -> PropertyDescriptor) {
|
||||
protected abstract val container: KCallableContainerImpl
|
||||
abstract class DescriptorBasedProperty private(
|
||||
container: KCallableContainerImpl,
|
||||
name: String,
|
||||
receiverParameterDesc: String?,
|
||||
descriptorInitialValue: PropertyDescriptor?
|
||||
) {
|
||||
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : this(
|
||||
container, name, receiverParameterClass?.desc, null
|
||||
)
|
||||
|
||||
protected abstract val name: String
|
||||
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : this(
|
||||
container,
|
||||
descriptor.getName().asString(),
|
||||
descriptor.getExtensionReceiverParameter()?.getType()?.let { type -> RuntimeTypeMapper.mapTypeToJvmDesc(type) },
|
||||
descriptor
|
||||
)
|
||||
|
||||
private data class PropertyProtoData(
|
||||
val proto: ProtoBuf.Callable,
|
||||
@@ -37,7 +50,9 @@ abstract class DescriptorBasedProperty(computeDescriptor: () -> PropertyDescript
|
||||
val signature: JvmProtoBuf.JvmPropertySignature
|
||||
)
|
||||
|
||||
protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft(computeDescriptor)
|
||||
protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft<PropertyDescriptor>(descriptorInitialValue) {
|
||||
container.findPropertyDescriptor(name, receiverParameterDesc)
|
||||
}
|
||||
|
||||
// null if this is a property declared in a foreign (Java) class
|
||||
private val protoData: PropertyProtoData? by ReflectProperties.lazyWeak {
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classLoader
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.createArrayType
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.desc
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
@@ -42,9 +41,7 @@ abstract class KCallableContainerImpl {
|
||||
|
||||
abstract val scope: JetScope
|
||||
|
||||
protected fun findPropertyDescriptor(name: String, receiverParameterClass: Class<*>? = null): () -> PropertyDescriptor = {
|
||||
val receiverDesc = receiverParameterClass?.desc
|
||||
|
||||
fun findPropertyDescriptor(name: String, receiverDesc: String? = null): PropertyDescriptor {
|
||||
val properties = scope
|
||||
.getProperties(Name.identifier(name))
|
||||
.filter { descriptor ->
|
||||
@@ -57,14 +54,14 @@ abstract class KCallableContainerImpl {
|
||||
}
|
||||
|
||||
if (properties.size() != 1) {
|
||||
val debugText = if (receiverParameterClass == null) name else "${receiverParameterClass.getSimpleName()}.$name"
|
||||
val debugText = if (receiverDesc == null) name else "$receiverDesc.$name"
|
||||
throw KotlinReflectionInternalError(
|
||||
if (properties.isEmpty()) "Property '$debugText' not resolved in $this"
|
||||
else "${properties.size()} properties '$debugText' resolved in $this"
|
||||
)
|
||||
}
|
||||
|
||||
properties.single() as PropertyDescriptor
|
||||
return properties.single() as PropertyDescriptor
|
||||
}
|
||||
|
||||
// TODO: check resulting method's return type
|
||||
|
||||
@@ -69,14 +69,14 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
|
||||
fun getProperties(declared: Boolean): Collection<KMemberProperty<T, *>> =
|
||||
getProperties(extension = false, declared = declared) { descriptor ->
|
||||
if (descriptor.isVar()) KMutableMemberPropertyImpl<T, Any?>(this) { descriptor }
|
||||
else KMemberPropertyImpl<T, Any?>(this) { descriptor }
|
||||
if (descriptor.isVar()) KMutableMemberPropertyImpl<T, Any?>(this, descriptor)
|
||||
else KMemberPropertyImpl<T, Any?>(this, descriptor)
|
||||
}
|
||||
|
||||
fun getExtensionProperties(declared: Boolean): Collection<KMemberExtensionProperty<T, *, *>> =
|
||||
getProperties(extension = true, declared = declared) { descriptor ->
|
||||
if (descriptor.isVar()) KMutableMemberExtensionPropertyImpl<T, Any?, Any?>(this) { descriptor }
|
||||
else KMemberExtensionPropertyImpl<T, Any?, Any?>(this) { descriptor }
|
||||
if (descriptor.isVar()) KMutableMemberExtensionPropertyImpl<T, Any?, Any?>(this, descriptor)
|
||||
else KMemberExtensionPropertyImpl<T, Any?, Any?>(this, descriptor)
|
||||
}
|
||||
|
||||
private fun <P : KProperty<*>> getProperties(extension: Boolean, declared: Boolean, create: (PropertyDescriptor) -> P): Collection<P> =
|
||||
@@ -91,10 +91,10 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
.toList()
|
||||
|
||||
fun memberProperty(name: String): KMemberProperty<T, *> =
|
||||
KMemberPropertyImpl<T, Any>(this, findPropertyDescriptor(name))
|
||||
KMemberPropertyImpl<T, Any>(this, name)
|
||||
|
||||
fun mutableMemberProperty(name: String): KMutableMemberProperty<T, *> =
|
||||
KMutableMemberPropertyImpl<T, Any>(this, findPropertyDescriptor(name))
|
||||
KMutableMemberPropertyImpl<T, Any>(this, name)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KClassImpl<*> && jClass == other.jClass
|
||||
|
||||
+13
-8
@@ -23,10 +23,11 @@ import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMemberExtensionProperty
|
||||
import kotlin.reflect.KMutableMemberExtensionProperty
|
||||
|
||||
open class KMemberExtensionPropertyImpl<D : Any, E, out R>(
|
||||
override val container: KClassImpl<D>,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : DescriptorBasedProperty(computeDescriptor), KMemberExtensionProperty<D, E, R>, KPropertyImpl<R> {
|
||||
open class KMemberExtensionPropertyImpl<D : Any, E, out R> : DescriptorBasedProperty, KMemberExtensionProperty<D, E, R>, KPropertyImpl<R> {
|
||||
constructor(container: KClassImpl<D>, name: String, receiverParameterClass: Class<E>) : super(container, name, receiverParameterClass)
|
||||
|
||||
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override val getter: Method get() = super<DescriptorBasedProperty>.getter!!
|
||||
@@ -45,10 +46,14 @@ open class KMemberExtensionPropertyImpl<D : Any, E, out R>(
|
||||
}
|
||||
|
||||
|
||||
class KMutableMemberExtensionPropertyImpl<D : Any, E, R>(
|
||||
container: KClassImpl<D>,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : KMemberExtensionPropertyImpl<D, E, R>(container, computeDescriptor), KMutableMemberExtensionProperty<D, E, R>, KMutablePropertyImpl<R> {
|
||||
class KMutableMemberExtensionPropertyImpl<D : Any, E, R> :
|
||||
KMemberExtensionPropertyImpl<D, E, R>,
|
||||
KMutableMemberExtensionProperty<D, E, R>,
|
||||
KMutablePropertyImpl<R> {
|
||||
constructor(container: KClassImpl<D>, name: String, receiverParameterClass: Class<E>) : super(container, name, receiverParameterClass)
|
||||
|
||||
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
override val setter: Method get() = super<KMemberExtensionPropertyImpl>.setter!!
|
||||
|
||||
override fun set(instance: D, extensionReceiver: E, value: R) {
|
||||
|
||||
@@ -21,10 +21,11 @@ import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMemberProperty
|
||||
import kotlin.reflect.KMutableMemberProperty
|
||||
|
||||
open class KMemberPropertyImpl<T : Any, out R>(
|
||||
override val container: KClassImpl<T>,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : DescriptorBasedProperty(computeDescriptor), KMemberProperty<T, R>, KPropertyImpl<R> {
|
||||
open class KMemberPropertyImpl<T : Any, out R> : DescriptorBasedProperty, KMemberProperty<T, R>, KPropertyImpl<R> {
|
||||
constructor(container: KClassImpl<T>, name: String) : super(container, name, null)
|
||||
|
||||
constructor(container: KClassImpl<T>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override fun get(instance: T): R {
|
||||
@@ -40,10 +41,11 @@ open class KMemberPropertyImpl<T : Any, out R>(
|
||||
}
|
||||
|
||||
|
||||
class KMutableMemberPropertyImpl<T : Any, R>(
|
||||
container: KClassImpl<T>,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : KMemberPropertyImpl<T, R>(container, computeDescriptor), KMutableMemberProperty<T, R>, KMutablePropertyImpl<R> {
|
||||
class KMutableMemberPropertyImpl<T : Any, R> : KMemberPropertyImpl<T, R>, KMutableMemberProperty<T, R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KClassImpl<T>, name: String) : super(container, name)
|
||||
|
||||
constructor(container: KClassImpl<T>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
override fun set(instance: T, value: R) {
|
||||
try {
|
||||
val setter = setter
|
||||
|
||||
@@ -31,21 +31,17 @@ class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KP
|
||||
|
||||
override val scope: JetScope get() = descriptor.getMemberScope()
|
||||
|
||||
fun topLevelVariable(name: String): KTopLevelVariable<*> {
|
||||
return KTopLevelVariableImpl<Any?>(this, findPropertyDescriptor(name))
|
||||
}
|
||||
fun topLevelVariable(name: String): KTopLevelVariable<*> =
|
||||
KTopLevelVariableImpl<Any?>(this, name)
|
||||
|
||||
fun mutableTopLevelVariable(name: String): KMutableTopLevelVariable<*> {
|
||||
return KMutableTopLevelVariableImpl<Any?>(this, findPropertyDescriptor(name))
|
||||
}
|
||||
fun mutableTopLevelVariable(name: String): KMutableTopLevelVariable<*> =
|
||||
KMutableTopLevelVariableImpl<Any?>(this, name)
|
||||
|
||||
fun <T> topLevelExtensionProperty(name: String, receiver: Class<T>): KTopLevelExtensionProperty<T, *> {
|
||||
return KTopLevelExtensionPropertyImpl<T, Any?>(this, findPropertyDescriptor(name, receiver))
|
||||
}
|
||||
fun <T> topLevelExtensionProperty(name: String, receiver: Class<T>): KTopLevelExtensionProperty<T, *> =
|
||||
KTopLevelExtensionPropertyImpl<T, Any?>(this, name, receiver)
|
||||
|
||||
fun <T> mutableTopLevelExtensionProperty(name: String, receiver: Class<T>): KMutableTopLevelExtensionProperty<T, *> {
|
||||
return KMutableTopLevelExtensionPropertyImpl<T, Any?>(this, findPropertyDescriptor(name, receiver))
|
||||
}
|
||||
fun <T> mutableTopLevelExtensionProperty(name: String, receiver: Class<T>): KMutableTopLevelExtensionProperty<T, *> =
|
||||
KMutableTopLevelExtensionPropertyImpl<T, Any?>(this, name, receiver)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KPackageImpl && jClass == other.jClass
|
||||
|
||||
+9
-9
@@ -16,16 +16,14 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableTopLevelExtensionProperty
|
||||
import kotlin.reflect.KTopLevelExtensionProperty
|
||||
|
||||
open class KTopLevelExtensionPropertyImpl<T, out R>(
|
||||
override val container: KPackageImpl,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : DescriptorBasedProperty(computeDescriptor), KTopLevelExtensionProperty<T, R>, KPropertyImpl<R> {
|
||||
open class KTopLevelExtensionPropertyImpl<T, out R> : DescriptorBasedProperty, KTopLevelExtensionProperty<T, R>, KPropertyImpl<R> {
|
||||
constructor(container: KPackageImpl, name: String, receiverParameterClass: Class<T>) : super(container, name, receiverParameterClass)
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override val getter: Method get() = super<DescriptorBasedProperty>.getter!!
|
||||
@@ -41,10 +39,12 @@ open class KTopLevelExtensionPropertyImpl<T, out R>(
|
||||
}
|
||||
}
|
||||
|
||||
class KMutableTopLevelExtensionPropertyImpl<T, R>(
|
||||
container: KPackageImpl,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : KTopLevelExtensionPropertyImpl<T, R>(container, computeDescriptor), KMutableTopLevelExtensionProperty<T, R>, KMutablePropertyImpl<R> {
|
||||
class KMutableTopLevelExtensionPropertyImpl<T, R> :
|
||||
KTopLevelExtensionPropertyImpl<T, R>,
|
||||
KMutableTopLevelExtensionProperty<T, R>,
|
||||
KMutablePropertyImpl<R> {
|
||||
constructor(container: KPackageImpl, name: String, receiverParameterClass: Class<T>) : super(container, name, receiverParameterClass)
|
||||
|
||||
override val setter: Method get() = super<KTopLevelExtensionPropertyImpl>.setter!!
|
||||
|
||||
override fun set(receiver: T, value: R) {
|
||||
|
||||
@@ -16,16 +16,14 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableTopLevelVariable
|
||||
import kotlin.reflect.KTopLevelVariable
|
||||
|
||||
open class KTopLevelVariableImpl<out R>(
|
||||
override val container: KPackageImpl,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : DescriptorBasedProperty(computeDescriptor), KTopLevelVariable<R>, KVariableImpl<R> {
|
||||
open class KTopLevelVariableImpl<out R> : DescriptorBasedProperty, KTopLevelVariable<R>, KVariableImpl<R> {
|
||||
constructor(container: KPackageImpl, name: String) : super(container, name, null)
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override val getter: Method get() = super<DescriptorBasedProperty>.getter!!
|
||||
@@ -41,10 +39,9 @@ open class KTopLevelVariableImpl<out R>(
|
||||
}
|
||||
}
|
||||
|
||||
class KMutableTopLevelVariableImpl<R>(
|
||||
container: KPackageImpl,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : KTopLevelVariableImpl<R>(container, computeDescriptor), KMutableTopLevelVariable<R>, KMutableVariableImpl<R> {
|
||||
class KMutableTopLevelVariableImpl<R> : KTopLevelVariableImpl<R>, KMutableTopLevelVariable<R>, KMutableVariableImpl<R> {
|
||||
constructor(container: KPackageImpl, name: String) : super(container, name)
|
||||
|
||||
override val setter: Method get() = super<KTopLevelVariableImpl>.setter!!
|
||||
|
||||
override fun set(value: R) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package kotlin.reflect.jvm.internal;
|
||||
|
||||
import kotlin.Function0;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.ref.WeakReference;
|
||||
@@ -67,8 +68,11 @@ import java.lang.ref.WeakReference;
|
||||
private final Function0<T> initializer;
|
||||
private SoftReference<Object> value = null;
|
||||
|
||||
public LazySoftVal(@NotNull Function0<T> initializer) {
|
||||
public LazySoftVal(@Nullable T initialValue, @NotNull Function0<T> initializer) {
|
||||
this.initializer = initializer;
|
||||
if (initialValue != null) {
|
||||
this.value = new SoftReference<Object>(escape(initialValue));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,9 +124,14 @@ import java.lang.ref.WeakReference;
|
||||
return new LazyVal<T>(initializer);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> LazySoftVal<T> lazySoft(@Nullable T initialValue, @NotNull Function0<T> initializer) {
|
||||
return new LazySoftVal<T>(initialValue, initializer);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> LazySoftVal<T> lazySoft(@NotNull Function0<T> initializer) {
|
||||
return new LazySoftVal<T>(initializer);
|
||||
return lazySoft(null, initializer);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
Reference in New Issue
Block a user