Support correct way of writing/loading version requirement table

Tests are added in subsequent commits.

KT-25120 Fixed
This commit is contained in:
Alexander Udalov
2018-07-12 13:59:42 +02:00
parent 4122021090
commit cfc0f5e453
11 changed files with 67 additions and 12 deletions
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.java.JavaClassProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -29,6 +31,9 @@ import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerial
// It uses BuiltInSerializerProtocol for annotations serialization
class JavaClassesSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
override val metadataVersion: BinaryVersion
get() = JvmMetadataVersion.INVALID_VERSION
override fun serializeClass(
descriptor: ClassDescriptor,
proto: ProtoBuf.Class.Builder,
@@ -16,9 +16,11 @@ import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.lazy.types.RawTypeImpl
import org.jetbrains.kotlin.load.kotlin.NON_EXISTENT_CLASS_NAME
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmFlags
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.FqName
@@ -37,7 +39,6 @@ import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.Method
class JvmSerializerExtension(private val bindings: JvmSerializationBindings, state: GenerationState) : SerializerExtension() {
private val codegenBinding = state.bindingContext
private val typeMapper = state.typeMapper
override val stringTable = JvmCodegenStringTable(typeMapper)
@@ -46,9 +47,10 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta
private val classBuilderMode = state.classBuilderMode
private val isReleaseCoroutines = state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
override fun shouldUseTypeTable(): Boolean {
return useTypeTable
}
override val metadataVersion: BinaryVersion
get() = JvmMetadataVersion.INSTANCE
override fun shouldUseTypeTable(): Boolean = useTypeTable
override fun serializeClass(
descriptor: ClassDescriptor,
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.serialization.builtins
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.types.KotlinType
@@ -29,6 +31,9 @@ class BuiltInsSerializerExtension : KotlinSerializerExtensionBase(BuiltInSeriali
"CharRange" to "kotlin/ranges/CharRange"
)
override val metadataVersion: BinaryVersion
get() = BuiltInsBinaryVersion.INSTANCE
override fun shouldUseTypeTable(): Boolean = true
override fun serializeErrorType(type: KotlinType, builder: ProtoBuf.Type.Builder) {
@@ -16,9 +16,14 @@
package org.jetbrains.kotlin.cli.metadata
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
class MetadataSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
override val metadataVersion: BinaryVersion
get() = BuiltInsBinaryVersion.INSTANCE
override fun shouldUseTypeTable(): Boolean = true
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.metadata.deserialization.isVersionRequirementTableWrittenCorrectly
import org.jetbrains.kotlin.metadata.serialization.Interner
import org.jetbrains.kotlin.metadata.serialization.MutableTypeTable
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
@@ -728,7 +729,8 @@ class DescriptorSerializer private constructor(
Interner(parent.typeParameters),
extension,
MutableTypeTable(),
if (container is ClassDescriptor) parent.versionRequirementTable else MutableVersionRequirementTable(),
if (container is ClassDescriptor && !isVersionRequirementTableWrittenCorrectly(extension.metadataVersion))
parent.versionRequirementTable else MutableVersionRequirementTable(),
serializeTypeTableToFunction = false
)
for (typeParameter in descriptor.declaredTypeParameters) {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.FlexibleType
@@ -15,6 +16,8 @@ import org.jetbrains.kotlin.types.KotlinType
abstract class SerializerExtension {
abstract val stringTable: DescriptorAwareStringTable
abstract val metadataVersion: BinaryVersion
val annotationSerializer by lazy { AnnotationSerializer(stringTable) }
open fun shouldUseTypeTable(): Boolean = false
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.resolve.constants.NullValue
import org.jetbrains.kotlin.resolve.descriptorUtil.nonSourceAnnotations
import org.jetbrains.kotlin.types.KotlinType
open class KotlinSerializerExtensionBase(private val protocol: SerializerExtensionProtocol) : SerializerExtension() {
abstract class KotlinSerializerExtensionBase(private val protocol: SerializerExtensionProtocol) : SerializerExtension() {
override val stringTable = StringTableImpl()
override fun serializeClass(
@@ -24,10 +24,7 @@ import org.jetbrains.kotlin.descriptors.deserialization.ClassDescriptorFactory
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirementTable
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.resolve.constants.ConstantValue
@@ -96,9 +93,12 @@ class DeserializationContext(
typeParameterProtos: List<ProtoBuf.TypeParameter>,
nameResolver: NameResolver = this.nameResolver,
typeTable: TypeTable = this.typeTable,
versionRequirementTable: VersionRequirementTable = this.versionRequirementTable,
metadataVersion: BinaryVersion = this.metadataVersion
): DeserializationContext = DeserializationContext(
components, nameResolver, descriptor, typeTable, versionRequirementTable, metadataVersion, this.containerSource,
components, nameResolver, descriptor, typeTable,
if (isVersionRequirementTableWrittenCorrectly(metadataVersion)) versionRequirementTable else this.versionRequirementTable,
metadataVersion, this.containerSource,
parentTypeDeserializer = this.typeDeserializer, typeParameters = typeParameterProtos
)
}
@@ -45,7 +45,10 @@ class DeserializedClassDescriptor(
private val visibility = ProtoEnumFlags.visibility(Flags.VISIBILITY.get(classProto.flags))
private val kind = ProtoEnumFlags.classKind(Flags.CLASS_KIND.get(classProto.flags))
val c = outerContext.childContext(this, classProto.typeParameterList, nameResolver, TypeTable(classProto.typeTable), metadataVersion)
val c = outerContext.childContext(
this, classProto.typeParameterList, nameResolver, TypeTable(classProto.typeTable),
VersionRequirementTable.create(classProto.versionRequirementTable), metadataVersion
)
private val staticScope = if (kind == ClassKind.ENUM_CLASS) StaticScopeForKotlinEnum(c.storageManager, this) else MemberScope.Empty
private val typeConstructor = DeserializedClassTypeConstructor()
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.metadata.deserialization
// The purpose of utilities in this file is to support different behavior in deserialization according to the given binary file's version.
//
// For example, if we find a bug in serialization/deserialization and would like to fix it _remaining compatible_ with two latest versions
// of Kotlin, we can use methods of this class to fix deserialization of the "future" binaries, and later (in the next major version)
// fix the bug in serialization when the binary version advances to the value supported in the first bug fix.
/**
* Before Kotlin 1.4, version requirements for nested classes were deserialized incorrectly: the version requirement table was loaded from
* the outermost class and passed to the nested classes and their members, even though indices of their version requirements were pointing
* to the other table stored in the nested class (which was not read by deserialization). See KT-25120 for more information
*/
fun isVersionRequirementTableWrittenCorrectly(version: BinaryVersion): Boolean =
isKotlin1Dot4OrLater(version)
private fun isKotlin1Dot4OrLater(version: BinaryVersion): Boolean {
// All metadata versions (JVM, JS, common) will be advanced to 1.4.0 in Kotlin 1.4
return version.major == 1 && version.minor >= 4
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.js.JsProtoBuf
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.psi.KtFile
@@ -27,11 +28,15 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.utils.JsMetadataVersion
class KotlinJavascriptSerializerExtension(
private val fileRegistry: KotlinFileRegistry,
private val languageVersionSettings: LanguageVersionSettings
) : KotlinSerializerExtensionBase(JsSerializerProtocol) {
override val metadataVersion: BinaryVersion
get() = JsMetadataVersion.INSTANCE
override val stringTable = JavaScriptStringTable()
override fun serializeFlexibleType(flexibleType: FlexibleType, lowerProto: ProtoBuf.Type.Builder, upperProto: ProtoBuf.Type.Builder) {