Improve ABI version from one number to "major.minor.patch"

This commit is contained in:
Alexander Udalov
2015-09-08 20:21:19 +03:00
parent 299df05a74
commit 6cecc66d10
37 changed files with 256 additions and 118 deletions
@@ -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() {
@@ -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;
@@ -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<FqName> ANNOTATIONS_COPIED_TO_TYPES = KotlinPackage.setOf(
@@ -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<Stri
}
companion object {
public val MAPPING_FILE_EXT: String = "kotlin_module";
public val MAPPING_FILE_EXT: String = "kotlin_module"
public val EMPTY: ModuleMapping = ModuleMapping(emptyMap())
fun create(protoWithAbi: ByteArray? = null): ModuleMapping {
if (protoWithAbi == null) {
fun create(proto: ByteArray? = null): ModuleMapping {
if (proto == null) {
return EMPTY
}
val inputStream = DataInputStream(ByteArrayInputStream(protoWithAbi))
val intCount = inputStream.readInt()
assert(intCount == 1, {"Expected one int value for abi version, but: $intCount"})
val abiVersion = Integer.valueOf(inputStream.readInt());
val inputStream = DataInputStream(ByteArrayInputStream(proto))
val size = inputStream.readInt()
val abiVersion =
if (size == 1) {
// TODO: this is a temporary workaround, drop after M13
BinaryVersion.create(0, inputStream.readInt(), 0)
}
else {
BinaryVersion.create((0..size - 1).map { inputStream.readInt() }.toIntArray())
}
if (AbiVersionUtil.isAbiVersionCompatible(abiVersion)) {
val parseFrom = JvmPackageTable.PackageTable.parseFrom(inputStream)
if (parseFrom != null) {
@@ -55,6 +64,7 @@ public class ModuleMapping private constructor(val packageFqName2Parts: Map<Stri
return ModuleMapping(packageFqNameParts)
}
}
return EMPTY
}
}
@@ -16,13 +16,14 @@
package org.jetbrains.kotlin.load.kotlin.header
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
import org.jetbrains.kotlin.load.java.AbiVersionUtil
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass
public class KotlinClassHeader(
public val kind: KotlinClassHeader.Kind,
public val version: Int,
public val version: BinaryVersion,
public val annotationData: Array<String>?,
public val classKind: KotlinClass.Kind?,
public val syntheticClassKind: KotlinSyntheticClass.Kind?,
@@ -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);
}
}
}