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:
Alexander Udalov
2015-09-21 18:22:14 +03:00
parent 5fe958f034
commit 6a8d0fbd75
32 changed files with 177 additions and 113 deletions
@@ -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();
}
}
@@ -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())
}
}
}
@@ -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?
@@ -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?
@@ -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");
@@ -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();
}
}
@@ -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))
}
}
@@ -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>?,
@@ -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);
}
}
@@ -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();
}
@@ -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)
}
@@ -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)
@@ -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() }
@@ -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() ->