[IR] Support reflection for MFVC
Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com> #KT-1179
This commit is contained in:
committed by
Space Team
parent
1ff4906880
commit
88f293d4a9
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.inlineClassRepresentation
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.multiFieldValueClassRepresentation
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -42,6 +43,8 @@ fun KotlinType.unsubstitutedUnderlyingTypes(): List<KotlinType> {
|
||||
|
||||
|
||||
fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?.isInlineClass() ?: false
|
||||
fun KotlinType.isMultiFieldValueClassType(): Boolean = constructor.declarationDescriptor?.isMultiFieldValueClass() ?: false
|
||||
fun KotlinType.isValueClassType(): Boolean = constructor.declarationDescriptor?.isValueClass() ?: false
|
||||
|
||||
fun KotlinType.needsMfvcFlattening(): Boolean =
|
||||
constructor.declarationDescriptor?.run { isMultiFieldValueClass() && !isNullableType() } == true
|
||||
@@ -77,6 +80,20 @@ fun KotlinType.isNullableUnderlyingType(): Boolean {
|
||||
fun CallableDescriptor.isGetterOfUnderlyingPropertyOfInlineClass() =
|
||||
this is PropertyGetterDescriptor && correspondingProperty.isUnderlyingPropertyOfInlineClass()
|
||||
|
||||
fun CallableDescriptor.isGetterOfUnderlyingPropertyOfMultiFieldValueClass() =
|
||||
this is PropertyGetterDescriptor && correspondingProperty.isUnderlyingPropertyOfMultiFieldValueClass()
|
||||
|
||||
fun CallableDescriptor.isGetterOfUnderlyingPropertyOfValueClass() =
|
||||
this is PropertyGetterDescriptor && correspondingProperty.isUnderlyingPropertyOfValueClass()
|
||||
|
||||
fun VariableDescriptor.isUnderlyingPropertyOfInlineClass(): Boolean =
|
||||
extensionReceiverParameter == null &&
|
||||
(containingDeclaration as? ClassDescriptor)?.inlineClassRepresentation?.underlyingPropertyName == this.name
|
||||
|
||||
fun VariableDescriptor.isUnderlyingPropertyOfMultiFieldValueClass(): Boolean =
|
||||
extensionReceiverParameter == null &&
|
||||
(containingDeclaration as? ClassDescriptor)?.multiFieldValueClassRepresentation?.containsPropertyWithName(this.name) == true
|
||||
|
||||
fun VariableDescriptor.isUnderlyingPropertyOfValueClass(): Boolean =
|
||||
extensionReceiverParameter == null &&
|
||||
(containingDeclaration as? ClassDescriptor)?.valueClassRepresentation?.containsPropertyWithName(this.name) == true
|
||||
|
||||
@@ -8,13 +8,14 @@ package kotlin.reflect.jvm.internal
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.types.asSimpleType
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.lang.reflect.WildcardType
|
||||
import java.util.*
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.internal.calls.Caller
|
||||
import kotlin.reflect.jvm.internal.calls.getMfvcUnboxMethods
|
||||
import kotlin.reflect.jvm.javaType
|
||||
import kotlin.reflect.jvm.jvmErasure
|
||||
import java.lang.reflect.Array as ReflectArray
|
||||
@@ -113,7 +114,9 @@ internal abstract class KCallableImpl<out R> : KCallable<R>, KTypeParameterOwner
|
||||
|
||||
private val _absentArguments = ReflectProperties.lazySoft {
|
||||
val parameterSize = parameters.size + (if (isSuspend) 1 else 0)
|
||||
val maskSize = (parameters.size + Integer.SIZE - 1) / Integer.SIZE
|
||||
val flattenedParametersSize =
|
||||
if (parametersNeedMFVCFlattening.value) parameters.sumOf { getParameterTypeSize(it) } else parameters.size
|
||||
val maskSize = (flattenedParametersSize + Integer.SIZE - 1) / Integer.SIZE
|
||||
|
||||
// Array containing the actual function arguments, masks, and +1 for DefaultConstructorMarker or MethodHandle.
|
||||
val arguments = arrayOfNulls<Any?>(parameterSize + maskSize + 1)
|
||||
@@ -161,14 +164,23 @@ internal abstract class KCallableImpl<out R> : KCallable<R>, KTypeParameterOwner
|
||||
var valueParameterIndex = 0
|
||||
var anyOptional = false
|
||||
|
||||
val hasMfvcParameters = parametersNeedMFVCFlattening.value
|
||||
for (parameter in parameters) {
|
||||
val parameterTypeSize = if (hasMfvcParameters) getParameterTypeSize(parameter) else 1
|
||||
when {
|
||||
args.containsKey(parameter) -> {
|
||||
arguments[parameter.index] = args[parameter]
|
||||
}
|
||||
parameter.isOptional -> {
|
||||
val maskIndex = parameterSize + (valueParameterIndex / Integer.SIZE)
|
||||
arguments[maskIndex] = (arguments[maskIndex] as Int) or (1 shl (valueParameterIndex % Integer.SIZE))
|
||||
if (hasMfvcParameters) {
|
||||
for (valueSubParameterIndex in valueParameterIndex until (valueParameterIndex + parameterTypeSize)) {
|
||||
val maskIndex = parameterSize + (valueSubParameterIndex / Integer.SIZE)
|
||||
arguments[maskIndex] = (arguments[maskIndex] as Int) or (1 shl (valueSubParameterIndex % Integer.SIZE))
|
||||
}
|
||||
} else {
|
||||
val maskIndex = parameterSize + (valueParameterIndex / Integer.SIZE)
|
||||
arguments[maskIndex] = (arguments[maskIndex] as Int) or (1 shl (valueParameterIndex % Integer.SIZE))
|
||||
}
|
||||
anyOptional = true
|
||||
}
|
||||
parameter.isVararg -> {}
|
||||
@@ -178,7 +190,7 @@ internal abstract class KCallableImpl<out R> : KCallable<R>, KTypeParameterOwner
|
||||
}
|
||||
|
||||
if (parameter.kind == KParameter.Kind.VALUE) {
|
||||
valueParameterIndex++
|
||||
valueParameterIndex += parameterTypeSize
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +209,20 @@ internal abstract class KCallableImpl<out R> : KCallable<R>, KTypeParameterOwner
|
||||
}
|
||||
}
|
||||
|
||||
private val parametersNeedMFVCFlattening = lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
parameters.any { it.type.needsMultiFieldValueClassFlattening }
|
||||
}
|
||||
|
||||
private fun getParameterTypeSize(parameter: KParameter): Int {
|
||||
require(parametersNeedMFVCFlattening.value) { "Check if parametersNeedMFVCFlattening is true before" }
|
||||
return if (parameter.type.needsMultiFieldValueClassFlattening) {
|
||||
val type = (parameter.type as KTypeImpl).type.asSimpleType()
|
||||
getMfvcUnboxMethods(type)!!.size
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
private fun callAnnotationConstructor(args: Map<KParameter, Any?>): R {
|
||||
val arguments = parameters.map { parameter ->
|
||||
when {
|
||||
|
||||
@@ -24,10 +24,12 @@ import org.jetbrains.kotlin.descriptors.runtime.structure.wrapperByPrimitive
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.isMultiFieldValueClass
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.jvm.internal.ClassBasedDeclarationContainer
|
||||
import kotlin.reflect.jvm.internal.calls.toJvmDescriptor
|
||||
|
||||
internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer {
|
||||
abstract inner class Data {
|
||||
@@ -119,9 +121,25 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
}
|
||||
|
||||
fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor {
|
||||
val members = if (name == "<init>") constructorDescriptors.toList() else getFunctions(Name.identifier(name))
|
||||
val functions = members.filter { descriptor ->
|
||||
RuntimeTypeMapper.mapSignature(descriptor).asString() == signature
|
||||
val members: Collection<FunctionDescriptor>
|
||||
val functions: List<FunctionDescriptor>
|
||||
if (name == "<init>") {
|
||||
members = constructorDescriptors.toList()
|
||||
functions = members.filter { descriptor ->
|
||||
val descriptorSignature = if (descriptor.isPrimary && descriptor.containingDeclaration.isMultiFieldValueClass()) {
|
||||
val initial = RuntimeTypeMapper.mapSignature(descriptor).asString()
|
||||
require(initial.startsWith("constructor-impl") && initial.endsWith(")V")) {
|
||||
"Invalid signature of $descriptor: $initial"
|
||||
}
|
||||
initial.removeSuffix("V") + descriptor.containingDeclaration.toJvmDescriptor()
|
||||
} else {
|
||||
RuntimeTypeMapper.mapSignature(descriptor).asString()
|
||||
}
|
||||
descriptorSignature == signature
|
||||
}
|
||||
} else {
|
||||
members = getFunctions(Name.identifier(name))
|
||||
functions = members.filter { descriptor -> RuntimeTypeMapper.mapSignature(descriptor).asString() == signature }
|
||||
}
|
||||
|
||||
if (functions.size != 1) {
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.jvm.shouldHideConstructorDueToInlineClassTypeValueParameters
|
||||
import org.jetbrains.kotlin.resolve.isMultiFieldValueClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.shouldHideConstructorDueToValueClassTypeValueParameters
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
@@ -66,7 +68,14 @@ internal class KFunctionImpl private constructor(
|
||||
return@caller AnnotationConstructorCaller(container.jClass, parameters.map { it.name!! }, POSITIONAL_CALL, KOTLIN)
|
||||
container.findConstructorBySignature(jvmSignature.constructorDesc)
|
||||
}
|
||||
is KotlinFunction -> container.findMethodBySignature(jvmSignature.methodName, jvmSignature.methodDesc)
|
||||
is KotlinFunction -> {
|
||||
if (descriptor.let { it.containingDeclaration.isMultiFieldValueClass() && it is ConstructorDescriptor && it.isPrimary }) {
|
||||
return@caller ValueClassAwareCaller.MultiFieldValueClassPrimaryConstructorCaller(
|
||||
descriptor, container, jvmSignature.methodDesc, descriptor.valueParameters
|
||||
)
|
||||
}
|
||||
container.findMethodBySignature(jvmSignature.methodName, jvmSignature.methodDesc)
|
||||
}
|
||||
is JavaMethod -> jvmSignature.method
|
||||
is JavaConstructor -> jvmSignature.constructor
|
||||
is FakeJavaAnnotationConstructor -> {
|
||||
@@ -87,13 +96,16 @@ internal class KFunctionImpl private constructor(
|
||||
createStaticMethodCaller(member)
|
||||
}
|
||||
else -> throw KotlinReflectionInternalError("Could not compute caller for function: $descriptor (member = $member)")
|
||||
}.createInlineClassAwareCallerIfNeeded(descriptor)
|
||||
}.createValueClassAwareCallerIfNeeded(descriptor)
|
||||
}
|
||||
|
||||
override val defaultCaller: Caller<*>? by lazy(PUBLICATION) defaultCaller@{
|
||||
val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor)
|
||||
val member: Member? = when (jvmSignature) {
|
||||
is KotlinFunction -> {
|
||||
if (descriptor.let { it.containingDeclaration.isMultiFieldValueClass() && it is ConstructorDescriptor && it.isPrimary }) {
|
||||
throw KotlinReflectionInternalError("${descriptor.containingDeclaration} cannot have default arguments")
|
||||
}
|
||||
container.findDefaultMethod(jvmSignature.methodName, jvmSignature.methodDesc, !Modifier.isStatic(caller.member!!.modifiers))
|
||||
}
|
||||
is KotlinConstructor -> {
|
||||
@@ -126,7 +138,7 @@ internal class KFunctionImpl private constructor(
|
||||
createStaticMethodCaller(member)
|
||||
}
|
||||
else -> null
|
||||
}?.createInlineClassAwareCallerIfNeeded(descriptor, isDefault = true)
|
||||
}?.createValueClassAwareCallerIfNeeded(descriptor, isDefault = true)
|
||||
}
|
||||
|
||||
private val boundReceiver
|
||||
@@ -144,7 +156,7 @@ internal class KFunctionImpl private constructor(
|
||||
private fun createConstructorCaller(
|
||||
member: Constructor<*>, descriptor: FunctionDescriptor, isDefault: Boolean
|
||||
): CallerImpl<Constructor<*>> {
|
||||
return if (!isDefault && shouldHideConstructorDueToInlineClassTypeValueParameters(descriptor)) {
|
||||
return if (!isDefault && shouldHideConstructorDueToValueClassTypeValueParameters(descriptor)) {
|
||||
if (isBound)
|
||||
CallerImpl.AccessorForHiddenBoundConstructor(member, boundReceiver)
|
||||
else
|
||||
|
||||
@@ -18,8 +18,10 @@ package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.jvm.internal.calls.ValueClassAwareCaller
|
||||
|
||||
internal class KParameterImpl(
|
||||
val callable: KCallableImpl<*>,
|
||||
@@ -39,6 +41,27 @@ internal class KParameterImpl(
|
||||
return if (name.isSpecial) null else name.asString()
|
||||
}
|
||||
|
||||
|
||||
private fun compoundType(vararg types: Type): Type = when (types.size) {
|
||||
0 -> throw KotlinReflectionNotSupportedError("Expected at least 1 type for compound type")
|
||||
1 -> types.single()
|
||||
else -> CompoundTypeImpl(types)
|
||||
}
|
||||
|
||||
private class CompoundTypeImpl(val types: Array<out Type>) : Type {
|
||||
private val hashCode = types.contentHashCode()
|
||||
override fun getTypeName(): String {
|
||||
return types.joinToString(", ", "[", "]")
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is CompoundTypeImpl && this.types contentEquals other.types
|
||||
|
||||
override fun hashCode(): Int = hashCode
|
||||
|
||||
override fun toString(): String = typeName
|
||||
}
|
||||
|
||||
override val type: KType
|
||||
get() = KTypeImpl(descriptor.type) {
|
||||
val descriptor = descriptor
|
||||
@@ -53,7 +76,16 @@ internal class KParameterImpl(
|
||||
(callable.descriptor.containingDeclaration as ClassDescriptor).toJavaClass()
|
||||
?: throw KotlinReflectionInternalError("Cannot determine receiver Java type of inherited declaration: $descriptor")
|
||||
} else {
|
||||
callable.caller.parameterTypes[index]
|
||||
when (val caller = callable.caller) {
|
||||
is ValueClassAwareCaller -> {
|
||||
val slice = caller.getRealSlicesOfParameters(index)
|
||||
val parameterTypes = caller.parameterTypes.slice(slice)
|
||||
compoundType(*parameterTypes.toTypedArray())
|
||||
}
|
||||
is ValueClassAwareCaller.MultiFieldValueClassPrimaryConstructorCaller ->
|
||||
compoundType(*caller.originalParametersGroups[index].toTypedArray())
|
||||
else -> caller.parameterTypes[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -271,8 +271,9 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
|
||||
if (property.descriptor.isUnderlyingPropertyOfInlineClass() &&
|
||||
property.descriptor.visibility == DescriptorVisibilities.INTERNAL
|
||||
) {
|
||||
val unboxMethod = property.descriptor.containingDeclaration.toInlineClass()?.getUnboxMethod(property.descriptor)
|
||||
?: throw KotlinReflectionInternalError("Underlying property of inline class $property should have a field")
|
||||
val unboxMethod =
|
||||
property.descriptor.containingDeclaration.toInlineClass()?.getInlineClassUnboxMethod(property.descriptor)
|
||||
?: throw KotlinReflectionInternalError("Underlying property of inline class $property should have a field")
|
||||
if (isBound) InternalUnderlyingValOfInlineClass.Bound(unboxMethod, boundReceiver)
|
||||
else InternalUnderlyingValOfInlineClass.Unbound(unboxMethod)
|
||||
} else {
|
||||
@@ -316,7 +317,7 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
|
||||
return if (isBound) CallerImpl.Method.BoundInstance(accessor, boundReceiver)
|
||||
else CallerImpl.Method.Instance(accessor)
|
||||
}
|
||||
}.createInlineClassAwareCallerIfNeeded(descriptor)
|
||||
}.createValueClassAwareCallerIfNeeded(descriptor)
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.isJvmFieldPropertyInCompanionObject(): Boolean {
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||
import org.jetbrains.kotlin.resolve.isMultiFieldValueClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
@@ -51,6 +52,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.jvm.internal.calls.toJvmDescriptor
|
||||
|
||||
internal sealed class JvmFunctionSignature {
|
||||
abstract fun asString(): String
|
||||
@@ -174,10 +176,27 @@ internal object RuntimeTypeMapper {
|
||||
}
|
||||
if (proto is ProtoBuf.Constructor) {
|
||||
JvmProtoBufUtil.getJvmConstructorSignature(proto, function.nameResolver, function.typeTable)?.let { signature ->
|
||||
return if (possiblySubstitutedFunction.containingDeclaration.isInlineClass())
|
||||
JvmFunctionSignature.KotlinFunction(signature)
|
||||
else
|
||||
JvmFunctionSignature.KotlinConstructor(signature)
|
||||
return when {
|
||||
possiblySubstitutedFunction.containingDeclaration.isInlineClass() ->
|
||||
JvmFunctionSignature.KotlinFunction(signature)
|
||||
possiblySubstitutedFunction.containingDeclaration.isMultiFieldValueClass() -> {
|
||||
val realSignature = if ((possiblySubstitutedFunction as ConstructorDescriptor).isPrimary) {
|
||||
require(signature.name == "constructor-impl" && signature.desc.endsWith(")V")) { "Invalid signature: $signature" }
|
||||
signature
|
||||
} else {
|
||||
require(signature.name == "constructor-impl") { "Invalid signature: $signature" }
|
||||
val constructedClass = possiblySubstitutedFunction.constructedClass.toJvmDescriptor()
|
||||
if (signature.desc.endsWith(")V")) {
|
||||
signature.copy(desc = signature.desc.removeSuffix("V") + constructedClass)
|
||||
} else {
|
||||
require(signature.desc.endsWith(constructedClass)) { "Invalid signature: $signature" }
|
||||
signature
|
||||
}
|
||||
}
|
||||
JvmFunctionSignature.KotlinFunction(realSignature)
|
||||
}
|
||||
else -> JvmFunctionSignature.KotlinConstructor(signature)
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapJvmFunctionSignature(function)
|
||||
|
||||
@@ -122,7 +122,7 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
}
|
||||
}
|
||||
|
||||
class BoundStatic(method: ReflectMethod, private val boundReceiver: Any?) : BoundCaller, Method(
|
||||
class BoundStatic(method: ReflectMethod, internal val boundReceiver: Any?) : BoundCaller, Method(
|
||||
method, requiresInstance = false, parameterTypes = method.genericParameterTypes.dropFirst()
|
||||
) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
@@ -131,6 +131,21 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
}
|
||||
}
|
||||
|
||||
class BoundStaticMultiFieldValueClass(
|
||||
method: ReflectMethod, internal val boundReceiverComponents: Array<Any?>
|
||||
) : BoundCaller, Method(
|
||||
method = method,
|
||||
requiresInstance = false,
|
||||
parameterTypes = method.genericParameterTypes.drop(boundReceiverComponents.size).toTypedArray()
|
||||
) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return callMethod(null, arrayOf(*boundReceiverComponents, *args))
|
||||
}
|
||||
|
||||
val receiverComponentsCount: Int get() = boundReceiverComponents.size
|
||||
}
|
||||
|
||||
class BoundInstance(method: ReflectMethod, private val boundReceiver: Any?) : BoundCaller,
|
||||
Method(method, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
|
||||
+211
-84
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -7,29 +7,50 @@ package kotlin.reflect.jvm.internal.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.runtime.structure.desc
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.multiFieldValueClassRepresentation
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.asSimpleType
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl
|
||||
import kotlin.reflect.jvm.internal.KotlinReflectionInternalError
|
||||
import kotlin.reflect.jvm.internal.defaultPrimitiveValue
|
||||
import kotlin.reflect.jvm.internal.toJavaClass
|
||||
|
||||
/**
|
||||
* A caller that is used whenever the declaration has inline classes in its parameter types or return type.
|
||||
* Each argument of an inline class type is unboxed, and the return value (if it's of an inline class type) is boxed.
|
||||
* A caller that is used whenever the declaration has value classes in its parameter types or inline class in return type.
|
||||
* Each argument of an value 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 ValueClassAwareCaller<out M : Member?>(
|
||||
descriptor: CallableMemberDescriptor,
|
||||
private val caller: Caller<M>,
|
||||
oldCaller: Caller<M>,
|
||||
private val isDefault: Boolean
|
||||
) : Caller<M> {
|
||||
override val member: M
|
||||
get() = caller.member
|
||||
|
||||
private val caller: Caller<M> = if (oldCaller is CallerImpl.Method.BoundStatic) {
|
||||
val receiverType = (descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter)?.type
|
||||
if (receiverType != null && receiverType.needsMfvcFlattening()) {
|
||||
val unboxMethods = getMfvcUnboxMethods(receiverType.asSimpleType())!!
|
||||
val boundReceiverComponents = unboxMethods.map { it.invoke(oldCaller.boundReceiver) }.toTypedArray()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
CallerImpl.Method.BoundStaticMultiFieldValueClass(oldCaller.member, boundReceiverComponents) as Caller<M>
|
||||
} else {
|
||||
oldCaller
|
||||
}
|
||||
} else {
|
||||
oldCaller
|
||||
}
|
||||
|
||||
override val member: M = caller.member
|
||||
|
||||
|
||||
override val returnType: Type
|
||||
get() = caller.returnType
|
||||
@@ -37,24 +58,18 @@ internal class InlineClassAwareCaller<out M : Member?>(
|
||||
override val parameterTypes: List<Type>
|
||||
get() = caller.parameterTypes
|
||||
|
||||
private class BoxUnboxData(val argumentRange: IntRange, val unbox: Array<Method?>, val box: Method?) {
|
||||
operator fun component1(): IntRange = argumentRange
|
||||
operator fun component2(): Array<Method?> = unbox
|
||||
operator fun component3(): Method? = box
|
||||
}
|
||||
private class BoxUnboxData(val argumentRange: IntRange, val unboxParameters: Array<List<Method>?>, val box: Method?)
|
||||
|
||||
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.
|
||||
if (descriptor.isGetterOfUnderlyingPropertyOfValueClass()) {
|
||||
// Getter of the underlying val of a value class is always called on a boxed receiver,
|
||||
// no argument unboxing is required.
|
||||
return@run BoxUnboxData(IntRange.EMPTY, emptyArray(), box)
|
||||
}
|
||||
|
||||
val shift = when {
|
||||
caller is CallerImpl.Method.BoundStatic -> {
|
||||
caller is CallerImpl.Method.BoundStatic || caller is CallerImpl.Method.BoundStaticMultiFieldValueClass -> {
|
||||
// Bound reference to a static method is only possible for a top level extension function/property,
|
||||
// and in that case the number of expected arguments is one less than usual, hence -1
|
||||
-1
|
||||
@@ -64,9 +79,9 @@ internal class InlineClassAwareCaller<out M : Member?>(
|
||||
if (caller is BoundCaller) -1 else 0
|
||||
|
||||
descriptor.dispatchReceiverParameter != null && caller !is BoundCaller -> {
|
||||
// If we have an unbound reference to the inline class member,
|
||||
// If we have an unbound reference to the value class member,
|
||||
// its receiver (which is passed as argument 0) should also be unboxed.
|
||||
if (descriptor.containingDeclaration.isInlineClass())
|
||||
if (descriptor.containingDeclaration.isValueClass())
|
||||
0
|
||||
else
|
||||
1
|
||||
@@ -75,117 +90,229 @@ internal class InlineClassAwareCaller<out M : Member?>(
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val kotlinParameterTypes: List<KotlinType> = ArrayList<KotlinType>().also { kotlinParameterTypes ->
|
||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type
|
||||
if (extensionReceiverType != null) {
|
||||
kotlinParameterTypes.add(extensionReceiverType)
|
||||
} else if (descriptor is ConstructorDescriptor) {
|
||||
val constructedClass = descriptor.constructedClass
|
||||
if (constructedClass.isInner) {
|
||||
kotlinParameterTypes.add((constructedClass.containingDeclaration as ClassDescriptor).defaultType)
|
||||
}
|
||||
} else {
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
if (containingDeclaration is ClassDescriptor && containingDeclaration.isInlineClass()) {
|
||||
kotlinParameterTypes.add(containingDeclaration.defaultType)
|
||||
}
|
||||
}
|
||||
val flattenedShift = if (caller is CallerImpl.Method.BoundStaticMultiFieldValueClass) -caller.receiverComponentsCount else shift
|
||||
|
||||
descriptor.valueParameters.mapTo(kotlinParameterTypes, ValueParameterDescriptor::getType)
|
||||
}
|
||||
val kotlinParameterTypes: List<KotlinType> = makeKotlinParameterTypes(descriptor) { isValueClass() }
|
||||
|
||||
fun typeSize(type: KotlinType): Int = getMfvcUnboxMethods(type.asSimpleType())?.size ?: 1
|
||||
|
||||
// If the default argument is set,
|
||||
// (kotlinParameterTypes.size + Integer.SIZE - 1) / Integer.SIZE masks and one marker are added to the end of the argument.
|
||||
val extraArgumentsTail = (if (isDefault) ((kotlinParameterTypes.size + Integer.SIZE - 1) / Integer.SIZE) + 1 else 0) +
|
||||
(if (descriptor is FunctionDescriptor && descriptor.isSuspend) 1 else 0)
|
||||
val expectedArgsSize = kotlinParameterTypes.size + shift + extraArgumentsTail
|
||||
if (arity != expectedArgsSize) {
|
||||
throw KotlinReflectionInternalError(
|
||||
"Inconsistent number of parameters in the descriptor and Java reflection object: $arity != $expectedArgsSize\n" +
|
||||
"Calling: $descriptor\n" +
|
||||
"Parameter types: ${this.parameterTypes})\n" +
|
||||
"Default: $isDefault"
|
||||
)
|
||||
}
|
||||
// (kotlinParameterTypes.size + Int.SIZE_BITS - 1) / Int.SIZE_BITS masks and one marker are added to the end of the argument.
|
||||
val extraArgumentsTail =
|
||||
(if (isDefault) ((kotlinParameterTypes.sumOf(::typeSize) + Int.SIZE_BITS - 1) / Int.SIZE_BITS) + 1 else 0) +
|
||||
(if (descriptor is FunctionDescriptor && descriptor.isSuspend) 1 else 0)
|
||||
val expectedArgsSize = kotlinParameterTypes.sumOf(::typeSize) + flattenedShift + extraArgumentsTail
|
||||
checkParametersSize(expectedArgsSize, descriptor, isDefault)
|
||||
|
||||
// maxOf is needed because in case of a bound top level extension, shift can be -1 (see above). But in that case, we need not unbox
|
||||
// the extension receiver argument, since it has already been unboxed at compile time and generated into the reference
|
||||
val argumentRange = maxOf(shift, 0) until (kotlinParameterTypes.size + shift)
|
||||
|
||||
val unbox = Array(expectedArgsSize) { i ->
|
||||
if (i in argumentRange) {
|
||||
kotlinParameterTypes[i - shift].toInlineClass()?.getUnboxMethod(descriptor)
|
||||
} else null
|
||||
if (i in argumentRange)
|
||||
getValueClassUnboxMethods(kotlinParameterTypes[i - shift].asSimpleType(), descriptor)
|
||||
else null
|
||||
}
|
||||
|
||||
BoxUnboxData(argumentRange, unbox, box)
|
||||
}
|
||||
|
||||
private val slices = buildList {
|
||||
var currentOffset = when (caller) {
|
||||
is CallerImpl.Method.BoundStaticMultiFieldValueClass -> caller.boundReceiverComponents.size
|
||||
is CallerImpl.Method.BoundStatic -> 1
|
||||
else -> 0
|
||||
}
|
||||
if (currentOffset > 0) {
|
||||
add(0 until currentOffset)
|
||||
}
|
||||
for (parameterUnboxMethods in data.unboxParameters) {
|
||||
val length = parameterUnboxMethods?.size ?: 1
|
||||
add(currentOffset until (currentOffset + length))
|
||||
currentOffset += length
|
||||
}
|
||||
}.toTypedArray()
|
||||
|
||||
fun getRealSlicesOfParameters(index: Int): IntRange = when {
|
||||
index in slices.indices -> slices[index]
|
||||
slices.isEmpty() -> index..index
|
||||
else -> {
|
||||
val start = (index - slices.size) + (slices.last().last + 1)
|
||||
start..start
|
||||
}
|
||||
}
|
||||
|
||||
private val hasMfvcParameters = data.argumentRange.any { (data.unboxParameters[it] ?: return@any false).size > 1 }
|
||||
|
||||
override fun call(args: Array<*>): Any? {
|
||||
val (range, unbox, box) = data
|
||||
val range = data.argumentRange
|
||||
val unbox = data.unboxParameters
|
||||
val box = data.box
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val unboxed = Array(args.size) { index ->
|
||||
val arg = args[index]
|
||||
|
||||
if (index in range) {
|
||||
// Note that arg may be null in case we're calling a $default method and it's an optional parameter of an inline class type
|
||||
val method = unbox[index]
|
||||
|
||||
if (method != null) {
|
||||
if (arg != null) {
|
||||
method.invoke(arg)
|
||||
val unboxedArguments = when {
|
||||
range.isEmpty() -> args
|
||||
hasMfvcParameters -> buildList(args.size) {
|
||||
for (index in 0 until range.first) {
|
||||
add(args[index])
|
||||
}
|
||||
for (index in range) {
|
||||
val methods = unbox[index]
|
||||
val arg = args[index]
|
||||
// Note that arg may be null in case we're calling a $default method, and it's an optional parameter of a value class type
|
||||
if (methods != null) {
|
||||
methods.mapTo(this) { if (arg != null) it.invoke(arg) else defaultPrimitiveValue(it.returnType) }
|
||||
} else {
|
||||
defaultPrimitiveValue(method.returnType)
|
||||
add(arg)
|
||||
}
|
||||
}
|
||||
for (index in (range.last + 1)..args.lastIndex) {
|
||||
add(args[index])
|
||||
}
|
||||
}.toTypedArray()
|
||||
else -> Array(args.size) { index ->
|
||||
if (index in range) {
|
||||
val method = unbox[index]?.single()
|
||||
val arg = args[index]
|
||||
// Note that arg may be null in case we're calling a $default method, and it's an optional parameter of a inline class type
|
||||
when {
|
||||
method == null -> arg
|
||||
arg != null -> method.invoke(arg)
|
||||
else -> defaultPrimitiveValue(method.returnType)
|
||||
}
|
||||
} else {
|
||||
arg
|
||||
args[index]
|
||||
}
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
}
|
||||
|
||||
val result = caller.call(unboxed)
|
||||
val result = caller.call(unboxedArguments)
|
||||
|
||||
// box is not null only for inline classes
|
||||
return box?.invoke(null, result) ?: result
|
||||
}
|
||||
|
||||
class MultiFieldValueClassPrimaryConstructorCaller(
|
||||
descriptor: FunctionDescriptor,
|
||||
container: KDeclarationContainerImpl,
|
||||
constructorDesc: String,
|
||||
originalParameters: List<ParameterDescriptor>
|
||||
) : Caller<Nothing?> {
|
||||
private val constructorImpl = container.findMethodBySignature("constructor-impl", constructorDesc)!!
|
||||
private val boxMethod = container.findMethodBySignature("box-impl", constructorDesc.removeSuffix("V") + container.jClass.desc)!!
|
||||
private val parameterUnboxMethods: List<List<Method>?> = originalParameters.map { parameter ->
|
||||
getValueClassUnboxMethods(parameter.type.asSimpleType(), descriptor)
|
||||
}
|
||||
override val member: Nothing?
|
||||
get() = null
|
||||
override val returnType: Type
|
||||
get() = boxMethod.returnType
|
||||
|
||||
val originalParametersGroups: List<List<Class<*>>> = originalParameters.mapIndexed { index, it ->
|
||||
val classDescriptor = it.type.constructor.declarationDescriptor as ClassDescriptor
|
||||
parameterUnboxMethods[index]?.map { it.returnType } ?: listOf(classDescriptor.toJavaClass()!!)
|
||||
}
|
||||
|
||||
override val parameterTypes: List<Type> = originalParametersGroups.flatten()
|
||||
|
||||
override fun call(args: Array<*>): Any? {
|
||||
val newArgs = (args zip parameterUnboxMethods)
|
||||
.flatMap { (arg, unboxMethods) -> unboxMethods?.map { it.invoke(arg) } ?: listOf(arg) }.toTypedArray()
|
||||
constructorImpl.invoke(null, *newArgs)
|
||||
return boxMethod.invoke(null, *newArgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <M : Member?> Caller<M>.createInlineClassAwareCallerIfNeeded(
|
||||
internal fun ClassifierDescriptor.toJvmDescriptor(): String = ClassMapperLite.mapClass(classId!!.asString())
|
||||
|
||||
|
||||
private fun getValueClassUnboxMethods(type: SimpleType, descriptor: CallableMemberDescriptor): List<Method>? =
|
||||
getMfvcUnboxMethods(type) ?: type.toInlineClass()?.getInlineClassUnboxMethod(descriptor)?.let(::listOf)
|
||||
|
||||
internal fun getMfvcUnboxMethods(type: SimpleType): List<Method>? {
|
||||
fun getUnboxMethodNameSuffixes(type: SimpleType): List<String>? =
|
||||
if (type.needsMfvcFlattening()) (type.constructor.declarationDescriptor as ClassDescriptor)
|
||||
.multiFieldValueClassRepresentation!!.underlyingPropertyNamesToTypes.flatMap { (name, innerType) ->
|
||||
getUnboxMethodNameSuffixes(innerType)?.map { "${name.identifier}-${it}" } ?: listOf(name.identifier)
|
||||
}
|
||||
else null
|
||||
|
||||
val unboxMethodsNames = getUnboxMethodNameSuffixes(type.asSimpleType())?.map { "unbox-impl-$it" } ?: return null
|
||||
val javaClass = (type.constructor.declarationDescriptor as ClassDescriptor).toJavaClass()!!
|
||||
return unboxMethodsNames.map { javaClass.getDeclaredMethod(it) }
|
||||
}
|
||||
|
||||
private fun Caller<*>.checkParametersSize(
|
||||
expectedArgsSize: Int,
|
||||
descriptor: CallableMemberDescriptor,
|
||||
isDefault: Boolean,
|
||||
) {
|
||||
if (arity != expectedArgsSize) {
|
||||
throw KotlinReflectionInternalError(
|
||||
"Inconsistent number of parameters in the descriptor and Java reflection object: $arity != $expectedArgsSize\n" +
|
||||
"Calling: $descriptor\n" +
|
||||
"Parameter types: ${this.parameterTypes})\n" +
|
||||
"Default: $isDefault"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeKotlinParameterTypes(
|
||||
descriptor: CallableMemberDescriptor, isSpecificClass: ClassDescriptor.() -> Boolean
|
||||
): List<KotlinType> = ArrayList<KotlinType>().also { kotlinParameterTypes ->
|
||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type
|
||||
if (extensionReceiverType != null) {
|
||||
kotlinParameterTypes.add(extensionReceiverType)
|
||||
} else if (descriptor is ConstructorDescriptor) {
|
||||
val constructedClass = descriptor.constructedClass
|
||||
if (constructedClass.isInner) {
|
||||
kotlinParameterTypes.add((constructedClass.containingDeclaration as ClassDescriptor).defaultType)
|
||||
}
|
||||
} else {
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
if (containingDeclaration is ClassDescriptor && containingDeclaration.isSpecificClass()) {
|
||||
kotlinParameterTypes.add(containingDeclaration.defaultType)
|
||||
}
|
||||
}
|
||||
|
||||
descriptor.valueParameters.mapTo(kotlinParameterTypes, ValueParameterDescriptor::getType)
|
||||
}
|
||||
|
||||
internal fun <M : Member?> Caller<M>.createValueClassAwareCallerIfNeeded(
|
||||
descriptor: CallableMemberDescriptor,
|
||||
isDefault: Boolean = false
|
||||
): Caller<M> {
|
||||
val needsInlineAwareCaller: Boolean =
|
||||
descriptor.isGetterOfUnderlyingPropertyOfInlineClass() ||
|
||||
descriptor.valueParameters.any { it.type.isInlineClassType() } ||
|
||||
val needsValueClassAwareCaller: Boolean =
|
||||
descriptor.isGetterOfUnderlyingPropertyOfValueClass() ||
|
||||
descriptor.contextReceiverParameters.any { it.type.isValueClassType() } ||
|
||||
descriptor.valueParameters.any { it.type.isValueClassType() } ||
|
||||
descriptor.returnType?.isInlineClassType() == true ||
|
||||
this !is BoundCaller && descriptor.hasInlineClassReceiver()
|
||||
descriptor.hasValueClassReceiver()
|
||||
|
||||
return if (needsInlineAwareCaller) InlineClassAwareCaller(descriptor, this, isDefault) else this
|
||||
return if (needsValueClassAwareCaller) ValueClassAwareCaller(descriptor, this, isDefault) else this
|
||||
}
|
||||
|
||||
private fun CallableMemberDescriptor.hasInlineClassReceiver() =
|
||||
expectedReceiverType?.isInlineClassType() == true
|
||||
private fun CallableMemberDescriptor.hasValueClassReceiver() =
|
||||
expectedReceiverType?.isValueClassType() == true
|
||||
|
||||
internal fun Class<*>.getUnboxMethod(descriptor: CallableMemberDescriptor): Method =
|
||||
internal fun Class<*>.getInlineClassUnboxMethod(descriptor: CallableMemberDescriptor): Method =
|
||||
try {
|
||||
getDeclaredMethod("unbox" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
throw KotlinReflectionInternalError("No unbox method found in inline class: $this (calling $descriptor)")
|
||||
}
|
||||
|
||||
internal fun Class<*>.getBoxMethod(descriptor: CallableMemberDescriptor): Method =
|
||||
private fun Class<*>.getBoxMethod(descriptor: CallableMemberDescriptor): Method =
|
||||
try {
|
||||
getDeclaredMethod("box" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS, getUnboxMethod(descriptor).returnType)
|
||||
getDeclaredMethod("box" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS, getInlineClassUnboxMethod(descriptor).returnType)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
throw KotlinReflectionInternalError("No box method found in inline class: $this (calling $descriptor)")
|
||||
}
|
||||
|
||||
internal fun KotlinType.toInlineClass(): Class<*>? {
|
||||
private fun KotlinType.toInlineClass(): Class<*>? {
|
||||
// See computeExpandedTypeForInlineClass.
|
||||
// TODO: add tests on type parameters with inline class bounds.
|
||||
// TODO: add tests on usages of inline classes in Java.
|
||||
// TODO: add tests on type parameters with value class bounds.
|
||||
// TODO: add tests on usages of value classes in Java.
|
||||
val klass = constructor.declarationDescriptor.toInlineClass() ?: return null
|
||||
if (!TypeUtils.isNullableType(this)) return klass
|
||||
|
||||
@@ -217,7 +344,7 @@ internal fun Any?.coerceToExpectedReceiverType(descriptor: CallableMemberDescrip
|
||||
if (descriptor is PropertyDescriptor && descriptor.isUnderlyingPropertyOfInlineClass()) return this
|
||||
|
||||
val expectedReceiverType = descriptor.expectedReceiverType
|
||||
val unboxMethod = expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
|
||||
val unboxMethod = expectedReceiverType?.toInlineClass()?.getInlineClassUnboxMethod(descriptor) ?: return this
|
||||
|
||||
return unboxMethod.invoke(this)
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.constants.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.isInlineClassType
|
||||
import org.jetbrains.kotlin.resolve.needsMfvcFlattening
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import java.lang.reflect.Field
|
||||
@@ -268,6 +269,8 @@ internal fun <M : MessageLite, D : CallableDescriptor> deserializeToDescriptor(
|
||||
|
||||
internal val KType.isInlineClassType: Boolean
|
||||
get() = (this as? KTypeImpl)?.type?.isInlineClassType() == true
|
||||
internal val KType.needsMultiFieldValueClassFlattening: Boolean
|
||||
get() = (this as? KTypeImpl)?.type?.needsMfvcFlattening() == true
|
||||
|
||||
internal fun defaultPrimitiveValue(type: Type): Any? =
|
||||
if (type is Class<*> && type.isPrimitive) {
|
||||
|
||||
Reference in New Issue
Block a user