Do not store JVM reflection objects by soft reference

Otherwise they might be garbage-collected before being made accessible
with `isAccessible = true` and the reflective call.

Also, compute BoxUnboxData in InlineClassAwareCaller right away, to
prevent storing a hard reference on the descriptor (all descriptors and
related data are stored by soft references in kotlin-reflect).

 #KT-27585 Fixed
This commit is contained in:
Alexander Udalov
2018-11-14 18:26:13 +01:00
parent 9d2524a790
commit 67bc8d62fc
3 changed files with 9 additions and 9 deletions
@@ -58,7 +58,7 @@ internal class KFunctionImpl private constructor(
override val name: String get() = descriptor.name.asString() override val name: String get() = descriptor.name.asString()
override val caller: Caller<*> by ReflectProperties.lazySoft caller@{ override val caller: Caller<*> by ReflectProperties.lazy caller@{
val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor) val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor)
val member: Member? = when (jvmSignature) { val member: Member? = when (jvmSignature) {
is KotlinConstructor -> { is KotlinConstructor -> {
@@ -90,7 +90,7 @@ internal class KFunctionImpl private constructor(
}.createInlineClassAwareCallerIfNeeded(descriptor) }.createInlineClassAwareCallerIfNeeded(descriptor)
} }
override val defaultCaller: Caller<*>? by ReflectProperties.lazySoft defaultCaller@{ override val defaultCaller: Caller<*>? by ReflectProperties.lazy defaultCaller@{
val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor) val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor)
val member: Member? = when (jvmSignature) { val member: Member? = when (jvmSignature) {
is KotlinFunction -> { is KotlinFunction -> {
@@ -48,7 +48,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
override val isBound: Boolean get() = rawBoundReceiver != CallableReference.NO_RECEIVER override val isBound: Boolean get() = rawBoundReceiver != CallableReference.NO_RECEIVER
private val _javaField = ReflectProperties.lazySoft { private val _javaField = ReflectProperties.lazy {
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor) val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
when (jvmSignature) { when (jvmSignature) {
is KotlinProperty -> { is KotlinProperty -> {
@@ -152,7 +152,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
property.descriptor.getter ?: DescriptorFactory.createDefaultGetter(property.descriptor, Annotations.EMPTY) property.descriptor.getter ?: DescriptorFactory.createDefaultGetter(property.descriptor, Annotations.EMPTY)
} }
override val caller: Caller<*> by ReflectProperties.lazySoft { override val caller: Caller<*> by ReflectProperties.lazy {
computeCallerForAccessor(isGetter = true) computeCallerForAccessor(isGetter = true)
} }
} }
@@ -165,7 +165,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
property.descriptor.setter ?: DescriptorFactory.createDefaultSetter(property.descriptor, Annotations.EMPTY, Annotations.EMPTY) property.descriptor.setter ?: DescriptorFactory.createDefaultSetter(property.descriptor, Annotations.EMPTY, Annotations.EMPTY)
} }
override val caller: Caller<*> by ReflectProperties.lazySoft { override val caller: Caller<*> by ReflectProperties.lazy {
computeCallerForAccessor(isGetter = false) computeCallerForAccessor(isGetter = false)
} }
} }
@@ -24,7 +24,7 @@ import kotlin.reflect.jvm.internal.toJavaClass
* Each argument of an inline class type is unboxed, and the return value (if it's of an inline class type) is boxed. * Each argument of an inline class type is unboxed, and the return value (if it's of an inline class type) is boxed.
*/ */
internal class InlineClassAwareCaller<out M : Member?>( internal class InlineClassAwareCaller<out M : Member?>(
private val descriptor: CallableMemberDescriptor, descriptor: CallableMemberDescriptor,
private val caller: Caller<M>, private val caller: Caller<M>,
private val isDefault: Boolean private val isDefault: Boolean
) : Caller<M> { ) : Caller<M> {
@@ -43,14 +43,14 @@ internal class InlineClassAwareCaller<out M : Member?>(
operator fun component3(): Method? = box operator fun component3(): Method? = box
} }
private val data: BoxUnboxData by lazy(LazyThreadSafetyMode.PUBLICATION) { private val data: BoxUnboxData = run {
val box = descriptor.returnType!!.toInlineClass()?.getBoxMethod(descriptor) val box = descriptor.returnType!!.toInlineClass()?.getBoxMethod(descriptor)
if (descriptor.isGetterOfUnderlyingPropertyOfInlineClass()) { if (descriptor.isGetterOfUnderlyingPropertyOfInlineClass()) {
// Getter of the underlying val of an inline class is always called on a boxed receiver, // Getter of the underlying val of an inline class is always called on a boxed receiver,
// no argument boxing/unboxing is required. // no argument boxing/unboxing is required.
// However, its result might require boxing if it is an inline class type. // However, its result might require boxing if it is an inline class type.
return@lazy BoxUnboxData(IntRange.EMPTY, emptyArray(), box) return@run BoxUnboxData(IntRange.EMPTY, emptyArray(), box)
} }
val shift = when { val shift = when {