From 8c95b783463f20029c74e613d9802b22bb2ff40d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 15 Feb 2021 18:07:38 +0100 Subject: [PATCH] Update JVM metadata version to 1.5.0 Improve the test which checks that we use correct metadata version if `-language-version` is passed by checking all supported language versions. The change in libraries/reflect/build.gradle.kts is needed because kotlinx-metadata-jvm of version 0.1.0 is based on pre-1.4 Kotlin, which doesn't support the new module file metadata generated with metadata version 1.4 and later, and module files need to be readable there to be able to transform them for the shadow plugin. Similarly override dependency on kotlinx-metadata-jvm in the binary-compatibility-validator module. --- .../kotlin/codegen/state/GenerationState.kt | 23 +++++++++++-- .../output.txt | 10 +++--- .../CompileKotlinAgainstCustomBinariesTest.kt | 32 ++++++++++++++----- .../jvm/deserialization/JvmMetadataVersion.kt | 2 +- libraries/reflect/build.gradle.kts | 2 +- .../build.gradle | 5 +++ 6 files changed, 57 insertions(+), 17 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index ed57f52192a..f24b29deb7a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.OptimizationClassBuilderFactory import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.config.LanguageVersion.* import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ScriptDescriptor @@ -49,6 +50,7 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeApproximator import org.jetbrains.org.objectweb.asm.Type import java.io.File +import java.util.* class GenerationState private constructor( val project: Project, @@ -320,8 +322,7 @@ class GenerationState private constructor( val metadataVersion = configuration.get(CommonConfigurationKeys.METADATA_VERSION) - ?: if (languageVersionSettings.languageVersion >= LanguageVersion.LATEST_STABLE) JvmMetadataVersion.INSTANCE - else JvmMetadataVersion(1, 1, 18) + ?: LANGUAGE_TO_METADATA_VERSION.getValue(languageVersionSettings.languageVersion) val abiStability = configuration.get(JVMConfigurationKeys.ABI_STABILITY) @@ -392,6 +393,24 @@ class GenerationState private constructor( private fun shouldOnlyCollectSignatures(origin: JvmDeclarationOrigin) = classBuilderMode == ClassBuilderMode.LIGHT_CLASSES && origin.originKind in doNotGenerateInLightClassMode + + companion object { + private val LANGUAGE_TO_METADATA_VERSION = EnumMap(LanguageVersion::class.java).apply { + val oldMetadataVersion = JvmMetadataVersion(1, 1, 18) + this[KOTLIN_1_0] = oldMetadataVersion + this[KOTLIN_1_1] = oldMetadataVersion + this[KOTLIN_1_2] = oldMetadataVersion + this[KOTLIN_1_3] = oldMetadataVersion + this[KOTLIN_1_4] = JvmMetadataVersion(1, 4, 3) + this[KOTLIN_1_5] = JvmMetadataVersion.INSTANCE + this[KOTLIN_1_6] = JvmMetadataVersion(1, 6, 0) + + check(size == LanguageVersion.values().size) { + "Please add mappings from the missing LanguageVersion instances to the corresponding JvmMetadataVersion " + + "in `GenerationState.LANGUAGE_TO_METADATA_VERSION`" + } + } + } } private val doNotGenerateInLightClassMode = setOf(CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL, BRIDGE, COLLECTION_STUB, AUGMENTED_BUILTIN_API) diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/output.txt index 45fe2dc4d3c..516d02f626e 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/output.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/output.txt @@ -1,6 +1,6 @@ error: incompatible classes were found in dependencies. Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors -$TMP_DIR$/library.jar!/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.5.0, expected version is $ABI_VERSION$. -compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:3:13: error: class 'a.C' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.5.0, expected version is $ABI_VERSION$. +$TMP_DIR$/library.jar!/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is $ABI_VERSION$. +compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:3:13: error: class 'a.C' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is $ABI_VERSION$. The class is loaded from $TMP_DIR$/library.jar!/a/C.class fun test(c: C) { ^ @@ -10,15 +10,15 @@ compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemant compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:5:5: error: unresolved reference: v v ^ -compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:6:5: error: class 'a.C' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.5.0, expected version is $ABI_VERSION$. +compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:6:5: error: class 'a.C' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is $ABI_VERSION$. The class is loaded from $TMP_DIR$/library.jar!/a/C.class c.let { C() } ^ -compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:6:7: error: class 'a.C' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.5.0, expected version is $ABI_VERSION$. +compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:6:7: error: class 'a.C' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is $ABI_VERSION$. The class is loaded from $TMP_DIR$/library.jar!/a/C.class c.let { C() } ^ -compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:6:13: error: class 'a.C' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.5.0, expected version is $ABI_VERSION$. +compiler/testData/compileKotlinAgainstCustomBinaries/strictMetadataVersionSemanticsOldVersion/source.kt:6:13: error: class 'a.C' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is $ABI_VERSION$. The class is loaded from $TMP_DIR$/library.jar!/a/C.class c.let { C() } ^ diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index 8b4940a5851..4eaf74593c2 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -421,22 +421,38 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration } fun testStrictMetadataVersionSemanticsOldVersion() { + val nextMetadataVersion = JvmMetadataVersion(JvmMetadataVersion.INSTANCE.major, JvmMetadataVersion.INSTANCE.minor + 1, 0) val library = compileLibrary( - "library", additionalOptions = listOf("-Xgenerate-strict-metadata-version", "-Xmetadata-version=1.5.0") + "library", additionalOptions = listOf("-Xgenerate-strict-metadata-version", "-Xmetadata-version=$nextMetadataVersion") ) compileKotlin("source.kt", tmpdir, listOf(library)) } fun testMetadataVersionDerivedFromLanguage() { - compileKotlin("source.kt", tmpdir, additionalOptions = listOf("-language-version", "1.3"), expectedFileName = null) + for (languageVersion in LanguageVersion.values()) { + if (languageVersion.isUnsupported) continue - val expectedVersion = JvmMetadataVersion(1, 1, 18) - val topLevelClass = LocalFileKotlinClass.create(File(tmpdir.absolutePath, "Foo.class"))!! - assertEquals(expectedVersion, topLevelClass.classHeader.metadataVersion) + compileKotlin( + "source.kt", tmpdir, additionalOptions = listOf("-language-version", languageVersion.versionString), + expectedFileName = null + ) - val moduleFile = File(tmpdir.absolutePath, "META-INF/main.kotlin_module").readBytes() - val versionNumber = ModuleMapping.readVersionNumber(DataInputStream(ByteArrayInputStream(moduleFile)))!! - assertEquals(expectedVersion, JvmMetadataVersion(*versionNumber)) + // Starting from Kotlin 1.4, major.minor version of JVM metadata must be equal to the language version. + // From Kotlin 1.0 to 1.4, we used JVM metadata version 1.1.*. + val expectedMajor = 1 + val expectedMinor = if (languageVersion < LanguageVersion.KOTLIN_1_4) 1 else languageVersion.minor + + val topLevelClass = LocalFileKotlinClass.create(File(tmpdir.absolutePath, "Foo.class"))!! + val classVersion = topLevelClass.classHeader.metadataVersion + assertEquals("Actual version: $classVersion", expectedMajor, classVersion.major) + assertEquals("Actual version: $classVersion", expectedMinor, classVersion.minor) + + val moduleFile = File(tmpdir.absolutePath, "META-INF/main.kotlin_module").readBytes() + val versionNumber = ModuleMapping.readVersionNumber(DataInputStream(ByteArrayInputStream(moduleFile)))!! + val moduleVersion = JvmMetadataVersion(*versionNumber) + assertEquals("Actual version: $moduleVersion", expectedMajor, moduleVersion.major) + assertEquals("Actual version: $moduleVersion", expectedMinor, moduleVersion.minor) + } } /*test source mapping generation when source info is absent*/ diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmMetadataVersion.kt b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmMetadataVersion.kt index 43e17e0ccdf..1b1ea4deda8 100644 --- a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmMetadataVersion.kt +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmMetadataVersion.kt @@ -26,7 +26,7 @@ class JvmMetadataVersion(versionArray: IntArray, val isStrictSemantics: Boolean) companion object { @JvmField - val INSTANCE = JvmMetadataVersion(1, 4, 2) + val INSTANCE = JvmMetadataVersion(1, 5, 0) @JvmField val INVALID_VERSION = JvmMetadataVersion() diff --git a/libraries/reflect/build.gradle.kts b/libraries/reflect/build.gradle.kts index edb4652eae9..8c75995d8cb 100644 --- a/libraries/reflect/build.gradle.kts +++ b/libraries/reflect/build.gradle.kts @@ -11,7 +11,7 @@ description = "Kotlin Full Reflection Library" buildscript { dependencies { - classpath("org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.1.0") + classpath("org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.2.0") } } diff --git a/libraries/tools/binary-compatibility-validator/build.gradle b/libraries/tools/binary-compatibility-validator/build.gradle index 63f44f4b56b..584c858ba35 100644 --- a/libraries/tools/binary-compatibility-validator/build.gradle +++ b/libraries/tools/binary-compatibility-validator/build.gradle @@ -6,6 +6,11 @@ configurations { } dependencies { + // Override dependency of binary-compatibility-validator:0.2.3 on kotlinx-metadata-jvm:0.1.0, + // until the new version of the binary compatibility validator is released. + // kotlinx-metadata-jvm 0.1.0 can't read metadata of version 1.5 and greater. + runtimeOnly("org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.2.0") + compile("org.jetbrains.kotlinx:binary-compatibility-validator:0.2.3") testCompile project(':kotlin-test:kotlin-test-junit')