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 caller: Caller<*> by ReflectProperties.lazySoft caller@{
override val caller: Caller<*> by ReflectProperties.lazy caller@{
val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor)
val member: Member? = when (jvmSignature) {
is KotlinConstructor -> {
@@ -90,7 +90,7 @@ internal class KFunctionImpl private constructor(
}.createInlineClassAwareCallerIfNeeded(descriptor)
}
override val defaultCaller: Caller<*>? by ReflectProperties.lazySoft defaultCaller@{
override val defaultCaller: Caller<*>? by ReflectProperties.lazy defaultCaller@{
val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor)
val member: Member? = when (jvmSignature) {
is KotlinFunction -> {
@@ -48,7 +48,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
override val isBound: Boolean get() = rawBoundReceiver != CallableReference.NO_RECEIVER
private val _javaField = ReflectProperties.lazySoft {
private val _javaField = ReflectProperties.lazy {
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
when (jvmSignature) {
is KotlinProperty -> {
@@ -152,7 +152,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
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)
}
}
@@ -165,7 +165,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
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)
}
}
@@ -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.
*/
internal class InlineClassAwareCaller<out M : Member?>(
private val descriptor: CallableMemberDescriptor,
descriptor: CallableMemberDescriptor,
private val caller: Caller<M>,
private val isDefault: Boolean
) : Caller<M> {
@@ -43,14 +43,14 @@ internal class InlineClassAwareCaller<out M : Member?>(
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)
if (descriptor.isGetterOfUnderlyingPropertyOfInlineClass()) {
// Getter of the underlying val of an inline class is always called on a boxed receiver,
// no argument boxing/unboxing is required.
// 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 {
@@ -196,4 +196,4 @@ internal fun Any?.coerceToExpectedReceiverType(descriptor: CallableMemberDescrip
val unboxMethod = expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
return unboxMethod.invoke(this)
}
}