Avoid multiple subsequent reading of the same class-file in front-end

^KT-23466 Fixed
This commit is contained in:
Denis Zharkov
2018-12-13 13:51:56 +03:00
parent bc61e5a3bc
commit f153d97f40
20 changed files with 148 additions and 64 deletions
@@ -22,7 +22,15 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
interface JavaClassFinder {
fun findClass(classId: ClassId): JavaClass?
data class Request(
val classId: ClassId,
@Suppress("ArrayInDataClass")
val previouslyFoundClassFileContent: ByteArray? = null,
val outerClass: JavaClass? = null
)
fun findClass(request: Request): JavaClass?
fun findClass(classId: ClassId): JavaClass? = findClass(Request(classId))
fun findPackage(fqName: FqName): JavaPackage?
@@ -706,7 +706,12 @@ class LazyJavaClassMemberScope(
)
} else null
} else {
c.components.finder.findClass(ownerDescriptor.classId!!.createNestedClassId(name))?.let {
c.components.finder.findClass(
JavaClassFinder.Request(
ownerDescriptor.classId!!.createNestedClassId(name),
outerClass = jClass
)
)?.let {
LazyJavaClassDescriptor(c, ownerDescriptor, it)
.also(c.components.javaClassesTracker::reportClass)
}
@@ -22,10 +22,12 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaPackage
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.name.ClassId
@@ -33,6 +35,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.storage.NullableLazyValue
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.alwaysTrue
import java.util.*
@@ -51,12 +54,14 @@ class LazyJavaPackageScope(
c.storageManager.createMemoizedFunctionWithNullableValues<FindClassRequest, ClassDescriptor> classByRequest@{ request ->
val requestClassId = ClassId(ownerDescriptor.fqName, request.name)
val kotlinBinaryClass =
val kotlinClassOrClassFileContent =
// These branches should be semantically equal, but the first one could be faster
if (request.javaClass != null)
c.components.kotlinClassFinder.findKotlinClass(request.javaClass)
c.components.kotlinClassFinder.findKotlinClassOrContent(request.javaClass)
else
c.components.kotlinClassFinder.findKotlinClass(requestClassId)
c.components.kotlinClassFinder.findKotlinClassOrContent(requestClassId)
val kotlinBinaryClass = kotlinClassOrClassFileContent?.toKotlinJvmBinaryClass()
val classId = kotlinBinaryClass?.classId
// Nested/local classes can be found when running in CLI in case when request.name looks like 'Outer$Inner'
@@ -69,7 +74,14 @@ class LazyJavaPackageScope(
is KotlinClassLookupResult.Found -> kotlinResult.descriptor
is KotlinClassLookupResult.SyntheticClass -> null
is KotlinClassLookupResult.NotFound -> {
val javaClass = request.javaClass ?: c.components.finder.findClass(requestClassId)
val javaClass =
request.javaClass ?: c.components.finder.findClass(
JavaClassFinder.Request(
requestClassId,
kotlinClassOrClassFileContent?.safeAs<KotlinClassFinder.Result.ClassFileContent>()
?.content
)
)
if (javaClass?.lightClassOriginKind == LightClassOriginKind.BINARY) {
throw IllegalStateException(
@@ -21,7 +21,23 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.KotlinMetadataFinder
interface KotlinClassFinder : KotlinMetadataFinder {
fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass?
fun findKotlinClassOrContent(classId: ClassId): Result?
fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass?
fun findKotlinClassOrContent(javaClass: JavaClass): Result?
fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? =
findKotlinClassOrContent(classId)?.toKotlinJvmBinaryClass()
fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass? =
findKotlinClassOrContent(javaClass)?.toKotlinJvmBinaryClass()
sealed class Result {
fun toKotlinJvmBinaryClass(): KotlinJvmBinaryClass? = (this as? KotlinClass)?.kotlinJvmBinaryClass
data class KotlinClass(val kotlinJvmBinaryClass: KotlinJvmBinaryClass) : Result()
data class ClassFileContent(
@Suppress("ArrayInDataClass")
val content: ByteArray
) : Result()
}
}
@@ -25,7 +25,8 @@ import kotlin.reflect.jvm.internal.structure.ReflectJavaClass
import kotlin.reflect.jvm.internal.structure.ReflectJavaPackage
class ReflectJavaClassFinder(private val classLoader: ClassLoader) : JavaClassFinder {
override fun findClass(classId: ClassId): JavaClass? {
override fun findClass(request: JavaClassFinder.Request): JavaClass? {
val classId = request.classId
val packageFqName = classId.packageFqName
val relativeClassName = classId.relativeClassName.asString().replace('.', '$')
val name =
@@ -18,19 +18,19 @@ package kotlin.reflect.jvm.internal.components
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import java.io.InputStream
class ReflectKotlinClassFinder(private val classLoader: ClassLoader) : KotlinClassFinder {
private fun findKotlinClass(fqName: String): KotlinJvmBinaryClass? {
return classLoader.tryLoadClass(fqName)?.let { ReflectKotlinClass.create(it) }
private fun findKotlinClass(fqName: String): KotlinClassFinder.Result? {
return classLoader.tryLoadClass(fqName)?.let { ReflectKotlinClass.create(it) }?.let(::KotlinClass)
}
override fun findKotlinClass(classId: ClassId) = findKotlinClass(classId.toRuntimeFqName())
override fun findKotlinClassOrContent(classId: ClassId) = findKotlinClass(classId.toRuntimeFqName())
override fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass? {
override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? {
// TODO: go through javaClass's class loader
return findKotlinClass(javaClass.fqName?.asString() ?: return null)
}