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
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.load.java
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.impl.JavaPackageImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
@@ -33,10 +32,10 @@ class JavaClassFinderImpl : AbstractJavaClassFinder() {
super.initialize(trace, codeAnalyzer)
}
override fun findClass(classId: ClassId): JavaClass? = javaFacade.findClass(classId, javaSearchScope)
override fun findClass(request: JavaClassFinder.Request): JavaClass? = javaFacade.findClass(request, javaSearchScope)
override fun findPackage(fqName: FqName) = javaFacade.findPackage(fqName.asString(), javaSearchScope)?.let { JavaPackageImpl(it, javaSearchScope) }
override fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? = javaFacade.knownClassNamesInPackage(packageFqName)
}
}
@@ -201,11 +201,16 @@ class BinaryJavaClass(
override fun visitAnnotation(desc: String, visible: Boolean) =
BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser)
override fun findInnerClass(name: Name): JavaClass? {
override fun findInnerClass(name: Name): JavaClass? = findInnerClass(name, classFileContent = null)
fun findInnerClass(name: Name, classFileContent: ByteArray?): JavaClass? {
val access = ownInnerClassNameToAccess[name] ?: return null
return virtualFile.parent.findChild("${virtualFile.nameWithoutExtension}$$name.class")?.let {
BinaryJavaClass(it, fqName.child(name), context.copyForMember(), signatureParser, access, this)
BinaryJavaClass(
it, fqName.child(name), context.copyForMember(), signatureParser, access, this,
classFileContent
)
}
}
}
@@ -28,14 +28,17 @@ class KotlinBinaryClassCache : Disposable {
private class RequestCache {
internal var virtualFile: VirtualFile? = null
internal var modificationStamp: Long = 0
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
internal var result: KotlinClassFinder.Result? = null
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
fun cache(
file: VirtualFile,
result: KotlinClassFinder.Result?
): KotlinClassFinder.Result? {
virtualFile = file
virtualFileKotlinClass = aClass
this.result = result
modificationStamp = file.modificationStamp
return aClass
return result
}
}
@@ -53,7 +56,9 @@ class KotlinBinaryClassCache : Disposable {
}
companion object {
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
fun getKotlinBinaryClassOrClassFileContent(
file: VirtualFile, fileContent: ByteArray? = null
): KotlinClassFinder.Result? {
if (file.fileType !== JavaClassFileType.INSTANCE) return null
if (file.name == PsiJavaModule.MODULE_INFO_CLS_FILE) return null
@@ -62,7 +67,7 @@ class KotlinBinaryClassCache : Disposable {
val requestCache = service.cache.get()
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
return requestCache.virtualFileKotlinClass
return requestCache.result
}
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
@@ -27,14 +27,17 @@ class KotlinBinaryClassCache : Disposable {
private class RequestCache {
internal var virtualFile: VirtualFile? = null
internal var modificationStamp: Long = 0
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
internal var result: KotlinClassFinder.Result? = null
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
fun cache(
file: VirtualFile,
result: KotlinClassFinder.Result?
): KotlinClassFinder.Result? {
virtualFile = file
virtualFileKotlinClass = aClass
this.result = result
modificationStamp = file.modificationStamp
return aClass
return result
}
}
@@ -52,14 +55,16 @@ class KotlinBinaryClassCache : Disposable {
}
companion object {
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
fun getKotlinBinaryClassOrClassFileContent(
file: VirtualFile, fileContent: ByteArray? = null
): KotlinClassFinder.Result? {
if (file.fileType !== JavaClassFileType.INSTANCE) return null
val service = ServiceManager.getService(KotlinBinaryClassCache::class.java)
val requestCache = service.cache.get()
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
return requestCache.virtualFileKotlinClass
return requestCache.result
}
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
@@ -27,14 +27,17 @@ class KotlinBinaryClassCache : Disposable {
private class RequestCache {
internal var virtualFile: VirtualFile? = null
internal var modificationStamp: Long = 0
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
internal var result: KotlinClassFinder.Result? = null
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
fun cache(
file: VirtualFile,
result: KotlinClassFinder.Result?
): KotlinClassFinder.Result? {
virtualFile = file
virtualFileKotlinClass = aClass
this.result = result
modificationStamp = file.modificationStamp
return aClass
return result
}
}
@@ -52,14 +55,16 @@ class KotlinBinaryClassCache : Disposable {
}
companion object {
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
fun getKotlinBinaryClassOrClassFileContent(
file: VirtualFile, fileContent: ByteArray? = null
): KotlinClassFinder.Result? {
if (file.fileType !== JavaClassFileType.INSTANCE) return null
val service = ServiceManager.getService(KotlinBinaryClassCache::class.java)
val requestCache = service.cache.get()
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
return requestCache.virtualFileKotlinClass
return requestCache.result
}
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
@@ -27,12 +27,12 @@ import org.jetbrains.kotlin.utils.sure
abstract class VirtualFileFinder : KotlinClassFinder {
abstract fun findVirtualFileWithHeader(classId: ClassId): VirtualFile?
override fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? {
override fun findKotlinClassOrContent(classId: ClassId): KotlinClassFinder.Result? {
val file = findVirtualFileWithHeader(classId) ?: return null
return KotlinBinaryClassCache.getKotlinBinaryClass(file)
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file)
}
override fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass? {
override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? {
var file = (javaClass as? VirtualFileBoundJavaClass)?.virtualFile ?: return null
if (javaClass.outerClass != null) {
@@ -41,7 +41,7 @@ abstract class VirtualFileFinder : KotlinClassFinder {
file = file.parent!!.findChild(classFileName(javaClass) + ".class").sure { "Virtual file not found for $javaClass" }
}
return KotlinBinaryClassCache.getKotlinBinaryClass(file)
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file)
}
private fun classFileName(jClass: JavaClass): String {
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.load.kotlin
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.util.PerformanceCounter
@@ -56,17 +57,19 @@ class VirtualFileKotlinClass private constructor(
private val perfCounter = PerformanceCounter.create("Binary class from Kotlin file")
@Deprecated("Use KotlinBinaryClassCache")
fun create(file: VirtualFile, fileContent: ByteArray?): VirtualFileKotlinClass? {
fun create(file: VirtualFile, fileContent: ByteArray?): KotlinClassFinder.Result? {
return perfCounter.time {
assert(file.fileType == JavaClassFileType.INSTANCE) { "Trying to read binary data from a non-class file $file" }
try {
val byteContent = fileContent ?: file.contentsToByteArray(false)
if (!byteContent.isEmpty()) {
return@time FileBasedKotlinClass.create(byteContent) {
name, classVersion, header, innerClasses ->
val kotlinJvmBinaryClass = FileBasedKotlinClass.create(byteContent) { name, classVersion, header, innerClasses ->
VirtualFileKotlinClass(file, name, classVersion, header, innerClasses)
}
return@time kotlinJvmBinaryClass?.let(::KotlinClass)
?: KotlinClassFinder.Result.ClassFileContent(byteContent)
}
}
catch (e: FileNotFoundException) {
@@ -18,11 +18,11 @@ package org.jetbrains.kotlin.resolve.jvm
import com.intellij.psi.impl.file.impl.JavaFileManager
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
interface KotlinCliJavaFileManager : JavaFileManager {
fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass?
fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass?
fun knownClassNamesInPackage(packageFqName: FqName): Set<String>?
}
@@ -43,6 +43,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.asJava.KtLightClassMarker;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.load.java.JavaClassFinder;
import org.jetbrains.kotlin.load.java.JavaClassFinderImpl;
import org.jetbrains.kotlin.load.java.structure.JavaClass;
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl;
@@ -104,9 +105,10 @@ public class KotlinJavaPsiFacade {
return emptyModifierList;
}
public JavaClass findClass(@NotNull ClassId classId, @NotNull GlobalSearchScope scope) {
public JavaClass findClass(@NotNull JavaClassFinder.Request request, @NotNull GlobalSearchScope scope) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly
ClassId classId = request.getClassId();
String qualifiedName = classId.asSingleFqName().asString();
if (shouldUseSlowResolve()) {
@@ -119,7 +121,7 @@ public class KotlinJavaPsiFacade {
for (KotlinPsiElementFinderWrapper finder : finders()) {
if (finder instanceof CliFinder) {
JavaClass aClass = ((CliFinder) finder).findClass(classId, scope);
JavaClass aClass = ((CliFinder) finder).findClass(request, scope);
if (aClass != null) return aClass;
}
else {
@@ -383,8 +385,8 @@ public class KotlinJavaPsiFacade {
return javaFileManager.findClass(qualifiedName, scope);
}
public JavaClass findClass(@NotNull ClassId classId, @NotNull GlobalSearchScope scope) {
return javaFileManager.findClass(classId, scope);
public JavaClass findClass(@NotNull JavaClassFinder.Request request, @NotNull GlobalSearchScope scope) {
return javaFileManager.findClass(request, scope);
}
@Nullable