diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index ca602b3fc94..2e06e9390a0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -35,7 +35,6 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo; import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.load.java.JavaVisibilities; -import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor; import org.jetbrains.kotlin.name.FqName; @@ -61,7 +60,6 @@ import java.util.Set; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveClass; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface; -import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; @@ -823,7 +821,7 @@ public class AsmUtil { public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) { AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true); - av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); + JvmCodegenUtil.writeAbiVersion(av); av.visitEnum( JvmAnnotationNames.KIND_FIELD_NAME, Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(), diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java index c962798fec8..8d3baf5bd09 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java @@ -120,10 +120,13 @@ public class ClassFileFactory implements OutputFileCollection { @Override public byte[] asBytes(ClassBuilderFactory factory) { try { - ByteArrayOutputStream moduleMapping = new ByteArrayOutputStream(4*1024); + ByteArrayOutputStream moduleMapping = new ByteArrayOutputStream(4096); DataOutputStream dataOutStream = new DataOutputStream(moduleMapping); - dataOutStream.writeInt(1); - dataOutStream.writeInt(JvmAbi.VERSION); + int[] version = JvmAbi.VERSION.toArray(); + dataOutStream.writeInt(version.length); + for (int number : version) { + dataOutStream.writeInt(number); + } builder.build().writeTo(dataOutStream); dataOutStream.flush(); return moduleMapping.toByteArray(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index 96a5af1b283..d1e59de7d00 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -237,7 +237,7 @@ public class ClosureCodegen extends MemberCodegen { NameResolver nameResolver = new NameResolver(strings.serializeSimpleNames(), strings.serializeQualifiedNames()); AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CALLABLE), true); - av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); + JvmCodegenUtil.writeAbiVersion(av); AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME); for (String string : BitEncoding.encodeBytes(SerializationUtil.serializeCallableData(nameResolver, callableProto))) { array.visit(null, string); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 1f8fdea3d48..797aca64b16 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -264,7 +264,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ClassData data = new ClassData(nameResolver, classProto); AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS), true); - av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); + JvmCodegenUtil.writeAbiVersion(av); //noinspection ConstantConditions if (kind != null) { av.visitEnum( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index d30453f87f7..824c57d0c7a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -31,6 +31,8 @@ import org.jetbrains.kotlin.codegen.context.PackageContext; import org.jetbrains.kotlin.codegen.context.RootContext; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.load.java.JvmAbi; +import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment; import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass; @@ -46,6 +48,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.inline.InlineUtil; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; import org.jetbrains.kotlin.types.JetType; +import org.jetbrains.org.objectweb.asm.AnnotationVisitor; import java.io.File; @@ -257,4 +260,11 @@ public class JvmCodegenUtil { public static String getMappingFileName(@NotNull String moduleName) { return "META-INF/" + moduleName + "." + ModuleMapping.MAPPING_FILE_EXT; } + + public static void writeAbiVersion(@NotNull AnnotationVisitor av) { + av.visit(JvmAnnotationNames.VERSION_FIELD_NAME, JvmAbi.VERSION.toArray()); + + // TODO: drop after some time + av.visit(JvmAnnotationNames.OLD_ABI_VERSION_FIELD_NAME, JvmAbi.VERSION.getMinor()); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt index 2ef5b8daace..8b4a73915fa 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.config.IncrementalCompilation import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticUtils -import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider import org.jetbrains.kotlin.name.FqName @@ -184,7 +183,7 @@ public class MultifileClassCodegen( if (files.any { it.isScript }) return val av = classBuilder.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS), true) - av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION) + JvmCodegenUtil.writeAbiVersion(av) val shortNames = partFqNames.map { it.shortName().asString() }.sorted() val filePartClassNamesArray = av.visitArray(JvmAnnotationNames.FILE_PART_CLASS_NAMES_FIELD_NAME) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt index 7087cf43937..e69a166e8b9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt @@ -20,7 +20,6 @@ import com.intellij.util.ArrayUtil import org.jetbrains.kotlin.codegen.context.FieldOwnerContext import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.JetFile @@ -36,7 +35,6 @@ import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import java.util.* - public class MultifileClassPartCodegen( v: ClassBuilder, file: JetFile, @@ -60,12 +58,12 @@ public class MultifileClassPartCodegen( override fun generateBody() { for (declaration in element.declarations) { if (declaration is JetNamedFunction || declaration is JetProperty) { - genFunctionOrProperty(declaration); + genFunctionOrProperty(declaration) } } if (state.classBuilderMode == ClassBuilderMode.FULL) { - generateInitializers({ createOrGetClInitCodegen(); }); + generateInitializers { createOrGetClInitCodegen() } } } @@ -100,7 +98,7 @@ public class MultifileClassPartCodegen( val data = PackageData(nameResolver, packageProto) val av = v.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS_PART), true) - av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION) + JvmCodegenUtil.writeAbiVersion(av) av.visit(JvmAnnotationNames.MULTIFILE_CLASS_NAME_FIELD_NAME, multifileClassFqName.shortName().asString()) val dataArray = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME) for (string in BitEncoding.encodeBytes(SerializationUtil.serializePackageData(data))) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java index 488d053f2a3..fef895aac0c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java @@ -301,7 +301,7 @@ public class PackageCodegen { PackageData data = new PackageData(nameResolver, packageProto); AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_PACKAGE), true); - av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); + JvmCodegenUtil.writeAbiVersion(av); AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME); for (String string : BitEncoding.encodeBytes(SerializationUtil.serializePackageData(data))) { array.visit(null, string); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java index a152c52dfe6..ba9beac12c0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java @@ -16,18 +16,14 @@ package org.jetbrains.kotlin.codegen; -import com.google.common.collect.Lists; import com.intellij.util.ArrayUtil; import kotlin.jvm.functions.Function0; -import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.codegen.context.FieldOwnerContext; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor; import org.jetbrains.kotlin.descriptors.VariableDescriptor; -import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.psi.JetDeclaration; import org.jetbrains.kotlin.psi.JetFile; @@ -41,12 +37,9 @@ import org.jetbrains.org.objectweb.asm.AnnotationVisitor; import org.jetbrains.org.objectweb.asm.Type; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import static org.jetbrains.kotlin.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses; -import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; -import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class PackagePartCodegen extends MemberCodegen { @@ -124,7 +117,7 @@ public class PackagePartCodegen extends MemberCodegen { PackageData data = new PackageData(nameResolver, packageProto); AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_FILE_FACADE), true); - av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); + JvmCodegenUtil.writeAbiVersion(av); AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME); for (String string : BitEncoding.encodeBytes(SerializationUtil.serializePackageData(data))) { array.visit(null, string); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/TraceBasedErrorReporter.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/TraceBasedErrorReporter.kt index 1fe61137776..15989706c20 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/TraceBasedErrorReporter.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/TraceBasedErrorReporter.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.OverrideResolver +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter import org.jetbrains.kotlin.util.slicedMap.Slices import org.jetbrains.kotlin.util.slicedMap.WritableSlice @@ -29,7 +30,7 @@ import org.jetbrains.kotlin.util.slicedMap.WritableSlice public class TraceBasedErrorReporter(private val trace: BindingTrace) : ErrorReporter { companion object { - private val LOG = Logger.getInstance(javaClass()) + private val LOG = Logger.getInstance(TraceBasedErrorReporter::class.java) public val ABI_VERSION_ERRORS: WritableSlice = Slices.createCollectiveSlice() // TODO: MutableList is a workaround for KT-5792 Covariant types in Kotlin translated to wildcard types in Java @@ -37,11 +38,11 @@ public class TraceBasedErrorReporter(private val trace: BindingTrace) : ErrorRep } public data class AbiVersionErrorData( - public val actualVersion: Int, + public val actualVersion: BinaryVersion, public val classId: ClassId ) - override fun reportIncompatibleAbiVersion(classId: ClassId, filePath: String, actualVersion: Int) { + override fun reportIncompatibleAbiVersion(classId: ClassId, filePath: String, actualVersion: BinaryVersion) { trace.record(ABI_VERSION_ERRORS, filePath, AbiVersionErrorData(actualVersion, classId)) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetFileElementType.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetFileElementType.java index d04c837f6d1..7b6d0918231 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetFileElementType.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetFileElementType.java @@ -36,7 +36,7 @@ import org.jetbrains.kotlin.psi.stubs.impl.KotlinFileStubImpl; import java.io.IOException; public class JetFileElementType extends IStubFileElementType { - public static final int STUB_VERSION = 55; + public static final int STUB_VERSION = 56; private static final String NAME = "kotlin.FILE"; diff --git a/compiler/testData/cli/jvm/wrongAbiVersion.out b/compiler/testData/cli/jvm/wrongAbiVersion.out index b187d7cf1fb..f3655702809 100644 --- a/compiler/testData/cli/jvm/wrongAbiVersion.out +++ b/compiler/testData/cli/jvm/wrongAbiVersion.out @@ -1,5 +1,5 @@ -compiler/testData/cli/jvm/wrongAbiVersionLib/bin/ClassWithWrongAbiVersion.class: error: class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is $ABI_VERSION$ -compiler/testData/cli/jvm/wrongAbiVersionLib/bin/wrong/Wrong_packageKt.class: error: class 'wrong/Wrong_packageKt' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is $ABI_VERSION$ +compiler/testData/cli/jvm/wrongAbiVersionLib/bin/ClassWithWrongAbiVersion.class: error: class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. Its ABI version is unknown, expected ABI version is $ABI_VERSION$ +compiler/testData/cli/jvm/wrongAbiVersionLib/bin/wrong/Wrong_packageKt.class: error: class 'wrong/Wrong_packageKt' was compiled with an incompatible version of Kotlin. Its ABI version is unknown, expected ABI version is $ABI_VERSION$ compiler/testData/cli/jvm/wrongAbiVersion.kt:4:3: error: unresolved reference: bar bar() ^ diff --git a/compiler/tests/org/jetbrains/kotlin/cli/CliBaseTest.java b/compiler/tests/org/jetbrains/kotlin/cli/CliBaseTest.java index d9ef6fd253f..54a1849ec5c 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/CliBaseTest.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/CliBaseTest.java @@ -71,7 +71,7 @@ public class CliBaseTest { public static String getNormalizedCompilerOutput(@NotNull String pureOutput, @NotNull ExitCode exitCode, @NotNull String testDataDir) { String normalizedOutputWithoutExitCode = pureOutput .replace(new File(testDataDir).getAbsolutePath(), "$TESTDATA_DIR$") - .replace("expected ABI version is " + Integer.toString(JvmAbi.VERSION), "expected ABI version is $ABI_VERSION$") + .replace("expected ABI version is " + JvmAbi.VERSION, "expected ABI version is $ABI_VERSION$") .replace("\\", "/"); return removePerfOutput(normalizedOutputWithoutExitCode) + exitCode; diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/KotlinSyntheticClassAnnotationTest.java b/compiler/tests/org/jetbrains/kotlin/codegen/KotlinSyntheticClassAnnotationTest.java index 4257e6b8a81..6d265414469 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/KotlinSyntheticClassAnnotationTest.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/KotlinSyntheticClassAnnotationTest.java @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.load.java.AbiVersionUtil; @@ -27,17 +26,18 @@ import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass; import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.resolve.jvm.JvmClassName; +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; import org.jetbrains.kotlin.test.ConfigurationKind; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.List; -import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KIND_FIELD_NAME; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass.Kind.ANONYMOUS_OBJECT; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass.Kind.LOCAL_CLASS; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass.Kind.*; +import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.VERSION_FIELD_NAME; public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { public static final FqName PACKAGE_NAME = new FqName("test"); @@ -194,10 +194,10 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { Annotation annotation = aClass.getAnnotation(annotationClass); - Integer version = (Integer) CodegenTestUtil.getAnnotationAttribute(annotation, ABI_VERSION_FIELD_NAME); + int[] version = (int[]) CodegenTestUtil.getAnnotationAttribute(annotation, VERSION_FIELD_NAME); assertNotNull(version); assertTrue("Annotation " + annotationFqName + " is written with an unsupported format", - AbiVersionUtil.isAbiVersionCompatible(version)); + AbiVersionUtil.isAbiVersionCompatible(BinaryVersion.create(version))); Object actualKind = CodegenTestUtil.getAnnotationAttribute(annotation, KIND_FIELD_NAME); assertNotNull(actualKind); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AbiVersionUtil.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AbiVersionUtil.java index 8ffb8e1b74f..85ccbc0a307 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AbiVersionUtil.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AbiVersionUtil.java @@ -16,11 +16,16 @@ package org.jetbrains.kotlin.load.java; -public final class AbiVersionUtil { - public static final int INVALID_VERSION = -1; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; - public static boolean isAbiVersionCompatible(int abiVersion) { - return abiVersion == JvmAbi.VERSION; +public final class AbiVersionUtil { + public static final BinaryVersion INVALID_VERSION = BinaryVersion.create(new int[0]); + + public static boolean isAbiVersionCompatible(@NotNull BinaryVersion actual) { + // TODO: compare versions according to Semantic Versioning + return actual.getMajor() == JvmAbi.VERSION.getMajor() && + actual.getMinor() == JvmAbi.VERSION.getMinor(); } private AbiVersionUtil() { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAbi.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAbi.java index 947c80d7fc4..b22e8f6289d 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAbi.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAbi.java @@ -21,13 +21,20 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; public final class JvmAbi { /** * This constant is used to identify binary format (class file) versions - * If you change class file metadata format and/or naming conventions, please increase this number + * If you change class file metadata format and/or naming conventions, please change this version. + * - Major version should be increased only when the new binary format is neither forward- nor backward compatible. + * This shouldn't really ever happen at all. + * - Minor version should be increased when the new format is backward compatible, + * i.e. the new compiler can process old class files, but the old compiler will not be able to process new class files. + * - Patch version can be increased freely and is only supposed to be used for debugging. Increase the patch version when you + * make a change to the metadata format or the bytecode which is both forward- and backward compatible. */ - public static final int VERSION = 24; + public static final BinaryVersion VERSION = BinaryVersion.create(0, 24, 0); public static final String TRAIT_IMPL_CLASS_NAME = "$TImpl"; public static final String TRAIT_IMPL_SUFFIX = "$" + TRAIT_IMPL_CLASS_NAME; diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java index 85a35edb3f2..33c212dfcff 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.java @@ -38,7 +38,7 @@ public final class JvmAnnotationNames { public static final FqName KOTLIN_SIGNATURE = new FqName("kotlin.jvm.KotlinSignature"); public static final FqName OLD_KOTLIN_SIGNATURE = new FqName("jet.runtime.typeinfo.KotlinSignature"); - public static final String ABI_VERSION_FIELD_NAME = "abiVersion"; + public static final String VERSION_FIELD_NAME = "version"; public static final String KIND_FIELD_NAME = "kind"; public static final String FILE_PART_CLASS_NAMES_FIELD_NAME = "filePartClassNames"; public static final String MULTIFILE_CLASS_NAME_FIELD_NAME = "multifileClassName"; @@ -114,6 +114,8 @@ public final class JvmAnnotationNames { @Deprecated public static final FqName OLD_KOTLIN_TRAIT_IMPL = new FqName("jet.KotlinTraitImpl"); + public static final String OLD_ABI_VERSION_FIELD_NAME = "abiVersion"; + // When these annotations appear on a declaration, they are copied to the _type_ of the declaration, becoming type annotations // See also DescriptorRendererOptions#excludedTypeAnnotationClasses public static final Set ANNOTATIONS_COPIED_TO_TYPES = KotlinPackage.setOf( diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/ModuleMapping.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/ModuleMapping.kt index 4d6bda68b46..ff59eb67a31 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/ModuleMapping.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/ModuleMapping.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.load.kotlin import org.jetbrains.kotlin.load.java.AbiVersionUtil +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable import java.io.ByteArrayInputStream import java.io.DataInputStream @@ -28,19 +29,27 @@ public class ModuleMapping private constructor(val packageFqName2Parts: Map?, public val classKind: KotlinClass.Kind?, public val syntheticClassKind: KotlinSyntheticClass.Kind?, diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java index e6f83989d13..183b88b53ec 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.load.java.AbiVersionUtil; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.jvm.JvmClassName; +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; import java.util.ArrayList; import java.util.HashMap; @@ -59,7 +60,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor OLD_DEPRECATED_ANNOTATIONS_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(OLD_KOTLIN_TRAIT_IMPL), SYNTHETIC_CLASS); } - private int version = AbiVersionUtil.INVALID_VERSION; + private BinaryVersion version = AbiVersionUtil.INVALID_VERSION; private String multifileClassName = null; private String[] filePartClassNames = null; private String[] annotationData = null; @@ -151,12 +152,18 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor @Override public void visit(@Nullable Name name, @Nullable Object value) { - if (name != null) { - if (name.asString().equals(ABI_VERSION_FIELD_NAME)) { - version = value instanceof Integer ? (Integer) value : AbiVersionUtil.INVALID_VERSION; - } - else if (name.asString().equals(MULTIFILE_CLASS_NAME_FIELD_NAME)) { - multifileClassName = value instanceof String ? (String) value : null; + if (name == null) return; + + String string = name.asString(); + if (VERSION_FIELD_NAME.equals(string)) { + version = value instanceof int[] ? BinaryVersion.create((int[]) value) : AbiVersionUtil.INVALID_VERSION; + } + else if (MULTIFILE_CLASS_NAME_FIELD_NAME.equals(string)) { + multifileClassName = value instanceof String ? (String) value : null; + } + else if (OLD_ABI_VERSION_FIELD_NAME.equals(string)) { + if (version == AbiVersionUtil.INVALID_VERSION && value instanceof Integer && (Integer) value > 0) { + version = BinaryVersion.create(0, (Integer) value, 0); } } } diff --git a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/java/components/RuntimeErrorReporter.kt b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/java/components/RuntimeErrorReporter.kt index 17fcfb01585..b8eb8947685 100644 --- a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/java/components/RuntimeErrorReporter.kt +++ b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/java/components/RuntimeErrorReporter.kt @@ -19,8 +19,8 @@ package org.jetbrains.kotlin.load.java.components import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.load.java.JvmAbi -import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter public object RuntimeErrorReporter : ErrorReporter { @@ -29,8 +29,8 @@ public object RuntimeErrorReporter : ErrorReporter { throw IllegalStateException("Incomplete hierarchy for class ${descriptor.getName()}, unresolved classes $unresolvedSuperClasses") } - override fun reportIncompatibleAbiVersion(classId: ClassId, filePath: String, actualVersion: Int) { - throw IllegalStateException("Incompatible ABI version of ${classId}: $actualVersion " + + override fun reportIncompatibleAbiVersion(classId: ClassId, filePath: String, actualVersion: BinaryVersion) { + throw IllegalStateException("Incompatible ABI version of $classId: $actualVersion " + "(expected version is ${JvmAbi.VERSION})") } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/BinaryVersion.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/BinaryVersion.kt new file mode 100644 index 00000000000..d3e0ce538f9 --- /dev/null +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/BinaryVersion.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.serialization.deserialization + +data class BinaryVersion private constructor( + val major: Int, + val minor: Int, + val patch: Int, + val rest: List = listOf() +) { + fun toArray(): IntArray = + intArrayOf(major, minor, patch, *rest.toIntArray()) + + override fun toString(): String { + val versions = toArray().takeWhile { it != UNKNOWN } + return if (versions.isEmpty()) "unknown" else versions.joinToString(".") + } + + companion object { + private val UNKNOWN = -1 + + @JvmStatic + fun create(version: IntArray): BinaryVersion { + return BinaryVersion( + major = version.getOrNull(0) ?: UNKNOWN, + minor = version.getOrNull(1) ?: UNKNOWN, + patch = version.getOrNull(2) ?: UNKNOWN, + rest = if (version.size() > 3) version.asList().subList(3, version.size()).toList() else listOf() + ) + } + + @JvmStatic + fun create(major: Int, minor: Int, patch: Int) = BinaryVersion(major, minor, patch) + } +} diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ErrorReporter.java b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ErrorReporter.java index 36ca6c39332..179079f443d 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ErrorReporter.java +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/ErrorReporter.java @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.name.ClassId; import java.util.List; public interface ErrorReporter { - void reportIncompatibleAbiVersion(@NotNull ClassId classId, @NotNull String filePath, int actualVersion); + void reportIncompatibleAbiVersion(@NotNull ClassId classId, @NotNull String filePath, @NotNull BinaryVersion actualVersion); void reportIncompleteHierarchy(@NotNull ClassDescriptor descriptor, @NotNull List unresolvedSuperClasses); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinCallable.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinCallable.java index 95d578edef8..08915460df4 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinCallable.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinCallable.java @@ -21,7 +21,10 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface KotlinCallable { + @Deprecated int abiVersion(); + int[] version() default {}; + String[] data(); } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinClass.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinClass.java index cf67e5352cc..b42d61458c9 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinClass.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinClass.java @@ -21,8 +21,11 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface KotlinClass { + @Deprecated int abiVersion(); + int[] version() default {}; + Kind kind() default Kind.CLASS; String[] data(); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinFileFacade.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinFileFacade.java index 9b69edd5ab8..f5ee97ae4bc 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinFileFacade.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinFileFacade.java @@ -21,7 +21,10 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface KotlinFileFacade { + @Deprecated int abiVersion(); + int[] version() default {}; + String[] data(); } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinMultifileClass.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinMultifileClass.java index 616e34f0932..f23a508bb05 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinMultifileClass.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinMultifileClass.java @@ -21,7 +21,10 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface KotlinMultifileClass { + @Deprecated int abiVersion(); + int[] version() default {}; + String[] filePartClassNames(); } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinMultifileClassPart.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinMultifileClassPart.java index 1f1dd57fb26..07ed2eee283 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinMultifileClassPart.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinMultifileClassPart.java @@ -21,8 +21,12 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface KotlinMultifileClassPart { + @Deprecated int abiVersion(); + int[] version() default {}; + String multifileClassName(); + String[] data(); } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinPackage.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinPackage.java index aff86f8758d..2b00b950f26 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinPackage.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinPackage.java @@ -21,7 +21,10 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface KotlinPackage { + @Deprecated int abiVersion(); + int[] version() default {}; + String[] data(); } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinSyntheticClass.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinSyntheticClass.java index 64531d5bee3..a1280945c4d 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinSyntheticClass.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinSyntheticClass.java @@ -21,8 +21,11 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface KotlinSyntheticClass { + @Deprecated int abiVersion(); + int[] version() default {}; + Kind kind(); enum Kind { diff --git a/generators/infrastructure/check-library-abi-version.kts b/generators/infrastructure/check-library-abi-version.kts index 298e667491b..c45f5beded3 100644 --- a/generators/infrastructure/check-library-abi-version.kts +++ b/generators/infrastructure/check-library-abi-version.kts @@ -26,15 +26,18 @@ import org.jetbrains.org.objectweb.asm.* * Some additional information is printed to stderr */ -fun loadAbiVersionOfClass(bytes: ByteArray): Int? { - var result: Int? = null +fun loadAbiVersionOfClass(bytes: ByteArray): IntArray? { + var result: IntArray? = null ClassReader(bytes).accept(object : ClassVisitor(Opcodes.ASM5) { override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? { if (desc == "Lkotlin/jvm/internal/KotlinClass;") { return object : AnnotationVisitor(Opcodes.ASM5) { override fun visit(name: String, value: Any) { - if (name == "abiVersion") { - result = value as Int + if (name == "version") { + result = value as IntArray + } + else if (name == "abiVersion") { + result = intArrayOf(0, value as Int, 0) } } } @@ -45,7 +48,7 @@ fun loadAbiVersionOfClass(bytes: ByteArray): Int? { return result } -fun loadVersion(library: File): Int { +fun loadVersion(library: File): IntArray { val jarFile = JarFile(library) try { for (entry in jarFile.entries()) { @@ -71,8 +74,8 @@ fun main(args: Array) { val library1 = File(args[0]) val library2 = File(args[1]) - val v1 = loadVersion(library1) - val v2 = loadVersion(library2) + val v1 = loadVersion(library1).joinToString(".") + val v2 = loadVersion(library2).joinToString(".") if (v1 != v2) { System.err.println("ABI versions differ:") diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/LoggingErrorReporter.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/LoggingErrorReporter.kt index 5da35377096..a92385bcdf5 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/LoggingErrorReporter.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/LoggingErrorReporter.kt @@ -16,11 +16,12 @@ package org.jetbrains.kotlin.idea.decompiler.textBuilder -import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import com.intellij.openapi.diagnostic.Logger +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion +import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter class LoggingErrorReporter(private val log: Logger) : ErrorReporter { override fun reportLoadingError(message: String, exception: Exception?) { @@ -35,7 +36,7 @@ class LoggingErrorReporter(private val log: Logger) : ErrorReporter { log.error("Could not infer visibility for $descriptor") } - override fun reportIncompatibleAbiVersion(classId: ClassId, filePath: String, actualVersion: Int) { + override fun reportIncompatibleAbiVersion(classId: ClassId, filePath: String, actualVersion: BinaryVersion) { log.error("Incompatible ABI version for class $classId, actual version: $actualVersion") } } diff --git a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinAbiVersionIndex.kt b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinAbiVersionIndex.kt index 9667b009bf3..702ef355472 100644 --- a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinAbiVersionIndex.kt +++ b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinAbiVersionIndex.kt @@ -23,21 +23,23 @@ import com.intellij.util.indexing.FileContent import org.jetbrains.kotlin.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses import org.jetbrains.kotlin.load.java.AbiVersionUtil import org.jetbrains.kotlin.load.java.JvmAnnotationNames.* +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion import org.jetbrains.org.objectweb.asm.AnnotationVisitor import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.ClassVisitor import org.jetbrains.org.objectweb.asm.Opcodes -public object KotlinAbiVersionIndex : KotlinAbiVersionIndexBase(javaClass()) { +public object KotlinAbiVersionIndex : KotlinAbiVersionIndexBase(KotlinAbiVersionIndex::class.java) { override fun getIndexer() = INDEXER - override fun getInputFilter() = FileBasedIndex.InputFilter() { file -> file.getFileType() == StdFileTypes.CLASS } + override fun getInputFilter() = FileBasedIndex.InputFilter() { file -> file.fileType == StdFileTypes.CLASS } override fun getVersion() = VERSION - private val VERSION = 1 + private val VERSION = 2 + @Suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") private val kotlinAnnotationsDesc = setOf( OLD_JET_CLASS_ANNOTATION, OLD_JET_PACKAGE_CLASS_ANNOTATION, @@ -48,12 +50,12 @@ public object KotlinAbiVersionIndex : KotlinAbiVersionIndexBase() { inputData: FileContent -> - var version: Int? = null + private val INDEXER = DataIndexer() { inputData: FileContent -> + var version: BinaryVersion? = null var annotationPresent = false tryBlock(inputData) { - val classReader = ClassReader(inputData.getContent()) + val classReader = ClassReader(inputData.content) classReader.accept(object : ClassVisitor(Opcodes.ASM5) { override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? { if (!kotlinAnnotationsDesc.contains(desc)) { @@ -62,13 +64,12 @@ public object KotlinAbiVersionIndex : KotlinAbiVersionIndexBase if (value is IntArray) { + version = BinaryVersion.create(value) } - else { - // Version is set to something weird - version = AbiVersionUtil.INVALID_VERSION + OLD_ABI_VERSION_FIELD_NAME -> if (version == null && value is Int) { + version = BinaryVersion.create(0, value, 0) } } } @@ -78,10 +79,10 @@ public object KotlinAbiVersionIndex : KotlinAbiVersionIndexBase(version!! to null) else mapOf() + if (version != null) mapOf(version!! to null) else mapOf() } } diff --git a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinAbiVersionIndexBase.kt b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinAbiVersionIndexBase.kt index 9f2e4ae2358..2473d958fff 100644 --- a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinAbiVersionIndexBase.kt +++ b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinAbiVersionIndexBase.kt @@ -20,16 +20,37 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.util.indexing.FileContent import com.intellij.util.indexing.ID import com.intellij.util.indexing.ScalarIndexExtension -import com.intellij.util.io.ExternalIntegerKeyDescriptor +import com.intellij.util.io.DataInputOutputUtil +import com.intellij.util.io.KeyDescriptor +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion +import java.io.DataInput +import java.io.DataOutput /** * Important! This is not a stub-based index. And it has its own version */ -abstract class KotlinAbiVersionIndexBase(private val classOfIndex: Class) : ScalarIndexExtension() { +abstract class KotlinAbiVersionIndexBase(private val classOfIndex: Class) : ScalarIndexExtension() { - override fun getName() = ID.create(classOfIndex.getCanonicalName()) + override fun getName() = ID.create(classOfIndex.canonicalName) - override fun getKeyDescriptor() = ExternalIntegerKeyDescriptor() + override fun getKeyDescriptor(): KeyDescriptor = object : KeyDescriptor { + override fun isEqual(val1: BinaryVersion, val2: BinaryVersion): Boolean = val1 == val2 + + override fun getHashCode(value: BinaryVersion): Int = value.hashCode() + + override fun read(input: DataInput): BinaryVersion { + val size = DataInputOutputUtil.readINT(input) + return BinaryVersion.create((0..size - 1).map { DataInputOutputUtil.readINT(input) }.toIntArray()) + } + + override fun save(output: DataOutput, value: BinaryVersion) { + val array = value.toArray() + DataInputOutputUtil.writeINT(output, array.size()) + for (number in array) { + DataInputOutputUtil.writeINT(output, number) + } + } + } override fun dependsOnFileContent() = true @@ -40,7 +61,7 @@ abstract class KotlinAbiVersionIndexBase(private val classOfIndex: Class) body() } catch (e: Throwable) { - LOG.warn("Could not index ABI version for file " + inputData.getFile() + ": " + e.getMessage()) + LOG.warn("Could not index ABI version for file " + inputData.file + ": " + e.getMessage()) } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinJavaScriptAbiVersionIndex.kt b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinJavaScriptAbiVersionIndex.kt index 7b710bd60bf..6fada6ffb8b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinJavaScriptAbiVersionIndex.kt +++ b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinJavaScriptAbiVersionIndex.kt @@ -16,42 +16,43 @@ package org.jetbrains.kotlin.idea.versions -import com.google.common.collect.Maps import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.util.indexing.DataIndexer import com.intellij.util.indexing.FileBasedIndex import com.intellij.util.indexing.FileContent import org.jetbrains.kotlin.js.JavaScript import org.jetbrains.kotlin.load.java.AbiVersionUtil +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils -import java.util.ArrayList +import java.util.* -public object KotlinJavaScriptAbiVersionIndex : KotlinAbiVersionIndexBase(javaClass()) { +public object KotlinJavaScriptAbiVersionIndex : KotlinAbiVersionIndexBase(KotlinJavaScriptAbiVersionIndex::class.java) { override fun getIndexer() = INDEXER - override fun getInputFilter() = FileBasedIndex.InputFilter() { file -> JavaScript.EXTENSION == file.getExtension() } + override fun getInputFilter() = FileBasedIndex.InputFilter() { file -> JavaScript.EXTENSION == file.extension } override fun getVersion() = VERSION - private val VERSION = 1 + private val VERSION = 2 - private val INDEXER = DataIndexer() { inputData: FileContent -> - val result = Maps.newHashMap() + private val INDEXER = DataIndexer { inputData: FileContent -> + val result = HashMap() tryBlock(inputData) { - val text = VfsUtilCore.loadText(inputData.getFile()) + val text = VfsUtilCore.loadText(inputData.file) val metadataList = ArrayList() KotlinJavascriptMetadataUtils.parseMetadata(text, metadataList) for (metadata in metadataList) { - if (KotlinJavascriptMetadataUtils.isAbiVersionCompatible(metadata.abiVersion)) { - result.put(metadata.abiVersion, null) + val version = if (KotlinJavascriptMetadataUtils.isAbiVersionCompatible(metadata.abiVersion)) { + BinaryVersion.create(0, metadata.abiVersion, 0) } else { // Version is set to something weird - result.put(AbiVersionUtil.INVALID_VERSION, null) + AbiVersionUtil.INVALID_VERSION } + result[version] = null } } diff --git a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.java b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.java index 49621242948..1f882af3544 100644 --- a/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.java +++ b/idea/src/org/jetbrains/kotlin/idea/versions/KotlinRuntimeLibraryUtil.java @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider; import org.jetbrains.kotlin.idea.framework.LibraryPresentationProviderUtil; import org.jetbrains.kotlin.idea.project.ProjectStructureUtil; import org.jetbrains.kotlin.load.java.AbiVersionUtil; +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils; import org.jetbrains.kotlin.utils.KotlinPaths; import org.jetbrains.kotlin.utils.PathUtil; @@ -76,10 +77,10 @@ public class KotlinRuntimeLibraryUtil { return module != null && ProjectStructureUtil.isJavaKotlinModule(module); } }, - new Function1() { + new Function1() { @Override - public Boolean invoke(Integer abiVersion) { - return !AbiVersionUtil.isAbiVersionCompatible(abiVersion); + public Boolean invoke(@NotNull BinaryVersion version) { + return !AbiVersionUtil.isAbiVersionCompatible(version); } }); } @@ -94,10 +95,11 @@ public class KotlinRuntimeLibraryUtil { return module != null && ProjectStructureUtil.isJsKotlinModule(module); } }, - new Function1() { + new Function1() { @Override - public Boolean invoke(Integer abiVersion) { - return !KotlinJavascriptMetadataUtils.isAbiVersionCompatible(abiVersion); + public Boolean invoke(@NotNull BinaryVersion version) { + // TODO: support major.minor.patch version in JS metadata + return !KotlinJavascriptMetadataUtils.isAbiVersionCompatible(version.getMinor()); } }); } @@ -328,23 +330,23 @@ public class KotlinRuntimeLibraryUtil { @NotNull private static Collection getLibraryRootsWithAbiIncompatibleVersion( @NotNull Project project, - @NotNull ScalarIndexExtension index, + @NotNull ScalarIndexExtension index, @NotNull Function1 checkModule, - @NotNull Function1 checkAbiVersion + @NotNull Function1 checkVersion ) { - ID id = index.getName(); + ID id = index.getName(); Module[] modules = ModuleManager.getInstance(project).getModules(); List modulesToCheck = KotlinPackage.filter(modules, checkModule); if (modulesToCheck.isEmpty()) return Collections.emptyList(); - Collection abiVersions = collectAllKeys(id, modulesToCheck); - Set badAbiVersions = Sets.newHashSet(KotlinPackage.filter(abiVersions, checkAbiVersion)); + Collection versions = collectAllKeys(id, modulesToCheck); + Set badVersions = Sets.newHashSet(KotlinPackage.filter(versions, checkVersion)); Set badRoots = Sets.newHashSet(); ProjectFileIndex fileIndex = ProjectFileIndex.SERVICE.getInstance(project); - for (Integer version : badAbiVersions) { + for (BinaryVersion version : badVersions) { Collection indexedFiles = FileBasedIndex.getInstance().getContainingFiles( id, version, ProjectScope.getLibrariesScope(project)); @@ -361,12 +363,12 @@ public class KotlinRuntimeLibraryUtil { } @NotNull - private static Collection collectAllKeys(@NotNull ID id, @NotNull List modules) { - Set allKeys = new HashSet(); + private static Collection collectAllKeys(@NotNull ID id, @NotNull List modules) { + Set allKeys = new HashSet(); for (Module module : modules) { GlobalSearchScope scope = GlobalSearchScope.moduleWithLibrariesScope(module); - FileBasedIndex.getInstance().processAllKeys(id, new CommonProcessors.CollectProcessor(allKeys), scope, null); + FileBasedIndex.getInstance().processAllKeys(id, new CommonProcessors.CollectProcessor(allKeys), scope, null); } return allKeys; diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt index 58b8b0d2dc0..c0b865d962a 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt @@ -68,7 +68,11 @@ class CacheFormatVersion(targetDataRoot: File) { companion object { // Change this when incremental cache format changes private val INCREMENTAL_CACHE_OWN_VERSION = 4 - private val CACHE_FORMAT_VERSION: Int = INCREMENTAL_CACHE_OWN_VERSION * 1000000 + JvmAbi.VERSION + + private val CACHE_FORMAT_VERSION = + INCREMENTAL_CACHE_OWN_VERSION * 1000000 + + JvmAbi.VERSION.major * 1000 + + JvmAbi.VERSION.minor private val NON_INCREMENTAL_MODE_PSEUDO_VERSION = Int.MAX_VALUE