Do not call findKotlinClass when loading class annotations

The main change is in AbstractBinaryClassAnnotationAndConstantLoader, where we
no longer perform unnecessary IO operations for classes which are already
loaded to memory
This commit is contained in:
Alexander Udalov
2016-04-06 16:18:10 +03:00
parent 7620d66019
commit ad068ed4ac
16 changed files with 68 additions and 70 deletions
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.load.java.components
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.name.ClassId
@@ -28,10 +27,7 @@ import org.jetbrains.kotlin.util.slicedMap.Slices
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
class TraceBasedErrorReporter(private val trace: BindingTrace) : ErrorReporter {
companion object {
private val LOG = Logger.getInstance(TraceBasedErrorReporter::class.java)
@JvmField
val METADATA_VERSION_ERRORS: WritableSlice<String, IncompatibleVersionErrorData> = Slices.createCollectiveSlice()
@@ -50,8 +46,4 @@ class TraceBasedErrorReporter(private val trace: BindingTrace) : ErrorReporter {
override fun reportCannotInferVisibility(descriptor: CallableMemberDescriptor) {
OverrideResolver.createCannotInferVisibilityReporter(trace).invoke(descriptor)
}
override fun reportLoadingError(message: String, exception: Exception?) {
LOG.error(message, exception)
}
}
@@ -38,8 +38,7 @@ import java.util.*
abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any, T : Any>(
storageManager: StorageManager,
private val kotlinClassFinder: KotlinClassFinder,
private val errorReporter: ErrorReporter
private val kotlinClassFinder: KotlinClassFinder
) : AnnotationAndConstantLoader<A, C, T> {
private val storage = storageManager.createMemoizedFunction<KotlinJvmBinaryClass, Storage<A, C>> {
kotlinClass ->
@@ -66,14 +65,11 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
return loadAnnotation(annotationClassId, source, result)
}
private fun ProtoContainer.Class.toBinaryClass(): KotlinJvmBinaryClass? =
(source as? KotlinJvmBinarySourceElement)?.binaryClass
override fun loadClassAnnotations(container: ProtoContainer.Class): List<A> {
val kotlinClass = kotlinClassFinder.findKotlinClass(container.classId)
if (kotlinClass == null) {
// This means that the resource we're constructing the descriptor from is no longer present: KotlinClassFinder had found the
// class earlier, but it can't now
errorReporter.reportLoadingError("Kotlin class for loading class annotations is not found: ${container.debugFqName()}", null)
return listOf()
}
val kotlinClass = container.toBinaryClass() ?: error("Class for loading annotations is not found: ${container.debugFqName()}")
val result = ArrayList<A>(1)
@@ -208,18 +204,28 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
private fun findClassWithAnnotationsAndInitializers(
container: ProtoContainer, implClassName: ClassId?, field: Boolean
): KotlinJvmBinaryClass? {
if (implClassName != null) {
return kotlinClassFinder.findKotlinClass(implClassName)
}
if (container is ProtoContainer.Class) {
val containerBinaryClass = container.toBinaryClass()
if (implClassName == container.classId) {
return containerBinaryClass
}
if (implClassName != null) {
return kotlinClassFinder.findKotlinClass(implClassName)
}
if (field && container.kind == ProtoBuf.Class.Kind.COMPANION_OBJECT &&
(container.outerClassKind == ClassKind.CLASS || container.outerClassKind == ClassKind.ENUM_CLASS)) {
// Backing fields of properties of a companion object in a class are generated in the outer class
return kotlinClassFinder.findKotlinClass(container.classId.outerClassId)
}
return kotlinClassFinder.findKotlinClass(container.classId)
return containerBinaryClass
}
if (implClassName != null) {
return kotlinClassFinder.findKotlinClass(implClassName)
}
return null
@@ -30,7 +30,10 @@ import org.jetbrains.kotlin.resolve.constants.AnnotationValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.AnnotationDeserializer
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses
import org.jetbrains.kotlin.serialization.deserialization.findNonGenericClassAcrossDependencies
import org.jetbrains.kotlin.storage.StorageManager
import java.util.*
@@ -38,10 +41,9 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
private val module: ModuleDescriptor,
private val notFoundClasses: NotFoundClasses,
storageManager: StorageManager,
kotlinClassFinder: KotlinClassFinder,
errorReporter: ErrorReporter
kotlinClassFinder: KotlinClassFinder
) : AbstractBinaryClassAnnotationAndConstantLoader<AnnotationDescriptor, ConstantValue<*>, AnnotationWithTarget>(
storageManager, kotlinClassFinder, errorReporter
storageManager, kotlinClassFinder
) {
private val annotationDeserializer = AnnotationDeserializer(module, notFoundClasses)
private val factory = ConstantValueFactory(module.builtIns)
@@ -18,8 +18,9 @@ package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.serialization.deserialization.descriptors.BinarySource
class KotlinJvmBinarySourceElement(val binaryClass: KotlinJvmBinaryClass) : SourceElement {
class KotlinJvmBinarySourceElement(val binaryClass: KotlinJvmBinaryClass) : SourceElement, BinarySource {
override fun toString() = javaClass.name + ": " + binaryClass.toString()
override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE
}
@@ -39,7 +39,4 @@ object RuntimeErrorReporter : ErrorReporter {
throw IllegalStateException("Cannot infer visibility for $descriptor")
}
override fun reportLoadingError(message: String, exception: Exception?) {
throw IllegalStateException(message, exception)
}
}
@@ -68,7 +68,7 @@ class RuntimeModuleData private constructor(val deserialization: Deserialization
val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver)
val notFoundClasses = NotFoundClasses(storageManager, module)
val binaryClassAnnotationAndConstantLoader = BinaryClassAnnotationAndConstantLoaderImpl(
module, notFoundClasses, storageManager, reflectKotlinClassFinder, RuntimeErrorReporter
module, notFoundClasses, storageManager, reflectKotlinClassFinder
)
val deserializationComponentsForJava = DeserializationComponentsForJava(
storageManager, module, javaClassDataFinder, binaryClassAnnotationAndConstantLoader,
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.serialization.deserialization;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.name.ClassId;
@@ -31,8 +30,6 @@ public interface ErrorReporter {
void reportCannotInferVisibility(@NotNull CallableMemberDescriptor descriptor);
void reportLoadingError(@NotNull String message, @Nullable Exception exception);
ErrorReporter DO_NOTHING = new ErrorReporter() {
@Override
public void reportIncompatibleMetadataVersion(
@@ -47,9 +44,5 @@ public interface ErrorReporter {
@Override
public void reportCannotInferVisibility(@NotNull CallableMemberDescriptor descriptor) {
}
@Override
public void reportLoadingError(@NotNull String message, @Nullable Exception exception) {
}
};
}
@@ -25,14 +25,16 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.BinarySour
sealed class ProtoContainer(
val nameResolver: NameResolver,
val typeTable: TypeTable
val typeTable: TypeTable,
val source: BinarySource?
) {
class Class(
val classProto: ProtoBuf.Class,
nameResolver: NameResolver,
typeTable: TypeTable,
source: BinarySource?,
val outerClassKind: ClassKind?
) : ProtoContainer(nameResolver, typeTable) {
) : ProtoContainer(nameResolver, typeTable, source) {
val classId: ClassId = nameResolver.getClassId(classProto.fqName)
val kind: ProtoBuf.Class.Kind = Flags.CLASS_KIND.get(classProto.flags) ?: ProtoBuf.Class.Kind.CLASS
@@ -45,8 +47,8 @@ sealed class ProtoContainer(
val fqName: FqName,
nameResolver: NameResolver,
typeTable: TypeTable,
val source: BinarySource?
) : ProtoContainer(nameResolver, typeTable) {
source: BinarySource?
) : ProtoContainer(nameResolver, typeTable, source) {
override fun debugFqName(): FqName = fqName
}
@@ -73,8 +73,9 @@ class DeserializedClassDescriptor(
private val constructors = c.storageManager.createLazyValue { computeConstructors() }
private val companionObjectDescriptor = c.storageManager.createNullableLazyValue { computeCompanionObjectDescriptor() }
internal val thisAsProtoContainer =
ProtoContainer.Class(classProto, c.nameResolver, c.typeTable, (containingDeclaration as? ClassDescriptor)?.kind)
internal val thisAsProtoContainer = ProtoContainer.Class(
classProto, c.nameResolver, c.typeTable, sourceElement as? BinarySource, (containingDeclaration as? ClassDescriptor)?.kind
)
private val annotations =
if (!Flags.HAS_ANNOTATIONS.get(classProto.flags)) {
@@ -57,7 +57,9 @@ class KotlinBuiltInStubBuilder : ClsStubBuilder() {
packageProto.functionList, packageProto.propertyList
)
for (classProto in file.classesToDecompile) {
createClassStub(fileStub, classProto, nameResolver, nameResolver.getClassId(classProto.fqName), context)
createClassStub(
fileStub, classProto, nameResolver, nameResolver.getClassId(classProto.fqName), source = null, context = context
)
}
return fileStub
}
@@ -57,14 +57,13 @@ class DeserializerForClassfileDecompiler(
init {
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
val errorReporter = LoggingErrorReporter(LOG)
val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor)
val annotationAndConstantLoader =
BinaryClassAnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, storageManager, classFinder, errorReporter)
BinaryClassAnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, storageManager, classFinder)
deserializationComponents = DeserializationComponents(
storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider,
ResolveEverythingToKotlinAnyLocalClassResolver(targetPlatform.builtIns), errorReporter,
ResolveEverythingToKotlinAnyLocalClassResolver(targetPlatform.builtIns), LoggingErrorReporter(LOG),
LookupTracker.DO_NOTHING, JavaFlexibleTypeCapabilitiesDeserializer, ClassDescriptorFactory.EMPTY, notFoundClasses
)
}
@@ -26,16 +26,15 @@ 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.idea.decompiler.textBuilder.LoggingErrorReporter
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.header.KotlinClassHeader
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
@@ -55,9 +54,9 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
}
fun doBuildFileStub(file: VirtualFile): PsiFileStub<KtFile>? {
val kotlinClassHeaderInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)!!
val header = kotlinClassHeaderInfo.classHeader
val classId = kotlinClassHeaderInfo.classId
val kotlinClass = IDEKotlinBinaryClassCache.getKotlinBinaryClass(file)!!
val header = kotlinClass.classHeader
val classId = kotlinClass.classId
val packageFqName = classId.packageFqName
if (!header.metadataVersion.isCompatible()) {
return createIncompatibleAbiVersionFileStub()
@@ -84,7 +83,7 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
if (classId.isLocal) return null
val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(annotationData, strings)
val context = components.createContext(nameResolver, packageFqName, TypeTable(classProto.typeTable))
createTopLevelClassStub(classId, classProto, context)
createTopLevelClassStub(classId, classProto, KotlinJvmBinarySourceElement(kotlinClass), context)
}
KotlinClassHeader.Kind.FILE_FACADE -> {
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings)
@@ -98,7 +97,7 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName): ClsStubBuilderComponents {
val classFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder, LoggingErrorReporter(LOG))
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder)
return ClsStubBuilderComponents(classDataFinder, annotationLoader, file)
}
@@ -108,10 +107,8 @@ open class KotlinClsStubBuilder : ClsStubBuilder() {
}
class AnnotationLoaderForClassFileStubBuilder(
kotlinClassFinder: KotlinClassFinder,
errorReporter: ErrorReporter
) : AbstractBinaryClassAnnotationAndConstantLoader<ClassId, Unit, ClassIdWithTarget>(
LockBasedStorageManager.NO_LOCKS, kotlinClassFinder, errorReporter) {
kotlinClassFinder: KotlinClassFinder
) : AbstractBinaryClassAnnotationAndConstantLoader<ClassId, Unit, ClassIdWithTarget>(LockBasedStorageManager.NO_LOCKS, kotlinClassFinder) {
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): ClassId =
nameResolver.getClassId(proto.id)
@@ -70,7 +70,7 @@ class KotlinJavaScriptStubBuilder : ClsStubBuilder() {
val classProto = ProtoBuf.Class.parseFrom(content, JsSerializerProtocol.extensionRegistry)
val context = components.createContext(nameResolver, packageFqName, TypeTable(classProto.typeTable))
val classId = JsMetaFileUtils.getClassId(file)
return createTopLevelClassStub(classId, classProto, context)
return createTopLevelClassStub(classId, classProto, source = null, context = context)
}
}
@@ -37,15 +37,17 @@ import org.jetbrains.kotlin.psi.stubs.impl.KotlinPlaceHolderStubImpl
import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.BinarySource
fun createClassStub(
parent: StubElement<out PsiElement>,
classProto: ProtoBuf.Class,
nameResolver: NameResolver,
classId: ClassId,
source: BinarySource?,
context: ClsStubBuilderContext
) {
ClassClsStubBuilder(parent, classProto, nameResolver, classId, context).build()
ClassClsStubBuilder(parent, classProto, nameResolver, classId, source, context).build()
}
private class ClassClsStubBuilder(
@@ -53,6 +55,7 @@ private class ClassClsStubBuilder(
private val classProto: ProtoBuf.Class,
private val nameResolver: NameResolver,
private val classId: ClassId,
private val source: BinarySource?,
private val outerContext: ClsStubBuilderContext
) {
private val classKind = Flags.CLASS_KIND[classProto.flags]
@@ -73,8 +76,9 @@ private class ClassClsStubBuilder(
private val companionObjectName =
if (classProto.hasCompanionObjectName()) c.nameResolver.getName(classProto.companionObjectName) else null
private val thisAsProtoContainer =
ProtoContainer.Class(classProto, c.nameResolver, c.typeTable, outerContext.classKind?.let { Deserialization.classKind(it) })
private val thisAsProtoContainer = ProtoContainer.Class(
classProto, c.nameResolver, c.typeTable, source, outerContext.classKind?.let { Deserialization.classKind(it) }
)
private val classOrObjectStub = createClassOrObjectStubAndModifierListStub()
@@ -249,7 +253,7 @@ private class ClassClsStubBuilder(
return
}
val (nameResolver, classProto) = classDataWithSource.classData
createClassStub(classBody, classProto, nameResolver, nestedClassId, c)
createClassStub(classBody, classProto, nameResolver, nestedClassId, classDataWithSource.sourceElement as? BinarySource, c)
}
companion object {
@@ -40,11 +40,17 @@ import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import org.jetbrains.kotlin.serialization.deserialization.descriptors.BinarySource
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
fun createTopLevelClassStub(classId: ClassId, classProto: ProtoBuf.Class, context: ClsStubBuilderContext): KotlinFileStubImpl {
fun createTopLevelClassStub(
classId: ClassId,
classProto: ProtoBuf.Class,
source: BinarySource?,
context: ClsStubBuilderContext
): KotlinFileStubImpl {
val fileStub = createFileStub(classId.packageFqName)
createClassStub(fileStub, classProto, context.nameResolver, classId, context)
createClassStub(fileStub, classProto, context.nameResolver, classId, source, context)
return fileStub
}
@@ -24,10 +24,6 @@ import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
class LoggingErrorReporter(private val log: Logger) : ErrorReporter {
override fun reportLoadingError(message: String, exception: Exception?) {
log.error(message, exception)
}
override fun reportIncompleteHierarchy(descriptor: ClassDescriptor, unresolvedSuperClasses: List<String>) {
// This is absolutely fine for the decompiler
}