Deserialization/class reading: pass chosen JvmMetadataVersion whenever possible

This commit is contained in:
Mikhail Glukhikh
2022-12-02 16:38:59 +01:00
parent 52ab565cc6
commit 0c4a0360ac
67 changed files with 399 additions and 163 deletions
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
class LazyJavaPackageFragment(
outerContext: LazyJavaResolverContext,
@@ -39,10 +40,13 @@ class LazyJavaPackageFragment(
) : PackageFragmentDescriptorImpl(outerContext.module, jPackage.fqName) {
private val c = outerContext.childForClassOrPackage(this)
private val jvmMetadataVersion =
outerContext.components.deserializedDescriptorResolver.components.configuration.jvmMetadataVersionOrDefault()
internal val binaryClasses by c.storageManager.createLazyValue {
c.components.packagePartProvider.findPackageParts(fqName.asString()).mapNotNull { partName ->
val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars)
c.components.kotlinClassFinder.findKotlinClass(classId)?.let { partName to it }
c.components.kotlinClassFinder.findKotlinClass(classId, jvmMetadataVersion)?.let { partName to it }
}.toMap()
}
@@ -30,12 +30,14 @@ import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.findKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.storage.NullableLazyValue
import org.jetbrains.kotlin.utils.alwaysTrue
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
import java.util.*
class LazyJavaPackageScope(
@@ -49,6 +51,10 @@ class LazyJavaPackageScope(
c.components.finder.knownClassNamesInPackage(ownerDescriptor.fqName)
}
private val jvmMetadataVersion: JvmMetadataVersion
get() = c.components.deserializedDescriptorResolver.components.configuration.jvmMetadataVersionOrDefault()
private val classes =
c.storageManager.createMemoizedFunctionWithNullableValues<FindClassRequest, ClassDescriptor> classByRequest@{ request ->
val requestClassId = ClassId(ownerDescriptor.fqName, request.name)
@@ -56,9 +62,9 @@ class LazyJavaPackageScope(
val kotlinClassOrClassFileContent =
// These branches should be semantically equal, but the first one could be faster
if (request.javaClass != null)
c.components.kotlinClassFinder.findKotlinClassOrContent(request.javaClass)
c.components.kotlinClassFinder.findKotlinClassOrContent(request.javaClass, jvmMetadataVersion)
else
c.components.kotlinClassFinder.findKotlinClassOrContent(requestClassId)
c.components.kotlinClassFinder.findKotlinClassOrContent(requestClassId, jvmMetadataVersion)
val kotlinBinaryClass = kotlinClassOrClassFileContent?.toKotlinJvmBinaryClass()
@@ -84,8 +90,8 @@ class LazyJavaPackageScope(
"Couldn't find kotlin binary class for light class created by kotlin binary file\n" +
"JavaClass: $javaClass\n" +
"ClassId: $requestClassId\n" +
"findKotlinClass(JavaClass) = ${c.components.kotlinClassFinder.findKotlinClass(javaClass)}\n" +
"findKotlinClass(ClassId) = ${c.components.kotlinClassFinder.findKotlinClass(requestClassId)}\n"
"findKotlinClass(JavaClass) = ${c.components.kotlinClassFinder.findKotlinClass(javaClass, jvmMetadataVersion)}\n" +
"findKotlinClass(ClassId) = ${c.components.kotlinClassFinder.findKotlinClass(requestClassId, jvmMetadataVersion)}\n"
)
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -33,6 +34,8 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
) {
private val annotationDeserializer = AnnotationDeserializer(module, notFoundClasses)
override var jvmMetadataVersion: JvmMetadataVersion = JvmMetadataVersion.INSTANCE
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): AnnotationDescriptor =
annotationDeserializer.deserializeAnnotation(proto, nameResolver)
@@ -224,3 +227,18 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses)
}
}
// Note: this function is needed because we cannot pass JvmMetadataVersion
// directly to the BinaryClassAnnotationAndConstantLoaderImpl constructor.
// This constructor is used by dependency injection.
fun createBinaryClassAnnotationAndConstantLoader(
module: ModuleDescriptor,
notFoundClasses: NotFoundClasses,
storageManager: StorageManager,
kotlinClassFinder: KotlinClassFinder,
jvmMetadataVersion: JvmMetadataVersion
): BinaryClassAnnotationAndConstantLoaderImpl = BinaryClassAnnotationAndConstantLoaderImpl(
module, notFoundClasses, storageManager, kotlinClassFinder
).apply {
this.jvmMetadataVersion = jvmMetadataVersion
}
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.load.java.sources.JavaSourceElementFactory
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeEnhancement
import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
@@ -122,7 +123,7 @@ class DeserializationComponentsForJava(
val deserializationComponentsForJava =
makeDeserializationComponentsForJava(
module, storageManager, notFoundClasses, lazyJavaPackageFragmentProvider,
kotlinClassFinder, deserializedDescriptorResolver, errorReporter
kotlinClassFinder, deserializedDescriptorResolver, errorReporter, JvmMetadataVersion.INSTANCE
)
deserializedDescriptorResolver.setComponents(deserializationComponentsForJava)
@@ -183,11 +184,12 @@ fun makeDeserializationComponentsForJava(
lazyJavaPackageFragmentProvider: LazyJavaPackageFragmentProvider,
reflectKotlinClassFinder: KotlinClassFinder,
deserializedDescriptorResolver: DeserializedDescriptorResolver,
errorReporter: ErrorReporter
errorReporter: ErrorReporter,
jvmMetadataVersion: JvmMetadataVersion
): DeserializationComponentsForJava {
val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver)
val binaryClassAnnotationAndConstantLoader = BinaryClassAnnotationAndConstantLoaderImpl(
module, notFoundClasses, storageManager, reflectKotlinClassFinder
val binaryClassAnnotationAndConstantLoader = createBinaryClassAnnotationAndConstantLoader(
module, notFoundClasses, storageManager, reflectKotlinClassFinder, jvmMetadataVersion
)
return DeserializationComponentsForJava(
storageManager, module, DeserializationConfiguration.Default, javaClassDataFinder,
@@ -28,11 +28,14 @@ import org.jetbrains.kotlin.serialization.deserialization.DeserializationCompone
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
import javax.inject.Inject
class DeserializedDescriptorResolver {
lateinit var components: DeserializationComponents
private val ownMetadataVersion: JvmMetadataVersion get() = components.configuration.jvmMetadataVersionOrDefault()
// component dependency cycle
@Inject
fun setComponents(components: DeserializationComponentsForJava) {
@@ -80,8 +83,10 @@ class DeserializedDescriptorResolver {
private val KotlinJvmBinaryClass.incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>?
get() {
if (skipMetadataVersionCheck || classHeader.metadataVersion.isCompatible()) return null
return IncompatibleVersionErrorData(classHeader.metadataVersion, JvmMetadataVersion.INSTANCE, location, classId)
if (skipMetadataVersionCheck || classHeader.metadataVersion.isCompatible(ownMetadataVersion)) return null
return IncompatibleVersionErrorData(
classHeader.metadataVersion, maxOf(ownMetadataVersion.prev(), JvmMetadataVersion.INSTANCE), location, classId
)
}
/**
@@ -120,7 +125,7 @@ class DeserializedDescriptorResolver {
throw IllegalStateException("Could not read data from ${klass.location}", e)
}
} catch (e: Throwable) {
if (skipMetadataVersionCheck || klass.classHeader.metadataVersion.isCompatible()) {
if (skipMetadataVersionCheck || klass.classHeader.metadataVersion.isCompatible(ownMetadataVersion)) {
throw e
}
@@ -19,13 +19,16 @@ package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
class JavaClassDataFinder(
internal val kotlinClassFinder: KotlinClassFinder,
private val deserializedDescriptorResolver: DeserializedDescriptorResolver
) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassData? {
val kotlinClass = kotlinClassFinder.findKotlinClass(classId) ?: return null
val kotlinClass = kotlinClassFinder.findKotlinClass(
classId, deserializedDescriptorResolver.components.configuration.jvmMetadataVersionOrDefault()
) ?: return null
assert(kotlinClass.classId == classId) {
"Class with incorrect id found: expected $classId, actual ${kotlinClass.classId}"
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
import org.jetbrains.kotlin.utils.jvmMetadataVersionOrDefault
fun ModuleMapping.Companion.loadModuleMapping(
bytes: ByteArray?,
@@ -20,5 +21,6 @@ fun ModuleMapping.Companion.loadModuleMapping(
debugName,
configuration.skipMetadataVersionCheck,
configuration.isJvmPackageNameSupported,
configuration.jvmMetadataVersionOrDefault(),
reportIncompatibleVersionError
)
@@ -61,7 +61,12 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
private String[] serializedIrFields = null;
@Nullable
public KotlinClassHeader createHeader() {
public KotlinClassHeader createHeaderWithDefaultMetadataVersion() {
return createHeader(JvmMetadataVersion.INSTANCE);
}
@Nullable
public KotlinClassHeader createHeader(JvmMetadataVersion metadataVersionFromLanguageVersion) {
if (headerKind == null || metadataVersionArray == null) {
return null;
}
@@ -69,7 +74,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
JvmMetadataVersion metadataVersion =
new JvmMetadataVersion(metadataVersionArray, (extraInt & JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0);
if (!metadataVersion.isCompatible()) {
if (!metadataVersion.isCompatible(metadataVersionFromLanguageVersion)) {
incompatibleData = data;
data = null;
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2022 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.utils
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
fun DeserializationConfiguration.jvmMetadataVersionOrDefault(): JvmMetadataVersion =
binaryVersion as? JvmMetadataVersion ?: JvmMetadataVersion.INSTANCE