FIR: Optimize deserialized annotations loading

This commit is contained in:
Denis Zharkov
2020-06-17 16:04:01 +03:00
parent 260e2d0dc3
commit 429b2a9705
5 changed files with 37 additions and 29 deletions
@@ -27,7 +27,8 @@ import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
class JvmBinaryAnnotationDeserializer( class JvmBinaryAnnotationDeserializer(
val session: FirSession val session: FirSession,
private var byteContent: ByteArray?
) : AbstractAnnotationDeserializer(session) { ) : AbstractAnnotationDeserializer(session) {
private val storage: MutableMap<KotlinJvmBinaryClass, MemberAnnotations> = mutableMapOf() private val storage: MutableMap<KotlinJvmBinaryClass, MemberAnnotations> = mutableMapOf()
@@ -190,7 +191,9 @@ class JvmBinaryAnnotationDeserializer(
} }
} }
} }
}, null) // TODO: cached file content? }, byteContent)
byteContent = null
val result = MemberAnnotations(memberAnnotations) val result = MemberAnnotations(memberAnnotations)
storage[kotlinClass] = result storage[kotlinClass] = result
@@ -16,25 +16,29 @@ import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext
import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.buildUnaryArgumentList
import org.jetbrains.kotlin.fir.expressions.builder.* import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.java.createConstant import org.jetbrains.kotlin.fir.java.createConstant
import org.jetbrains.kotlin.fir.java.topLevelName import org.jetbrains.kotlin.fir.java.topLevelName
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.AbstractFirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.AbstractFirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredCallableSymbols import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredCallableSymbols
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.KotlinScopeProvider import org.jetbrains.kotlin.fir.scopes.KotlinScopeProvider
import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.constructClassType
import org.jetbrains.kotlin.load.java.JavaClassFinder import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.kotlin.* import org.jetbrains.kotlin.load.kotlin.*
@@ -105,7 +109,8 @@ class KotlinDeserializedJvmSymbolsProvider(
return packagePartProvider.findPackageParts(packageFqName.asString()).mapNotNull { partName -> return packagePartProvider.findPackageParts(packageFqName.asString()).mapNotNull { partName ->
val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars) val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars)
if (hasNoTopLevelClassOf(classId)) return@mapNotNull null if (hasNoTopLevelClassOf(classId)) return@mapNotNull null
val kotlinJvmBinaryClass = kotlinClassFinder.findKotlinClass(classId) ?: return@mapNotNull null val (kotlinJvmBinaryClass, byteContent) =
kotlinClassFinder.findKotlinClassOrContent(classId) as? KotlinClassFinder.Result.KotlinClass ?: return@mapNotNull null
val header = kotlinJvmBinaryClass.classHeader val header = kotlinJvmBinaryClass.classHeader
val data = header.data ?: header.incompatibleData ?: return@mapNotNull null val data = header.data ?: header.incompatibleData ?: return@mapNotNull null
@@ -121,7 +126,7 @@ class KotlinDeserializedJvmSymbolsProvider(
packageProto, packageProto,
FirDeserializationContext.createForPackage( FirDeserializationContext.createForPackage(
packageFqName, packageProto, nameResolver, session, packageFqName, packageProto, nameResolver, session,
JvmBinaryAnnotationDeserializer(session), JvmBinaryAnnotationDeserializer(session, byteContent),
source source
), ),
source, source,
@@ -164,20 +169,15 @@ class KotlinDeserializedJvmSymbolsProvider(
return JvmProtoBufUtil.readClassDataFrom(data, strings) return JvmProtoBufUtil.readClassDataFrom(data, strings)
} }
private fun FirClassifierSymbol<*>?.toDefaultResolvedTypeRef(classId: ClassId): FirResolvedTypeRef { private fun ConeClassLikeLookupTag.toDefaultResolvedTypeRef(classId: ClassId): FirResolvedTypeRef =
return this?.let { buildResolvedTypeRef {
buildResolvedTypeRef { type = constructClassType(emptyArray(), isNullable = false)
type = it.constructType(emptyList(), isNullable = false) }
}
} ?: buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Symbol not found for $classId", DiagnosticKind.Java) }
}
private fun loadAnnotation( private fun loadAnnotation(
annotationClassId: ClassId, result: MutableList<FirAnnotationCall>, annotationClassId: ClassId, result: MutableList<FirAnnotationCall>,
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
val lookupTag = ConeClassLikeLookupTagImpl(annotationClassId) val lookupTag = ConeClassLikeLookupTagImpl(annotationClassId)
val symbol = lookupTag.toSymbol(session)
return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor { return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor {
private val argumentMap = mutableMapOf<Name, FirExpression>() private val argumentMap = mutableMapOf<Name, FirExpression>()
@@ -190,9 +190,8 @@ class KotlinDeserializedJvmSymbolsProvider(
private fun ClassLiteralValue.toFirClassReferenceExpression(): FirClassReferenceExpression { private fun ClassLiteralValue.toFirClassReferenceExpression(): FirClassReferenceExpression {
val literalLookupTag = ConeClassLikeLookupTagImpl(classId) val literalLookupTag = ConeClassLikeLookupTagImpl(classId)
val literalSymbol = literalLookupTag.toSymbol(this@KotlinDeserializedJvmSymbolsProvider.session)
return buildClassReferenceExpression { return buildClassReferenceExpression {
classTypeRef = literalSymbol.toDefaultResolvedTypeRef(classId) classTypeRef = literalLookupTag.toDefaultResolvedTypeRef(classId)
} }
} }
@@ -275,7 +274,7 @@ class KotlinDeserializedJvmSymbolsProvider(
override fun visitEnd() { override fun visitEnd() {
result += buildAnnotationCall { result += buildAnnotationCall {
annotationTypeRef = symbol.toDefaultResolvedTypeRef(annotationClassId) annotationTypeRef = lookupTag.toDefaultResolvedTypeRef(annotationClassId)
argumentList = buildArgumentList { argumentList = buildArgumentList {
for ((name, expression) in argumentMap) { for ((name, expression) in argumentMap) {
arguments += buildNamedArgumentExpression { arguments += buildNamedArgumentExpression {
@@ -315,8 +314,8 @@ class KotlinDeserializedJvmSymbolsProvider(
} catch (e: ProcessCanceledException) { } catch (e: ProcessCanceledException) {
return null return null
} }
val kotlinJvmBinaryClass = when (result) { val kotlinClassWithContent = when (result) {
is KotlinClassFinder.Result.KotlinClass -> result.kotlinJvmBinaryClass is KotlinClassFinder.Result.KotlinClass -> result
is KotlinClassFinder.Result.ClassFileContent -> { is KotlinClassFinder.Result.ClassFileContent -> {
handledByJava.add(classId) handledByJava.add(classId)
return try { return try {
@@ -327,17 +326,19 @@ class KotlinDeserializedJvmSymbolsProvider(
} }
null -> null null -> null
} }
if (kotlinJvmBinaryClass == null) { if (kotlinClassWithContent == null) {
val outerClassId = classId.outerClassId ?: return null val outerClassId = classId.outerClassId ?: return null
findAndDeserializeClass(outerClassId) ?: return null findAndDeserializeClass(outerClassId) ?: return null
} else { } else {
val (kotlinJvmBinaryClass, byteContent) = kotlinClassWithContent
if (kotlinJvmBinaryClass.classHeader.kind != KotlinClassHeader.Kind.CLASS) return null if (kotlinJvmBinaryClass.classHeader.kind != KotlinClassHeader.Kind.CLASS) return null
val (nameResolver, classProto) = kotlinJvmBinaryClass.readClassDataFrom() ?: return null val (nameResolver, classProto) = kotlinJvmBinaryClass.readClassDataFrom() ?: return null
val symbol = FirRegularClassSymbol(classId) val symbol = FirRegularClassSymbol(classId)
deserializeClassToSymbol( deserializeClassToSymbol(
classId, classProto, symbol, nameResolver, session, classId, classProto, symbol, nameResolver, session,
JvmBinaryAnnotationDeserializer(session), JvmBinaryAnnotationDeserializer(session, byteContent),
kotlinScopeProvider, kotlinScopeProvider,
parentContext, KotlinJvmBinarySourceElement(kotlinJvmBinaryClass), parentContext, KotlinJvmBinarySourceElement(kotlinJvmBinaryClass),
this::findAndDeserializeClass this::findAndDeserializeClass
@@ -356,7 +357,7 @@ class KotlinDeserializedJvmSymbolsProvider(
}, },
null, byteContent,
) )
(symbol.fir.annotations as MutableList<FirAnnotationCall>) += annotations (symbol.fir.annotations as MutableList<FirAnnotationCall>) += annotations
} }
@@ -280,7 +280,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
} }
} }
fun loadFunction(proto: ProtoBuf.Function): FirSimpleFunction { fun loadFunction(proto: ProtoBuf.Function, byteContent: ByteArray? = null): FirSimpleFunction {
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags) val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
val receiverAnnotations = val receiverAnnotations =
@@ -68,7 +68,7 @@ class VirtualFileKotlinClass private constructor(
VirtualFileKotlinClass(file, name, classVersion, header, innerClasses) VirtualFileKotlinClass(file, name, classVersion, header, innerClasses)
} }
return@time kotlinJvmBinaryClass?.let(::KotlinClass) return@time kotlinJvmBinaryClass?.let { KotlinClass(it, byteContent) }
?: KotlinClassFinder.Result.ClassFileContent(byteContent) ?: KotlinClassFinder.Result.ClassFileContent(byteContent)
} }
} }
@@ -28,8 +28,12 @@ interface KotlinClassFinder : KotlinMetadataFinder {
sealed class Result { sealed class Result {
fun toKotlinJvmBinaryClass(): KotlinJvmBinaryClass? = (this as? KotlinClass)?.kotlinJvmBinaryClass fun toKotlinJvmBinaryClass(): KotlinJvmBinaryClass? = (this as? KotlinClass)?.kotlinJvmBinaryClass
data class KotlinClass(val kotlinJvmBinaryClass: KotlinJvmBinaryClass) : Result() class KotlinClass(val kotlinJvmBinaryClass: KotlinJvmBinaryClass, val byteContent: ByteArray? = null) : Result() {
data class ClassFileContent( operator fun component1(): KotlinJvmBinaryClass = kotlinJvmBinaryClass
operator fun component2(): ByteArray? = byteContent
}
class ClassFileContent(
@Suppress("ArrayInDataClass") @Suppress("ArrayInDataClass")
val content: ByteArray val content: ByteArray
) : Result() ) : Result()