Split JVM binary version into two: metadata and bytecode interface

Currently all code only uses the first one (JvmMetadataVersion), later the
bytecode interface version (JvmBytecodeBinaryVersion) will be used only in
codegen and reflection to avoid compiling against or calling methods with
unsupported conventions like default method naming and signature,
getters/setters naming etc.
This commit is contained in:
Alexander Udalov
2015-12-28 20:01:00 +03:00
parent fc88a0186f
commit bd47e9d47b
13 changed files with 136 additions and 79 deletions
@@ -18,6 +18,10 @@ package org.jetbrains.kotlin.load.java
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
/**
* The version of conventions used in bytecode of generated .class files, such as default method naming & signatures,
* internal member name mangling specifics, property getter/setter names, etc.
*/
class JvmBytecodeBinaryVersion protected constructor(
major: Int, minor: Int, patch: Int, rest: List<Int>
) : BinaryVersion(major, minor, patch, rest) {
@@ -70,8 +70,8 @@ fun LazyJavaResolverContext.resolveKotlinBinaryClass(kotlinClass: KotlinJvmBinar
val header = kotlinClass.classHeader
return when {
!header.version.isCompatible() -> {
components.errorReporter.reportIncompatibleAbiVersion(kotlinClass.classId, kotlinClass.location, header.version)
!header.metadataVersion.isCompatible() -> {
components.errorReporter.reportIncompatibleAbiVersion(kotlinClass.classId, kotlinClass.location, header.metadataVersion)
KotlinClassLookupResult.NotFound
}
header.kind == KotlinClassHeader.Kind.CLASS -> {
@@ -115,8 +115,8 @@ public final class DeserializedDescriptorResolver {
@Nullable
public String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass, @NotNull Set<KotlinClassHeader.Kind> expectedKinds) {
KotlinClassHeader header = kotlinClass.getClassHeader();
if (!header.getVersion().isCompatible()) {
errorReporter.reportIncompatibleAbiVersion(kotlinClass.getClassId(), kotlinClass.getLocation(), header.getVersion());
if (!header.getMetadataVersion().isCompatible()) {
errorReporter.reportIncompatibleAbiVersion(kotlinClass.getClassId(), kotlinClass.getLocation(), header.getMetadataVersion());
}
else if (expectedKinds.contains(header.getKind())) {
return header.getAnnotationData();
@@ -0,0 +1,43 @@
/*
* 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.load.kotlin
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
/**
* The version of the metadata serialized by the compiler and deserialized by the compiler and reflection.
* This version includes the version of the core protobuf messages (descriptors.proto) as well as JVM extensions (jvm_descriptors.proto).
*/
class JvmMetadataVersion protected constructor(
major: Int, minor: Int, patch: Int, rest: List<Int>
) : BinaryVersion(major, minor, patch, rest) {
override fun isCompatible() = this.isCompatibleTo(INSTANCE)
companion object {
@JvmField
val INSTANCE = create(1, 0, 2)
@JvmField
val INVALID_VERSION = JvmMetadataVersion.create(IntArray(0))
@JvmStatic
fun create(version: IntArray) = create(version, ::JvmMetadataVersion)
@JvmStatic
fun create(major: Int, minor: Int, patch: Int) = create(major, minor, patch, ::JvmMetadataVersion)
}
}
@@ -16,11 +16,13 @@
package org.jetbrains.kotlin.load.kotlin.header
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
class KotlinClassHeader(
val kind: KotlinClassHeader.Kind,
val version: BinaryVersion,
val metadataVersion: JvmMetadataVersion,
val bytecodeVersion: JvmBytecodeBinaryVersion,
val annotationData: Array<String>?,
val strings: Array<String>?,
val filePartClassNames: Array<String>?,
@@ -36,10 +38,5 @@ class KotlinClassHeader(
SYNTHETIC_CLASS
}
override fun toString() = "$kind " + (if (isLocalClass) "(local) " else "") + "version=$version"
override fun toString() = "$kind " + (if (isLocalClass) "(local) " else "") + "version=$metadataVersion"
}
fun KotlinClassHeader.isCompatibleClassKind(): Boolean = version.isCompatible() && kind == KotlinClassHeader.Kind.CLASS
fun KotlinClassHeader.isCompatibleFileFacadeKind(): Boolean = version.isCompatible() && kind == KotlinClassHeader.Kind.FILE_FACADE
fun KotlinClassHeader.isCompatibleMultifileClassKind(): Boolean = version.isCompatible() && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS
fun KotlinClassHeader.isCompatibleMultifileClassPartKind(): Boolean = version.isCompatible() && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART
@@ -20,10 +20,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.SourceElement;
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion;
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion;
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;
import java.util.ArrayList;
import java.util.HashMap;
@@ -45,7 +45,8 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
HEADER_KINDS.put(ClassId.topLevel(KOTLIN_SYNTHETIC_CLASS), SYNTHETIC_CLASS);
}
private BinaryVersion version = JvmBytecodeBinaryVersion.INVALID_VERSION;
private JvmMetadataVersion metadataVersion = null;
private JvmBytecodeBinaryVersion bytecodeVersion = null;
private String multifileClassName = null;
private String[] filePartClassNames = null;
private String[] annotationData = null;
@@ -60,7 +61,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
return null;
}
if (!version.isCompatible()) {
if (metadataVersion == null || !metadataVersion.isCompatible()) {
annotationData = null;
}
else if (shouldHaveData() && annotationData == null) {
@@ -70,7 +71,10 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
}
return new KotlinClassHeader(
headerKind, version, annotationData, strings, filePartClassNames, multifileClassName, isInterfaceDefaultImpls, isLocalClass
headerKind,
metadataVersion != null ? metadataVersion : JvmMetadataVersion.INVALID_VERSION,
bytecodeVersion != null ? bytecodeVersion : JvmBytecodeBinaryVersion.INVALID_VERSION,
annotationData, strings, filePartClassNames, multifileClassName, isInterfaceDefaultImpls, isLocalClass
);
}
@@ -118,7 +122,14 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
String string = name.asString();
if (VERSION_FIELD_NAME.equals(string)) {
version = value instanceof int[] ? JvmBytecodeBinaryVersion.create((int[]) value) : JvmBytecodeBinaryVersion.INVALID_VERSION;
if (value instanceof int[]) {
metadataVersion = JvmMetadataVersion.create((int[]) value);
// If there's no bytecode binary version in the class file, we assume it to be equal to the metadata version
if (bytecodeVersion == null) {
bytecodeVersion = JvmBytecodeBinaryVersion.create((int[]) value);
}
}
}
else if (MULTIFILE_CLASS_NAME_FIELD_NAME.equals(string)) {
multifileClassName = value instanceof String ? (String) value : null;