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:
Alexander Udalov
2015-04-01 21:20:35 +03:00
parent 715641fb0d
commit 9c1e7f93d2
9 changed files with 85 additions and 64 deletions
@@ -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
@@ -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
@@ -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