Avoid repeated reading of file contents from disk while building stubs

This commit is contained in:
Dmitry Jemerov
2017-01-30 18:08:25 +01:00
parent 66f7382e3a
commit bc9c40883c
6 changed files with 32 additions and 23 deletions
@@ -143,8 +143,9 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
}
@Override
public void loadClassAnnotations(@NotNull final AnnotationVisitor annotationVisitor) {
new ClassReader(getFileContents()).accept(new ClassVisitor(ASM5) {
public void loadClassAnnotations(@NotNull final AnnotationVisitor annotationVisitor, @Nullable byte[] cachedContents) {
byte[] fileContents = cachedContents != null ? cachedContents : getFileContents();
new ClassReader(fileContents).accept(new ClassVisitor(ASM5) {
@Override
public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitAnnotation(@NotNull String desc, boolean visible) {
return convertAnnotationVisitor(annotationVisitor, desc, innerClasses);
@@ -215,8 +216,9 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
}
@Override
public void visitMembers(@NotNull final MemberVisitor memberVisitor) {
new ClassReader(getFileContents()).accept(new ClassVisitor(ASM5) {
public void visitMembers(@NotNull final MemberVisitor memberVisitor, @Nullable byte[] cachedContents) {
byte[] fileContents = cachedContents != null ? cachedContents : getFileContents();
new ClassReader(fileContents).accept(new ClassVisitor(ASM5) {
@Override
public FieldVisitor visitField(int access, @NotNull String name, @NotNull String desc, String signature, Object value) {
final AnnotationVisitor v = memberVisitor.visitField(Name.identifier(name), desc, value);
@@ -67,6 +67,8 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
private fun ProtoContainer.Class.toBinaryClass(): KotlinJvmBinaryClass? =
(source as? KotlinJvmBinarySourceElement)?.binaryClass
protected open fun getCachedFileContent(kotlinClass: KotlinJvmBinaryClass): ByteArray? = null
override fun loadClassAnnotations(container: ProtoContainer.Class): List<A> {
val kotlinClass = container.toBinaryClass() ?: error("Class for loading annotations is not found: ${container.debugFqName()}")
@@ -79,7 +81,7 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
override fun visitEnd() {
}
})
}, getCachedFileContent(kotlinClass))
return result
}
@@ -294,7 +296,7 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
}
}
}
})
}, getCachedFileContent(kotlinClass))
return Storage(memberAnnotations, propertyConstants)
}
@@ -29,9 +29,9 @@ interface KotlinJvmBinaryClass {
*/
val location: String
fun loadClassAnnotations(visitor: AnnotationVisitor)
fun loadClassAnnotations(visitor: AnnotationVisitor, cachedContents: ByteArray?)
fun visitMembers(visitor: MemberVisitor)
fun visitMembers(visitor: MemberVisitor, cachedContents: ByteArray?)
val classHeader: KotlinClassHeader
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.load.kotlin.reflect
import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes
import org.jetbrains.kotlin.load.java.structure.reflect.classId
import org.jetbrains.kotlin.load.java.structure.reflect.desc
import org.jetbrains.kotlin.load.java.structure.reflect.isEnumClassOrSpecializedEnumEntryClass
@@ -61,11 +60,11 @@ class ReflectKotlinClass private constructor(
override val classId: ClassId
get() = klass.classId
override fun loadClassAnnotations(visitor: KotlinJvmBinaryClass.AnnotationVisitor) {
override fun loadClassAnnotations(visitor: KotlinJvmBinaryClass.AnnotationVisitor, cachedContents: ByteArray?) {
ReflectClassStructure.loadClassAnnotations(klass, visitor)
}
override fun visitMembers(visitor: KotlinJvmBinaryClass.MemberVisitor) {
override fun visitMembers(visitor: KotlinJvmBinaryClass.MemberVisitor, cachedContents: ByteArray?) {
ReflectClassStructure.visitMembers(klass, visitor)
}
@@ -34,7 +34,7 @@ class KotlinBuiltInStubBuilder : ClsStubBuilder() {
override fun buildFileStub(content: FileContent): PsiFileStub<*>? {
val virtualFile = content.file
assert(virtualFile.fileType == KotlinBuiltInFileType) { "Unexpected file type ${virtualFile.fileType}" }
val file = BuiltInDefinitionFile.read(virtualFile) ?: return null
val file = BuiltInDefinitionFile.read(content.content, virtualFile) ?: return null
when (file) {
is BuiltInDefinitionFile.Incompatible -> {
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.*
import org.jetbrains.kotlin.load.kotlin.AbstractBinaryClassAnnotationAndConstantLoader
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -51,11 +48,11 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
return null
}
return doBuildFileStub(file)
return doBuildFileStub(file, content.content)
}
fun doBuildFileStub(file: VirtualFile): PsiFileStub<KtFile>? {
val kotlinClass = IDEKotlinBinaryClassCache.getKotlinBinaryClass(file) ?: error("Can't find binary class for Kotlin file: $file")
fun doBuildFileStub(file: VirtualFile, fileContent: ByteArray): PsiFileStub<KtFile>? {
val kotlinClass = IDEKotlinBinaryClassCache.getKotlinBinaryClass(file, fileContent) ?: error("Can't find binary class for Kotlin file: $file")
val header = kotlinClass.classHeader
val classId = kotlinClass.classId
val packageFqName = classId.packageFqName
@@ -63,7 +60,7 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
return createIncompatibleAbiVersionFileStub()
}
val components = createStubBuilderComponents(file, packageFqName)
val components = createStubBuilderComponents(file, packageFqName, fileContent)
if (header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS) {
val partFiles = findMultifileClassParts(file, classId, header)
return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components)
@@ -95,10 +92,10 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
}
}
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName): ClsStubBuilderComponents {
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName, fileContent: ByteArray): ClsStubBuilderComponents {
val classFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder)
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder, file, fileContent)
return ClsStubBuilderComponents(classDataFinder, annotationLoader, file)
}
@@ -108,9 +105,18 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
}
class AnnotationLoaderForClassFileStubBuilder(
kotlinClassFinder: KotlinClassFinder
kotlinClassFinder: KotlinClassFinder,
private val cachedFile: VirtualFile,
private val cachedFileContent: ByteArray
) : AbstractBinaryClassAnnotationAndConstantLoader<ClassId, Unit, ClassIdWithTarget>(LockBasedStorageManager.NO_LOCKS, kotlinClassFinder) {
override fun getCachedFileContent(kotlinClass: KotlinJvmBinaryClass): ByteArray? {
if ((kotlinClass as? VirtualFileKotlinClass)?.file == cachedFile) {
return cachedFileContent
}
return null
}
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): ClassId =
nameResolver.getClassId(proto.id)