Introduce infrastructure to separate string table from metadata on JVM
Nothing especially helpful happens here, this is only a big refactoring introducing a separate string array for the string table, which is currently always empty, but will contain actual strings soon
This commit is contained in:
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPackage;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.TypesPackage;
|
||||
@@ -841,6 +842,18 @@ public class AsmUtil {
|
||||
av.visitEnd();
|
||||
}
|
||||
|
||||
public static void writeAnnotationData(@NotNull AnnotationVisitor av, @NotNull byte[] bytes) {
|
||||
JvmCodegenUtil.writeAbiVersion(av);
|
||||
AnnotationVisitor data = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
|
||||
for (String string : BitEncoding.encodeBytes(bytes)) {
|
||||
data.visit(null, string);
|
||||
}
|
||||
data.visitEnd();
|
||||
AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.STRINGS_FIELD_NAME);
|
||||
// TODO: write the actual string table
|
||||
strings.visitEnd();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
|
||||
return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
|
||||
|
||||
@@ -41,7 +41,6 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf;
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.kotlin.utils.UtilsPackage;
|
||||
@@ -231,12 +230,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
ProtoBuf.Callable callableProto = serializer.callableProto(funDescriptor).build();
|
||||
|
||||
AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CALLABLE), true);
|
||||
JvmCodegenUtil.writeAbiVersion(av);
|
||||
AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
|
||||
for (String string : BitEncoding.encodeBytes(serializer.serialize(callableProto))) {
|
||||
array.visit(null, string);
|
||||
}
|
||||
array.visitEnd();
|
||||
writeAnnotationData(av, serializer.serialize(callableProto));
|
||||
av.visitEnd();
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf;
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
@@ -254,7 +253,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
|
||||
|
||||
AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS), true);
|
||||
JvmCodegenUtil.writeAbiVersion(av);
|
||||
writeAnnotationData(av, serializer.serialize(classProto));
|
||||
if (kind != null) {
|
||||
av.visitEnum(
|
||||
JvmAnnotationNames.KIND_FIELD_NAME,
|
||||
@@ -262,11 +261,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
kind.toString()
|
||||
);
|
||||
}
|
||||
AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
|
||||
for (String string : BitEncoding.encodeBytes(serializer.serialize(classProto))) {
|
||||
array.visit(null, string);
|
||||
}
|
||||
array.visitEnd();
|
||||
av.visitEnd();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.psi.JetProperty
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import java.util.*
|
||||
@@ -96,13 +95,8 @@ public class MultifileClassPartCodegen(
|
||||
if (packageProto.memberCount == 0) return
|
||||
|
||||
val av = v.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS_PART), true)
|
||||
JvmCodegenUtil.writeAbiVersion(av)
|
||||
AsmUtil.writeAnnotationData(av, serializer.serialize(packageProto))
|
||||
av.visit(JvmAnnotationNames.MULTIFILE_CLASS_NAME_FIELD_NAME, multifileClassFqName.shortName().asString())
|
||||
val dataArray = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME)
|
||||
for (string in BitEncoding.encodeBytes(serializer.serialize(packageProto))) {
|
||||
dataArray.visit(null, string)
|
||||
}
|
||||
dataArray.visitEnd()
|
||||
av.visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ import org.jetbrains.kotlin.serialization.ProtoBuf;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
@@ -291,12 +290,7 @@ public class PackageCodegen {
|
||||
ProtoBuf.Package packageProto = serializer.packageProtoWithoutDescriptors().build();
|
||||
|
||||
AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_PACKAGE), true);
|
||||
JvmCodegenUtil.writeAbiVersion(av);
|
||||
AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
|
||||
for (String string : BitEncoding.encodeBytes(serializer.serialize(packageProto))) {
|
||||
array.visit(null, string);
|
||||
}
|
||||
array.visitEnd();
|
||||
AsmUtil.writeAnnotationData(av, serializer.serialize(packageProto));
|
||||
av.visitEnd();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf;
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
@@ -41,6 +40,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.writeAnnotationData;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class PackagePartCodegen extends MemberCodegen<JetFile> {
|
||||
@@ -128,12 +128,7 @@ public class PackagePartCodegen extends MemberCodegen<JetFile> {
|
||||
if (packageProto.getMemberCount() == 0) return;
|
||||
|
||||
AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_FILE_FACADE), true);
|
||||
JvmCodegenUtil.writeAbiVersion(av);
|
||||
AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
|
||||
for (String string : BitEncoding.encodeBytes(serializer.serialize(packageProto))) {
|
||||
array.visit(null, string);
|
||||
}
|
||||
array.visitEnd();
|
||||
writeAnnotationData(av, serializer.serialize(packageProto));
|
||||
av.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -117,17 +117,20 @@ public class IncrementalPackageFragmentProvider(
|
||||
allParts.filterNot { it in obsoletePackageParts }
|
||||
} ?: emptyList<String>()
|
||||
|
||||
val dataOfPackageParts = actualPackagePartFiles.map { incrementalCache.getPackagePartData(it) }.filterNotNull()
|
||||
val scopes = actualPackagePartFiles
|
||||
.map {
|
||||
incrementalCache.getPackagePartData(it)
|
||||
}
|
||||
.filterNotNull()
|
||||
.map {
|
||||
IncrementalPackageScope(JvmProtoBufUtil.readPackageDataFrom(it.data, it.strings))
|
||||
}
|
||||
|
||||
if (dataOfPackageParts.isEmpty()) {
|
||||
if (scopes.isEmpty()) {
|
||||
JetScope.Empty
|
||||
}
|
||||
else {
|
||||
val scopes = dataOfPackageParts.map { IncrementalPackageScope(JvmProtoBufUtil.readPackageDataFrom(it)) }
|
||||
ChainedScope(this,
|
||||
"Member scope for incremental compilation: union of package parts data",
|
||||
*scopes.toTypedArray<JetScope>()
|
||||
)
|
||||
ChainedScope(this, "Member scope for incremental compilation: union of package parts data", *scopes.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -16,10 +16,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.kotlin.incremental.components
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class JvmPackagePartProto(val data: ByteArray, val strings: Array<String>) : Serializable
|
||||
|
||||
public interface IncrementalCache {
|
||||
public fun getObsoletePackageParts(): Collection<String>
|
||||
|
||||
public fun getPackagePartData(fqName: String): ByteArray?
|
||||
public fun getPackagePartData(fqName: String): JvmPackagePartProto?
|
||||
|
||||
public fun getModuleMappingData(): ByteArray?
|
||||
|
||||
|
||||
+2
-2
@@ -17,12 +17,12 @@
|
||||
package org.jetbrains.kotlin.rmi.kotlinr
|
||||
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
|
||||
import org.jetbrains.kotlin.rmi.CompileService
|
||||
import org.jetbrains.kotlin.rmi.LoopbackNetworkInterface
|
||||
import org.jetbrains.kotlin.rmi.SOCKET_ANY_FREE_PORT
|
||||
import java.rmi.server.UnicastRemoteObject
|
||||
|
||||
|
||||
public class RemoteIncrementalCacheServer(val cache: IncrementalCache, port: Int = SOCKET_ANY_FREE_PORT) : CompileService.RemoteIncrementalCache {
|
||||
|
||||
init {
|
||||
@@ -31,7 +31,7 @@ public class RemoteIncrementalCacheServer(val cache: IncrementalCache, port: Int
|
||||
|
||||
override fun getObsoletePackageParts(): Collection<String> = cache.getObsoletePackageParts()
|
||||
|
||||
override fun getPackagePartData(fqName: String): ByteArray? = cache.getPackagePartData(fqName)
|
||||
override fun getPackagePartData(fqName: String): JvmPackagePartProto? = cache.getPackagePartData(fqName)
|
||||
|
||||
override fun getModuleMappingData(): ByteArray? = cache.getModuleMappingData()
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.rmi
|
||||
|
||||
import org.jetbrains.kotlin.incremental.components.ScopeKind
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import java.io.Serializable
|
||||
import java.rmi.Remote
|
||||
@@ -34,7 +35,7 @@ public interface CompileService : Remote {
|
||||
public fun getObsoletePackageParts(): Collection<String>
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
public fun getPackagePartData(fqName: String): ByteArray?
|
||||
public fun getPackagePartData(fqName: String): JvmPackagePartProto?
|
||||
|
||||
@Throws(RemoteException::class)
|
||||
public fun getModuleMappingData(): ByteArray?
|
||||
|
||||
+2
-1
@@ -17,12 +17,13 @@
|
||||
package org.jetbrains.kotlin.rmi.service
|
||||
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
|
||||
import org.jetbrains.kotlin.rmi.CompileService
|
||||
|
||||
public class RemoteIncrementalCacheClient(val cache: CompileService.RemoteIncrementalCache): IncrementalCache {
|
||||
override fun getObsoletePackageParts(): Collection<String> = cache.getObsoletePackageParts()
|
||||
|
||||
override fun getPackagePartData(fqName: String): ByteArray? = cache.getPackagePartData(fqName)
|
||||
override fun getPackagePartData(fqName: String): JvmPackagePartProto? = cache.getPackagePartData(fqName)
|
||||
|
||||
override fun getModuleMappingData(): ByteArray? = cache.getModuleMappingData()
|
||||
|
||||
|
||||
@@ -54,7 +54,9 @@ public class KotlinClassAnnotationTest extends CodegenTestCase {
|
||||
|
||||
String[] data = (String[]) CodegenTestUtil.getAnnotationAttribute(kotlinClass, "data");
|
||||
assertNotNull(data);
|
||||
ClassData classData = JvmProtoBufUtil.readClassDataFrom(data);
|
||||
String[] strings = (String[]) CodegenTestUtil.getAnnotationAttribute(kotlinClass, "strings");
|
||||
assertNotNull(strings);
|
||||
ClassData classData = JvmProtoBufUtil.readClassDataFrom(data, strings);
|
||||
|
||||
Set<String> callableNames = collectCallableNames(classData.getClassProto().getMemberList(), classData.getNameResolver());
|
||||
assertSameElements(Arrays.asList("foo", "bar"), callableNames);
|
||||
|
||||
@@ -60,7 +60,9 @@ public class KotlinPackageAnnotationTest extends CodegenTestCase {
|
||||
|
||||
String[] data = (String[]) CodegenTestUtil.getAnnotationAttribute(kotlinPackage, "data");
|
||||
assertNotNull(data);
|
||||
PackageData packageData = JvmProtoBufUtil.readPackageDataFrom(data);
|
||||
String[] strings = (String[]) CodegenTestUtil.getAnnotationAttribute(kotlinPackage, "strings");
|
||||
assertNotNull(strings);
|
||||
PackageData packageData = JvmProtoBufUtil.readPackageDataFrom(data, strings);
|
||||
|
||||
Set<String> callableNames = collectCallableNames(packageData.getPackageProto().getMemberList(), packageData.getNameResolver());
|
||||
assertEmpty(callableNames);
|
||||
@@ -84,7 +86,9 @@ public class KotlinPackageAnnotationTest extends CodegenTestCase {
|
||||
|
||||
String[] data = (String[]) CodegenTestUtil.getAnnotationAttribute(kotlinPackage, "data");
|
||||
assertNotNull(data);
|
||||
PackageData packageData = JvmProtoBufUtil.readPackageDataFrom(data);
|
||||
String[] strings = (String[]) CodegenTestUtil.getAnnotationAttribute(kotlinPackage, "strings");
|
||||
assertNotNull(strings);
|
||||
PackageData packageData = JvmProtoBufUtil.readPackageDataFrom(data, strings);
|
||||
|
||||
Set<String> callableNames = collectCallableNames(packageData.getPackageProto().getMemberList(), packageData.getNameResolver());
|
||||
assertSameElements(callableNames, Arrays.asList("foo", "bar"));
|
||||
|
||||
@@ -48,6 +48,7 @@ public final class JvmAnnotationNames {
|
||||
public static final String FILE_PART_CLASS_NAMES_FIELD_NAME = "filePartClassNames";
|
||||
public static final String MULTIFILE_CLASS_NAME_FIELD_NAME = "multifileClassName";
|
||||
public static final String DATA_FIELD_NAME = "data";
|
||||
public static final String STRINGS_FIELD_NAME = "strings";
|
||||
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
|
||||
public static final Name TARGET_ANNOTATION_MEMBER_NAME = Name.identifier("allowedTargets");
|
||||
|
||||
|
||||
+7
-3
@@ -61,7 +61,9 @@ public final class DeserializedDescriptorResolver {
|
||||
public ClassDescriptor resolveClass(@NotNull KotlinJvmBinaryClass kotlinClass) {
|
||||
String[] data = readData(kotlinClass, KOTLIN_CLASS);
|
||||
if (data != null) {
|
||||
ClassData classData = JvmProtoBufUtil.readClassDataFrom(data);
|
||||
String[] strings = kotlinClass.getClassHeader().getStrings();
|
||||
assert strings != null : "String table not found in " + kotlinClass;
|
||||
ClassData classData = JvmProtoBufUtil.readClassDataFrom(data, strings);
|
||||
KotlinJvmBinarySourceElement sourceElement = new KotlinJvmBinarySourceElement(kotlinClass);
|
||||
return components.getClassDeserializer().deserializeClass(
|
||||
kotlinClass.getClassId(),
|
||||
@@ -75,13 +77,15 @@ public final class DeserializedDescriptorResolver {
|
||||
public JetScope createKotlinPackagePartScope(@NotNull PackageFragmentDescriptor descriptor, @NotNull KotlinJvmBinaryClass kotlinClass) {
|
||||
String[] data = readData(kotlinClass, KOTLIN_FILE_FACADE_OR_MULTIFILE_CLASS_PART);
|
||||
if (data != null) {
|
||||
//all classes are included in java scope
|
||||
PackageData packageData = JvmProtoBufUtil.readPackageDataFrom(data);
|
||||
String[] strings = kotlinClass.getClassHeader().getStrings();
|
||||
assert strings != null : "String table not found in " + kotlinClass;
|
||||
PackageData packageData = JvmProtoBufUtil.readPackageDataFrom(data, strings);
|
||||
return new DeserializedPackageMemberScope(
|
||||
descriptor, packageData.getPackageProto(), packageData.getNameResolver(), components,
|
||||
new Function0<Collection<Name>>() {
|
||||
@Override
|
||||
public Collection<Name> invoke() {
|
||||
// All classes are included into Java scope
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -27,11 +27,12 @@ public class JavaClassDataFinder(
|
||||
) : ClassDataFinder {
|
||||
override fun findClassData(classId: ClassId): ClassDataWithSource? {
|
||||
val kotlinJvmBinaryClass = kotlinClassFinder.findKotlinClass(classId) ?: return null
|
||||
assert(kotlinJvmBinaryClass.getClassId() == classId) {
|
||||
"Class with incorrect id found: expected $classId, actual ${kotlinJvmBinaryClass.getClassId()}"
|
||||
assert(kotlinJvmBinaryClass.classId == classId) {
|
||||
"Class with incorrect id found: expected $classId, actual ${kotlinJvmBinaryClass.classId}"
|
||||
}
|
||||
val data = deserializedDescriptorResolver.readData(kotlinJvmBinaryClass, DeserializedDescriptorResolver.KOTLIN_CLASS) ?: return null
|
||||
val classData = JvmProtoBufUtil.readClassDataFrom(data)
|
||||
val strings = kotlinJvmBinaryClass.classHeader.strings ?: error("String table not found in $kotlinJvmBinaryClass")
|
||||
val classData = JvmProtoBufUtil.readClassDataFrom(data, strings)
|
||||
return ClassDataWithSource(classData, KotlinJvmBinarySourceElement(kotlinJvmBinaryClass))
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ public class KotlinClassHeader(
|
||||
public val kind: KotlinClassHeader.Kind,
|
||||
public val version: BinaryVersion,
|
||||
public val annotationData: Array<String>?,
|
||||
public val strings: Array<String>?,
|
||||
public val classKind: KotlinClass.Kind?,
|
||||
public val syntheticClassKind: KotlinSyntheticClass.Kind?,
|
||||
public val filePartClassNames: Array<String>?,
|
||||
|
||||
+33
-16
@@ -64,6 +64,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
||||
private String multifileClassName = null;
|
||||
private String[] filePartClassNames = null;
|
||||
private String[] annotationData = null;
|
||||
private String[] strings = null;
|
||||
private KotlinClassHeader.Kind headerKind = null;
|
||||
private KotlinClass.Kind classKind = null;
|
||||
private KotlinSyntheticClass.Kind syntheticClassKind = null;
|
||||
@@ -80,7 +81,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
||||
}
|
||||
|
||||
if (!AbiVersionUtil.isAbiVersionCompatible(version)) {
|
||||
return new KotlinClassHeader(headerKind, version, null, classKind, syntheticClassKind, null, null);
|
||||
return new KotlinClassHeader(headerKind, version, null, strings, classKind, syntheticClassKind, null, null);
|
||||
}
|
||||
|
||||
if (shouldHaveData() && annotationData == null) {
|
||||
@@ -89,7 +90,9 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
||||
return null;
|
||||
}
|
||||
|
||||
return new KotlinClassHeader(headerKind, version, annotationData, classKind, syntheticClassKind, filePartClassNames, multifileClassName);
|
||||
return new KotlinClassHeader(
|
||||
headerKind, version, annotationData, strings, classKind, syntheticClassKind, filePartClassNames, multifileClassName
|
||||
);
|
||||
}
|
||||
|
||||
private boolean shouldHaveData() {
|
||||
@@ -171,10 +174,14 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
||||
@Override
|
||||
@Nullable
|
||||
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
|
||||
if (name.asString().equals(DATA_FIELD_NAME)) {
|
||||
String string = name.asString();
|
||||
if (DATA_FIELD_NAME.equals(string)) {
|
||||
return dataArrayVisitor();
|
||||
}
|
||||
else if (name.asString().equals(FILE_PART_CLASS_NAMES_FIELD_NAME)) {
|
||||
else if (STRINGS_FIELD_NAME.equals(string)) {
|
||||
return stringsArrayVisitor();
|
||||
}
|
||||
else if (FILE_PART_CLASS_NAMES_FIELD_NAME.equals(string)) {
|
||||
return filePartClassNamesVisitor();
|
||||
}
|
||||
else {
|
||||
@@ -186,12 +193,32 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
||||
private AnnotationArrayArgumentVisitor filePartClassNamesVisitor() {
|
||||
return new CollectStringArrayAnnotationVisitor() {
|
||||
@Override
|
||||
protected void visitEnd(String[] data) {
|
||||
protected void visitEnd(@NotNull String[] data) {
|
||||
filePartClassNames = data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AnnotationArrayArgumentVisitor dataArrayVisitor() {
|
||||
return new CollectStringArrayAnnotationVisitor() {
|
||||
@Override
|
||||
protected void visitEnd(@NotNull String[] data) {
|
||||
annotationData = data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AnnotationArrayArgumentVisitor stringsArrayVisitor() {
|
||||
return new CollectStringArrayAnnotationVisitor() {
|
||||
@Override
|
||||
protected void visitEnd(@NotNull String[] data) {
|
||||
strings = data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
||||
}
|
||||
@@ -202,16 +229,6 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AnnotationArrayArgumentVisitor dataArrayVisitor() {
|
||||
return new CollectStringArrayAnnotationVisitor() {
|
||||
@Override
|
||||
protected void visitEnd(String[] data) {
|
||||
annotationData = data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
}
|
||||
@@ -240,7 +257,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
||||
visitEnd(strings.toArray(new String[strings.size()]));
|
||||
}
|
||||
|
||||
protected abstract void visitEnd(String[] data);
|
||||
protected abstract void visitEnd(@NotNull String[] data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -31,11 +31,11 @@ public object JvmProtoBufUtil {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
public fun readClassDataFrom(data: Array<String>): ClassData =
|
||||
readClassDataFrom(BitEncoding.decodeBytes(data))
|
||||
public fun readClassDataFrom(data: Array<String>, strings: Array<String>): ClassData =
|
||||
readClassDataFrom(BitEncoding.decodeBytes(data), strings)
|
||||
|
||||
@JvmStatic
|
||||
public fun readClassDataFrom(bytes: ByteArray): ClassData {
|
||||
public fun readClassDataFrom(bytes: ByteArray, strings: Array<String>): ClassData {
|
||||
val input = ByteArrayInputStream(bytes)
|
||||
val nameResolver = NameResolverImpl.read(input)
|
||||
val classProto = ProtoBuf.Class.parseFrom(input, EXTENSION_REGISTRY)
|
||||
@@ -43,11 +43,11 @@ public object JvmProtoBufUtil {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
public fun readPackageDataFrom(data: Array<String>): PackageData =
|
||||
readPackageDataFrom(BitEncoding.decodeBytes(data))
|
||||
public fun readPackageDataFrom(data: Array<String>, strings: Array<String>): PackageData =
|
||||
readPackageDataFrom(BitEncoding.decodeBytes(data), strings)
|
||||
|
||||
@JvmStatic
|
||||
public fun readPackageDataFrom(bytes: ByteArray): PackageData {
|
||||
public fun readPackageDataFrom(bytes: ByteArray, strings: Array<String>): PackageData {
|
||||
val input = ByteArrayInputStream(bytes)
|
||||
val nameResolver = NameResolverImpl.read(input)
|
||||
val packageProto = ProtoBuf.Package.parseFrom(input, EXTENSION_REGISTRY)
|
||||
|
||||
@@ -30,4 +30,6 @@ public @interface KotlinCallable {
|
||||
int[] version() default {};
|
||||
|
||||
String[] data();
|
||||
|
||||
String[] strings();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ public @interface KotlinClass {
|
||||
|
||||
String[] data();
|
||||
|
||||
String[] strings();
|
||||
|
||||
enum Kind {
|
||||
CLASS,
|
||||
|
||||
|
||||
@@ -30,4 +30,6 @@ public @interface KotlinFileFacade {
|
||||
int[] version() default {};
|
||||
|
||||
String[] data();
|
||||
|
||||
String[] strings();
|
||||
}
|
||||
|
||||
@@ -30,4 +30,6 @@ public @interface KotlinMultifileClass {
|
||||
int[] version() default {};
|
||||
|
||||
String[] filePartClassNames();
|
||||
|
||||
String[] strings();
|
||||
}
|
||||
|
||||
@@ -32,4 +32,6 @@ public @interface KotlinMultifileClassPart {
|
||||
String multifileClassName();
|
||||
|
||||
String[] data();
|
||||
|
||||
String[] strings();
|
||||
}
|
||||
|
||||
@@ -30,4 +30,6 @@ public @interface KotlinPackage {
|
||||
int[] version() default {};
|
||||
|
||||
String[] data();
|
||||
|
||||
String[] strings();
|
||||
}
|
||||
|
||||
+8
-3
@@ -70,20 +70,25 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() {
|
||||
LOG.error("Corrupted kotlin header for file ${file.getName()}")
|
||||
return null
|
||||
}
|
||||
val strings = header.strings
|
||||
if (strings == null) {
|
||||
LOG.error("String table not found in file ${file.getName()}")
|
||||
return null
|
||||
}
|
||||
return when {
|
||||
header.isCompatiblePackageFacadeKind() -> {
|
||||
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData)
|
||||
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings)
|
||||
val context = components.createContext(nameResolver, packageFqName)
|
||||
createPackageFacadeStub(packageProto, packageFqName, context)
|
||||
}
|
||||
header.isCompatibleClassKind() -> {
|
||||
if (header.classKind != JvmAnnotationNames.KotlinClass.Kind.CLASS) return null
|
||||
val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(annotationData)
|
||||
val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(annotationData, strings)
|
||||
val context = components.createContext(nameResolver, packageFqName)
|
||||
createTopLevelClassStub(classId, classProto, context)
|
||||
}
|
||||
header.isCompatibleFileFacadeKind() -> {
|
||||
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData)
|
||||
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings)
|
||||
val context = components.createContext(nameResolver, packageFqName)
|
||||
createFileFacadeStub(packageProto, classId.asSingleFqName(), context)
|
||||
}
|
||||
|
||||
+1
-2
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.idea.stubindex.KotlinFileStubForIde
|
||||
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -87,7 +86,7 @@ fun createMultifileClassStub(
|
||||
val multifileClassContainer = ProtoContainer(null, packageFqName)
|
||||
for (partFile in partFiles) {
|
||||
val partHeader = partFile.classHeader
|
||||
val partData = JvmProtoBufUtil.readPackageDataFrom(partHeader.annotationData!!)
|
||||
val partData = JvmProtoBufUtil.readPackageDataFrom(partHeader.annotationData!!, partHeader.strings!!)
|
||||
val partContext = components.createContext(partData.nameResolver, packageFqName)
|
||||
for (partMember in partData.packageProto.memberList) {
|
||||
createCallableStub(fileStub, partMember, partContext, multifileClassContainer)
|
||||
|
||||
+6
-4
@@ -62,12 +62,14 @@ public class DeserializerForDecompiler(
|
||||
"Was called for $facadeFqName; only members of $directoryPackageFqName package are expected."
|
||||
}
|
||||
val binaryClassForPackageClass = classFinder.findKotlinClass(ClassId.topLevel(facadeFqName))
|
||||
val annotationData = binaryClassForPackageClass?.classHeader?.annotationData
|
||||
if (annotationData == null) {
|
||||
LOG.error("Could not read annotation data for $facadeFqName from ${binaryClassForPackageClass?.classId}")
|
||||
val header = binaryClassForPackageClass?.classHeader
|
||||
val annotationData = header?.annotationData
|
||||
val strings = header?.strings
|
||||
if (annotationData == null || strings == null) {
|
||||
LOG.error("Could not read annotation data for $facadeFqName from ${binaryClassForPackageClass?.getClassId()}")
|
||||
return emptyList()
|
||||
}
|
||||
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData)
|
||||
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings)
|
||||
val membersScope = DeserializedPackageMemberScope(
|
||||
createDummyPackageFragment(packageFqName), packageProto, nameResolver, deserializationComponents
|
||||
) { emptyList() }
|
||||
|
||||
+9
-4
@@ -73,14 +73,19 @@ class DirectoryBasedDataFinder(
|
||||
) : ClassDataFinder {
|
||||
override fun findClassData(classId: ClassId): ClassDataWithSource? {
|
||||
val binaryClass = classFinder.findKotlinClass(classId) ?: return null
|
||||
val data = binaryClass.getClassHeader().annotationData
|
||||
val classHeader = binaryClass.classHeader
|
||||
val data = classHeader.annotationData
|
||||
if (data == null) {
|
||||
log.error("Annotation data missing for ${binaryClass.getClassId()}")
|
||||
log.error("Annotation data missing for ${binaryClass.classId}")
|
||||
return null
|
||||
}
|
||||
val strings = classHeader.strings
|
||||
if (strings == null) {
|
||||
log.error("String table not found in class ${binaryClass.classId}")
|
||||
return null
|
||||
}
|
||||
|
||||
val classData = JvmProtoBufUtil.readClassDataFrom(data)
|
||||
return ClassDataWithSource(classData)
|
||||
return ClassDataWithSource(JvmProtoBufUtil.readClassDataFrom(data, strings))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName.byInternalName
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||
@@ -167,7 +168,7 @@ public class IncrementalCacheImpl(
|
||||
|
||||
public fun saveModuleMappingToCache(sourceFiles: Collection<File>, file: File): ChangesInfo {
|
||||
val jvmClassName = JvmClassName.byInternalName(MODULE_MAPPING_FILE_NAME)
|
||||
protoMap.process(jvmClassName, file.readBytes(), isPackage = false, checkChangesIsOpenPart = false)
|
||||
protoMap.process(jvmClassName, file.readBytes(), emptyArray<String>(), isPackage = false, checkChangesIsOpenPart = false)
|
||||
dirtyOutputClassesMap.notDirty(MODULE_MAPPING_FILE_NAME)
|
||||
sourceFiles.forEach { sourceToClassesMap.add(it, jvmClassName) }
|
||||
return ChangesInfo.NO_CHANGES
|
||||
@@ -249,8 +250,10 @@ public class IncrementalCacheImpl(
|
||||
return obsoletePackageParts
|
||||
}
|
||||
|
||||
override fun getPackagePartData(fqName: String): ByteArray? {
|
||||
return protoMap[JvmClassName.byInternalName(fqName)]?.bytes
|
||||
override fun getPackagePartData(fqName: String): JvmPackagePartProto? {
|
||||
return protoMap[JvmClassName.byInternalName(fqName)]?.let { value ->
|
||||
JvmPackagePartProto(value.bytes, value.strings)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getModuleMappingData(): ByteArray? {
|
||||
@@ -275,19 +278,24 @@ public class IncrementalCacheImpl(
|
||||
public fun process(kotlinClass: LocalFileKotlinClass, isPackage: Boolean, checkChangesIsOpenPart: Boolean = true): ChangesInfo {
|
||||
val header = kotlinClass.classHeader
|
||||
val bytes = BitEncoding.decodeBytes(header.annotationData!!)
|
||||
return put(kotlinClass.className, bytes, isPackage, checkChangesIsOpenPart)
|
||||
return put(kotlinClass.className, bytes, header.strings!!, isPackage, checkChangesIsOpenPart)
|
||||
}
|
||||
|
||||
public fun process(className: JvmClassName, data: ByteArray, isPackage: Boolean, checkChangesIsOpenPart: Boolean): ChangesInfo {
|
||||
return put(className, data, isPackage, checkChangesIsOpenPart)
|
||||
public fun process(className: JvmClassName, data: ByteArray, strings: Array<String>, isPackage: Boolean, checkChangesIsOpenPart: Boolean): ChangesInfo {
|
||||
return put(className, data, strings, isPackage, checkChangesIsOpenPart)
|
||||
}
|
||||
|
||||
private fun put(className: JvmClassName, bytes: ByteArray, isPackage: Boolean, checkChangesIsOpenPart: Boolean): ChangesInfo {
|
||||
private fun put(
|
||||
className: JvmClassName, bytes: ByteArray, strings: Array<String>, isPackage: Boolean, checkChangesIsOpenPart: Boolean
|
||||
): ChangesInfo {
|
||||
val key = className.internalName
|
||||
val oldData = storage[key]
|
||||
val data = ProtoMapValue(isPackage, bytes)
|
||||
val data = ProtoMapValue(isPackage, bytes, strings)
|
||||
|
||||
if (oldData == null || !Arrays.equals(bytes, oldData.bytes) || isPackage != oldData.isPackageFacade) {
|
||||
if (oldData == null ||
|
||||
!Arrays.equals(bytes, oldData.bytes) ||
|
||||
!Arrays.equals(strings, oldData.strings) ||
|
||||
isPackage != oldData.isPackageFacade) {
|
||||
storage[key] = data
|
||||
}
|
||||
|
||||
@@ -757,14 +765,19 @@ private object ProtoMapValueExternalizer : DataExternalizer<ProtoMapValue> {
|
||||
out.writeBoolean(value.isPackageFacade)
|
||||
out.writeInt(value.bytes.size())
|
||||
out.write(value.bytes)
|
||||
out.writeInt(value.strings.size())
|
||||
for (string in value.strings) {
|
||||
out.writeUTF(string)
|
||||
}
|
||||
}
|
||||
|
||||
override fun read(`in`: DataInput): ProtoMapValue {
|
||||
val isPackageFacade = `in`.readBoolean()
|
||||
val length = `in`.readInt()
|
||||
val buf = ByteArray(length)
|
||||
`in`.readFully(buf)
|
||||
return ProtoMapValue(isPackageFacade, buf)
|
||||
val bytesLength = `in`.readInt()
|
||||
val bytes = ByteArray(bytesLength)
|
||||
`in`.readFully(bytes, 0, bytesLength)
|
||||
val stringsLength = `in`.readInt()
|
||||
val strings = Array<String>(stringsLength) { `in`.readUTF() }
|
||||
return ProtoMapValue(isPackageFacade, bytes, strings)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public sealed class DifferenceKind() {
|
||||
public class MEMBERS(val names: Collection<String>): DifferenceKind()
|
||||
}
|
||||
|
||||
data class ProtoMapValue(val isPackageFacade: Boolean, val bytes: ByteArray)
|
||||
data class ProtoMapValue(val isPackageFacade: Boolean, val bytes: ByteArray, val strings: Array<String>)
|
||||
|
||||
public fun difference(oldData: ProtoMapValue, newData: ProtoMapValue): DifferenceKind {
|
||||
if (oldData.isPackageFacade != newData.isPackageFacade) return DifferenceKind.CLASS_SIGNATURE
|
||||
@@ -127,8 +127,8 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot
|
||||
)
|
||||
}
|
||||
|
||||
val oldClassData = JvmProtoBufUtil.readClassDataFrom(oldData.bytes)
|
||||
val newClassData = JvmProtoBufUtil.readClassDataFrom(newData.bytes)
|
||||
val oldClassData = JvmProtoBufUtil.readClassDataFrom(oldData.bytes, oldData.strings)
|
||||
val newClassData = JvmProtoBufUtil.readClassDataFrom(newData.bytes, newData.strings)
|
||||
|
||||
val oldProto = oldClassData.classProto
|
||||
val newProto = newClassData.classProto
|
||||
@@ -217,8 +217,8 @@ private class DifferenceCalculatorForClass(oldData: ProtoMapValue, newData: Prot
|
||||
}
|
||||
|
||||
private class DifferenceCalculatorForPackageFacade(oldData: ProtoMapValue, newData: ProtoMapValue) : DifferenceCalculator() {
|
||||
val oldPackageData = JvmProtoBufUtil.readPackageDataFrom(oldData.bytes)
|
||||
val newPackageData = JvmProtoBufUtil.readPackageDataFrom(newData.bytes)
|
||||
val oldPackageData = JvmProtoBufUtil.readPackageDataFrom(oldData.bytes, oldData.strings)
|
||||
val newPackageData = JvmProtoBufUtil.readPackageDataFrom(newData.bytes, newData.strings)
|
||||
|
||||
val oldProto = oldPackageData.packageProto
|
||||
val newProto = newPackageData.packageProto
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.test.JetTestUtils
|
||||
import org.jetbrains.kotlin.test.MockLibraryUtil
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import java.io.File
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
public abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
||||
|
||||
@@ -85,8 +84,14 @@ public abstract class AbstractProtoComparisonTest : UsefulTestCase() {
|
||||
val oldProtoBytes = BitEncoding.decodeBytes(oldClassHeader.annotationData!!)
|
||||
val newProtoBytes = BitEncoding.decodeBytes(newClassHeader.annotationData!!)
|
||||
|
||||
val oldProto = ProtoMapValue(oldClassHeader.isCompatiblePackageFacadeKind() || oldClassHeader.isCompatibleFileFacadeKind(), oldProtoBytes)
|
||||
val newProto = ProtoMapValue(newClassHeader.isCompatiblePackageFacadeKind() || newClassHeader.isCompatibleFileFacadeKind(), newProtoBytes)
|
||||
val oldProto = ProtoMapValue(
|
||||
oldClassHeader.isCompatiblePackageFacadeKind() || oldClassHeader.isCompatibleFileFacadeKind(),
|
||||
oldProtoBytes, oldClassHeader.strings!!
|
||||
)
|
||||
val newProto = ProtoMapValue(
|
||||
newClassHeader.isCompatiblePackageFacadeKind() || newClassHeader.isCompatibleFileFacadeKind(),
|
||||
newProtoBytes, newClassHeader.strings!!
|
||||
)
|
||||
|
||||
val diff = when {
|
||||
newClassHeader.isCompatiblePackageFacadeKind(), newClassHeader.isCompatibleClassKind(), newClassHeader.isCompatibleFileFacadeKind() ->
|
||||
|
||||
Reference in New Issue
Block a user