From fb296b5b95a56fe380bdbe7c9f61d092bd21f275 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 3 Feb 2021 21:21:55 +0100 Subject: [PATCH] Do not create Array instance in kotlin-reflect where not necessary Although the previous code of computing JVM internal name from a Class instance was shorter, it led to unnecessary creation of array types, which is less performant and makes configuration of kotlin-reflect for GraalVM native-image more verbose. Unfortunately I didn't succeed in writing a test for this, since `Array.newInstance` calls a native method which doesn't record any trace of it being called in the class loader: the resulting array type never goes through findClass/loadClass, and is not visible via findLoadedClass. #KT-44594 Fixed --- .../runtime/structure/reflectClassUtil.kt | 23 ++++++++++++------- .../jvm/internal/KDeclarationContainerImpl.kt | 1 - .../kotlin/reflect/jvm/internal/KTypeImpl.kt | 1 - .../src/kotlin/reflect/jvm/internal/util.kt | 3 +++ 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/structure/reflectClassUtil.kt b/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/structure/reflectClassUtil.kt index fba5e29b020..76eec25e191 100644 --- a/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/structure/reflectClassUtil.kt +++ b/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/structure/reflectClassUtil.kt @@ -67,16 +67,23 @@ val Class<*>.classId: ClassId } val Class<*>.desc: String - get() { - if (this == Void.TYPE) return "V" - // This is a clever exploitation of a format returned by Class.getName(): for arrays, it's almost an internal name, - // but with '.' instead of '/' - return createArrayType().name.substring(1).replace('.', '/') + get() = when { + isPrimitive -> when (name) { + "boolean" -> "Z" + "char" -> "C" + "byte" -> "B" + "short" -> "S" + "int" -> "I" + "float" -> "F" + "long" -> "J" + "double" -> "D" + "void" -> "V" + else -> throw IllegalArgumentException("Unsupported primitive type: $this") + } + isArray -> name.replace('.', '/') + else -> "L${name.replace('.', '/')};" } -fun Class<*>.createArrayType(): Class<*> = - Array.newInstance(this, 0)::class.java - /** * @return all arguments of a parameterized type, including those of outer classes in case this type represents an inner generic. * The returned list starts with the arguments to the innermost class, then continues with those of its outer class, and so on. diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt index d83e7387884..35d14c74401 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt @@ -19,7 +19,6 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.runtime.components.RuntimeModuleData import org.jetbrains.kotlin.descriptors.runtime.components.tryLoadClass -import org.jetbrains.kotlin.descriptors.runtime.structure.createArrayType import org.jetbrains.kotlin.descriptors.runtime.structure.safeClassLoader import org.jetbrains.kotlin.descriptors.runtime.structure.wrapperByPrimitive import org.jetbrains.kotlin.load.java.JvmAbi diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt index 49666340603..5dd3fe793d4 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt @@ -19,7 +19,6 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.descriptors.runtime.structure.createArrayType import org.jetbrains.kotlin.descriptors.runtime.structure.parameterizedTypeArguments import org.jetbrains.kotlin.descriptors.runtime.structure.primitiveByWrapper import org.jetbrains.kotlin.types.KotlinType diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt index cda72d58eb5..cf7dc541715 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -101,6 +101,9 @@ private fun loadClass(classLoader: ClassLoader, packageName: String, className: return classLoader.tryLoadClass(fqName) } +internal fun Class<*>.createArrayType(): Class<*> = + java.lang.reflect.Array.newInstance(this, 0)::class.java + internal fun DescriptorVisibility.toKVisibility(): KVisibility? = when (this) { DescriptorVisibilities.PUBLIC -> KVisibility.PUBLIC