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:
+4
@@ -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 -> {
|
||||
|
||||
+2
-2
@@ -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();
|
||||
|
||||
+43
@@ -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)
|
||||
}
|
||||
}
|
||||
+5
-8
@@ -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
|
||||
|
||||
+16
-5
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user