From 6c6b7c8b8403d18a36da6b9e173f618113b297c7 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Mon, 22 Jun 2020 13:55:45 +0300 Subject: [PATCH] Implement constant deserializer for fir This deserializer is uniform loader, that is responsible for loading all constants. For example, Math.E, UInt.MAX_VALUE or Float.MIN_VALUE. --- .../KotlinDeserializedJvmSymbolsProvider.kt | 6 ++ .../deserialization/ClassDeserialization.kt | 2 + .../deserialization/FirConstDeserializer.kt | 77 +++++++++++++++++++ .../deserialization/FirMemberDeserializer.kt | 16 ++-- .../impl/FirBuiltinSymbolProvider.kt | 2 + 5 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirConstDeserializer.kt diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/KotlinDeserializedJvmSymbolsProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/KotlinDeserializedJvmSymbolsProvider.kt index de21d7e57db..758263aed4f 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/KotlinDeserializedJvmSymbolsProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/KotlinDeserializedJvmSymbolsProvider.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl +import org.jetbrains.kotlin.fir.deserialization.FirConstDeserializer import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic @@ -112,6 +113,10 @@ class KotlinDeserializedJvmSymbolsProvider( val (kotlinJvmBinaryClass, byteContent) = kotlinClassFinder.findKotlinClassOrContent(classId) as? KotlinClassFinder.Result.KotlinClass ?: return@mapNotNull null + val facadeName = kotlinJvmBinaryClass.classHeader.multifileClassName?.takeIf { it.isNotEmpty() } + val facadeFqName = facadeName?.let { JvmClassName.byInternalName(it).fqNameForTopLevelClassMaybeWithDollars } + val facadeBinaryClass = facadeFqName?.let { kotlinClassFinder.findKotlinClass(ClassId.topLevel(it)) } + val header = kotlinJvmBinaryClass.classHeader val data = header.data ?: header.incompatibleData ?: return@mapNotNull null val strings = header.strings ?: return@mapNotNull null @@ -127,6 +132,7 @@ class KotlinDeserializedJvmSymbolsProvider( FirDeserializationContext.createForPackage( packageFqName, packageProto, nameResolver, session, JvmBinaryAnnotationDeserializer(session, kotlinJvmBinaryClass, byteContent), + FirConstDeserializer(session, kotlinJvmBinaryClass, facadeBinaryClass), source ), source, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt index c9271166aab..455da189142 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.deserialization.NameResolver @@ -81,6 +82,7 @@ fun deserializeClassToSymbol( ) ?: FirDeserializationContext.createForClass( classId, classProto, nameResolver, session, defaultAnnotationDeserializer ?: FirBuiltinAnnotationDeserializer(session), + FirConstDeserializer(session, (containerSource as? KotlinJvmBinarySourceElement)?.binaryClass), containerSource ) buildRegularClass { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirConstDeserializer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirConstDeserializer.kt new file mode 100644 index 00000000000..dc994ab8749 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirConstDeserializer.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.deserialization + +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.expressions.FirConstKind +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression +import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.Flags +import org.jetbrains.kotlin.metadata.deserialization.NameResolver +import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol + +class FirConstDeserializer( + val session: FirSession, + private val partSource: KotlinJvmBinaryClass? = null, + private val facadeSource: KotlinJvmBinaryClass? = null +) { + companion object { + private val constantCache = mutableMapOf() + } + + fun loadConstant(propertyProto: ProtoBuf.Property, callableId: CallableId, nameResolver: NameResolver): FirExpression? { + if (!Flags.HAS_CONSTANT.get(propertyProto.flags)) return null + + constantCache[callableId]?.let { return it } + + if (facadeSource == null && partSource == null) { + val value = propertyProto.getExtensionOrNull(BuiltInSerializerProtocol.compileTimeValue) ?: return null + return buildFirConstant(value, null, value.type.name, nameResolver)?.apply { constantCache[callableId] = this } + } + + (facadeSource ?: partSource)!!.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor { + override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor? = null + + override fun visitField(name: Name, desc: String, initializer: Any?): KotlinJvmBinaryClass.AnnotationVisitor? { + if (initializer != null) { + val constant = buildFirConstant(null, initializer, desc, nameResolver) + constant?.let { constantCache[callableId.replaceName(name)] = it } + } + return null + } + }, null) + + return constantCache[callableId] + } + + private fun buildFirConstant( + protoValue: ProtoBuf.Annotation.Argument.Value?, sourceValue: Any?, constKind: String, nameResolver: NameResolver + ): FirExpression? { + return when (constKind) { + "BYTE", "B" -> buildConstExpression(null, FirConstKind.Byte, ((protoValue?.intValue ?: sourceValue) as Number).toByte()) + "CHAR", "C" -> buildConstExpression(null, FirConstKind.Char, ((protoValue?.intValue ?: sourceValue) as Number).toChar()) + "SHORT", "S" -> buildConstExpression(null, FirConstKind.Short, ((protoValue?.intValue ?: sourceValue) as Number).toShort()) + "INT", "I" -> buildConstExpression(null, FirConstKind.Int, protoValue?.intValue?.toInt() ?: sourceValue as Int) + "LONG", "J" -> buildConstExpression(null, FirConstKind.Long, (protoValue?.intValue ?: sourceValue) as Long) + "FLOAT", "F" -> buildConstExpression(null, FirConstKind.Float, (protoValue?.floatValue ?: sourceValue) as Float) + "DOUBLE", "D" -> buildConstExpression(null, FirConstKind.Double, (protoValue?.doubleValue ?: sourceValue) as Double) + "BOOLEAN", "Z" -> buildConstExpression(null, FirConstKind.Boolean, (protoValue?.intValue?.toInt() ?: sourceValue) != 0) + "STRING", "Ljava/lang/String" -> buildConstExpression( + null, FirConstKind.String, protoValue?.stringValue?.let { nameResolver.getString(it) } ?: sourceValue as String + ) + else -> null + } + } + + private fun CallableId.replaceName(newName: Name): CallableId { + return CallableId(this.packageName, this.className, newName) + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt index cc64b709ad1..6fa891da347 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt @@ -40,6 +40,7 @@ class FirDeserializationContext( val relativeClassName: FqName?, val typeDeserializer: FirTypeDeserializer, val annotationDeserializer: AbstractAnnotationDeserializer, + val constDeserializer: FirConstDeserializer, val containerSource: DeserializedContainerSource?, outerTypeParameters: List, val components: FirDeserializationComponents @@ -58,7 +59,8 @@ class FirDeserializationContext( FirTypeDeserializer( session, nameResolver, typeTable, typeParameterProtos, typeDeserializer ), - annotationDeserializer, containerSource, if (capturesTypeParameters) allTypeParameters else emptyList(), components + annotationDeserializer, constDeserializer, containerSource, + if (capturesTypeParameters) allTypeParameters else emptyList(), components ) val memberDeserializer: FirMemberDeserializer = FirMemberDeserializer(this) @@ -70,12 +72,14 @@ class FirDeserializationContext( nameResolver: NameResolver, session: FirSession, annotationDeserializer: AbstractAnnotationDeserializer, + constDeserializer: FirConstDeserializer, containerSource: DeserializedContainerSource? ) = createRootContext( nameResolver, TypeTable(packageProto.typeTable), session, annotationDeserializer, + constDeserializer, fqName, relativeClassName = null, typeParameterProtos = emptyList(), @@ -88,12 +92,14 @@ class FirDeserializationContext( nameResolver: NameResolver, session: FirSession, annotationDeserializer: AbstractAnnotationDeserializer, + constDeserializer: FirConstDeserializer, containerSource: DeserializedContainerSource? ) = createRootContext( nameResolver, TypeTable(classProto.typeTable), session, annotationDeserializer, + constDeserializer, classId.packageFqName, classId.relativeClassName, classProto.typeParameterList, @@ -105,6 +111,7 @@ class FirDeserializationContext( typeTable: TypeTable, session: FirSession, annotationDeserializer: AbstractAnnotationDeserializer, + constDeserializer: FirConstDeserializer, packageFqName: FqName, relativeClassName: FqName?, typeParameterProtos: List, @@ -124,6 +131,7 @@ class FirDeserializationContext( null ), annotationDeserializer, + constDeserializer, containerSource, emptyList(), FirDeserializationComponents() @@ -272,11 +280,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) { this.getter = getter this.setter = setter this.containerSource = c.containerSource - this.initializer = if (Flags.HAS_CONSTANT.get(flags)) { - proto.getExtensionOrNull(BuiltInSerializerProtocol.compileTimeValue)?.let { - c.annotationDeserializer.resolveValue(returnTypeRef, it, c.nameResolver) - } - } else null + this.initializer = c.constDeserializer.loadConstant(proto, symbol.callableId, c.nameResolver) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt index e81e2343a7f..793c91905b2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.deserialization.FirBuiltinAnnotationDeserializer +import org.jetbrains.kotlin.fir.deserialization.FirConstDeserializer import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider @@ -78,6 +79,7 @@ class FirBuiltinSymbolProvider(val session: FirSession, val kotlinScopeProvider: FirDeserializationContext.createForPackage( fqName, packageProto.`package`, nameResolver, session, FirBuiltinAnnotationDeserializer(session), + FirConstDeserializer(session), containerSource = null ).memberDeserializer }