Write anonymousObjectOriginName for classes copied during inline

#KT-21320
This commit is contained in:
Alexander Udalov
2018-02-01 19:13:43 +01:00
parent 81122ed236
commit 6da3f37fc3
11 changed files with 156 additions and 35 deletions
@@ -200,6 +200,11 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
}
}
if (old.hasExtension(JvmProtoBuf.anonymousObjectOriginName) != new.hasExtension(JvmProtoBuf.anonymousObjectOriginName)) return false
if (old.hasExtension(JvmProtoBuf.anonymousObjectOriginName)) {
if (!checkStringEquals(old.getExtension(JvmProtoBuf.anonymousObjectOriginName), new.getExtension(JvmProtoBuf.anonymousObjectOriginName))) return false
}
if (old.getExtensionCount(JsProtoBuf.classAnnotation) != new.getExtensionCount(JsProtoBuf.classAnnotation)) {
return false
}
@@ -249,6 +254,7 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
VERSION_REQUIREMENT_TABLE,
JVM_EXT_CLASS_MODULE_NAME,
JVM_EXT_CLASS_LOCAL_VARIABLE_LIST,
JVM_EXT_ANONYMOUS_OBJECT_ORIGIN_NAME,
JS_EXT_CLASS_ANNOTATION_LIST,
JS_EXT_CLASS_CONTAINING_FILE_ID,
JAVA_EXT_IS_PACKAGE_PRIVATE_CLASS,
@@ -319,6 +325,11 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
}
}
if (old.hasExtension(JvmProtoBuf.anonymousObjectOriginName) != new.hasExtension(JvmProtoBuf.anonymousObjectOriginName)) result.add(ProtoBufClassKind.JVM_EXT_ANONYMOUS_OBJECT_ORIGIN_NAME)
if (old.hasExtension(JvmProtoBuf.anonymousObjectOriginName)) {
if (!checkStringEquals(old.getExtension(JvmProtoBuf.anonymousObjectOriginName), new.getExtension(JvmProtoBuf.anonymousObjectOriginName))) result.add(ProtoBufClassKind.JVM_EXT_ANONYMOUS_OBJECT_ORIGIN_NAME)
}
if (old.getExtensionCount(JsProtoBuf.classAnnotation) != new.getExtensionCount(JsProtoBuf.classAnnotation)) {
result.add(ProtoBufClassKind.JS_EXT_CLASS_ANNOTATION_LIST)
}
@@ -1551,6 +1562,10 @@ fun ProtoBuf.Class.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) ->
hashCode = 31 * hashCode + getExtension(JvmProtoBuf.classLocalVariable, i).hashCode(stringIndexes, fqNameIndexes)
}
if (hasExtension(JvmProtoBuf.anonymousObjectOriginName)) {
hashCode = 31 * hashCode + stringIndexes(getExtension(JvmProtoBuf.anonymousObjectOriginName))
}
for(i in 0..getExtensionCount(JsProtoBuf.classAnnotation) - 1) {
hashCode = 31 * hashCode + getExtension(JsProtoBuf.classAnnotation, i).hashCode(stringIndexes, fqNameIndexes)
}
@@ -251,6 +251,9 @@ class DifferenceCalculatorForClass(
ProtoBufClassKind.BUILT_INS_EXT_CLASS_ANNOTATION_LIST -> {
isClassAffected = true
}
ProtoCompareGenerated.ProtoBufClassKind.JVM_EXT_ANONYMOUS_OBJECT_ORIGIN_NAME -> {
// Not affected, this extension is not used in the compiler
}
}
}
@@ -15,6 +15,7 @@ public final class DebugJvmProtoBuf {
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.typeParameterAnnotation);
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.classModuleName);
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.classLocalVariable);
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.anonymousObjectOriginName);
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.packageModuleName);
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.packageLocalVariable);
}
@@ -4599,6 +4600,22 @@ public final class DebugJvmProtoBuf {
.newFileScopedGeneratedExtension(
org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.class,
org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.getDefaultInstance());
public static final int ANONYMOUS_OBJECT_ORIGIN_NAME_FIELD_NUMBER = 103;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Class { ... }</code>
*
* <pre>
* For anonymous objects from bodies of inline functions copied to the use site, the JVM internal name of the original
* anonymous object this class is copied from
* </pre>
*/
public static final
org.jetbrains.kotlin.protobuf.GeneratedMessage.GeneratedExtension<
org.jetbrains.kotlin.serialization.DebugProtoBuf.Class,
java.lang.Integer> anonymousObjectOriginName = org.jetbrains.kotlin.protobuf.GeneratedMessage
.newFileScopedGeneratedExtension(
java.lang.Integer.class,
null);
public static final int PACKAGE_MODULE_NAME_FIELD_NUMBER = 101;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
@@ -4704,13 +4721,15 @@ public final class DebugJvmProtoBuf {
".serialization.Class\030e \001(\005B\004\230\265\030\001:u\n\024clas" +
"s_local_variable\022).org.jetbrains.kotlin." +
"serialization.Class\030f \003(\0132,.org.jetbrain" +
"s.kotlin.serialization.Property:N\n\023packa",
"ge_module_name\022+.org.jetbrains.kotlin.se" +
"rialization.Package\030e \001(\005B\004\230\265\030\001:y\n\026packa" +
"ge_local_variable\022+.org.jetbrains.kotlin" +
".serialization.Package\030f \003(\0132,.org.jetbr" +
"ains.kotlin.serialization.PropertyB\022B\020De" +
"bugJvmProtoBuf"
"s.kotlin.serialization.Property:U\n\034anony",
"mous_object_origin_name\022).org.jetbrains." +
"kotlin.serialization.Class\030g \001(\005B\004\230\265\030\001:N" +
"\n\023package_module_name\022+.org.jetbrains.ko" +
"tlin.serialization.Package\030e \001(\005B\004\230\265\030\001:y" +
"\n\026package_local_variable\022+.org.jetbrains" +
".kotlin.serialization.Package\030f \003(\0132,.or" +
"g.jetbrains.kotlin.serialization.Propert" +
"yB\022B\020DebugJvmProtoBuf"
};
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
@@ -4764,8 +4783,9 @@ public final class DebugJvmProtoBuf {
typeParameterAnnotation.internalInit(descriptor.getExtensions().get(5));
classModuleName.internalInit(descriptor.getExtensions().get(6));
classLocalVariable.internalInit(descriptor.getExtensions().get(7));
packageModuleName.internalInit(descriptor.getExtensions().get(8));
packageLocalVariable.internalInit(descriptor.getExtensions().get(9));
anonymousObjectOriginName.internalInit(descriptor.getExtensions().get(8));
packageModuleName.internalInit(descriptor.getExtensions().get(9));
packageLocalVariable.internalInit(descriptor.getExtensions().get(10));
org.jetbrains.kotlin.protobuf.ExtensionRegistry registry =
org.jetbrains.kotlin.protobuf.ExtensionRegistry.newInstance();
registry.add(org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf.stringIdInTable);
@@ -4774,6 +4794,7 @@ public final class DebugJvmProtoBuf {
registry.add(org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf.stringIdInTable);
registry.add(org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf.stringIdInTable);
registry.add(org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf.stringIdInTable);
registry.add(org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf.stringIdInTable);
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor
.internalUpdateFileDescriptor(descriptor, registry);
org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf.getDescriptor();
@@ -45,10 +45,7 @@ import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveClass;
@@ -875,19 +872,24 @@ public class AsmUtil {
@NotNull DescriptorSerializer serializer,
@NotNull MessageLite message
) {
byte[] bytes = serializer.serialize(message);
writeAnnotationData(av, message, (JvmStringTable) serializer.getStringTable());
}
AnnotationVisitor data = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME);
for (String string : BitEncoding.encodeBytes(bytes)) {
data.visit(null, string);
public static void writeAnnotationData(
@NotNull AnnotationVisitor av, @NotNull MessageLite message, @NotNull JvmStringTable stringTable
) {
String[] data = BitEncoding.encodeBytes(DescriptorSerializer.serialize(message, stringTable));
AnnotationVisitor dataVisitor = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME);
for (String string : data) {
dataVisitor.visit(null, string);
}
data.visitEnd();
dataVisitor.visitEnd();
AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.METADATA_STRINGS_FIELD_NAME);
for (String string : ((JvmStringTable) serializer.getStringTable()).getStrings()) {
strings.visit(null, string);
AnnotationVisitor stringsVisitor = av.visitArray(JvmAnnotationNames.METADATA_STRINGS_FIELD_NAME);
for (String string : stringTable.getStrings()) {
stringsVisitor.visit(null, string);
}
strings.visitEnd();
stringsVisitor.visitEnd();
}
@NotNull
@@ -21,8 +21,18 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_IMPL_ASM_TYPE
import org.jetbrains.kotlin.codegen.serialization.JvmStringTable
import org.jetbrains.kotlin.codegen.writeKotlinMetadata
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.*
@@ -47,6 +57,7 @@ class AnonymousObjectTransformer(
val innerClassNodes = ArrayList<InnerClassNode>()
val classBuilder = createRemappingClassBuilderViaFactory(inliningContext)
val methodsToTransform = ArrayList<MethodNode>()
val metadataReader = ReadKotlinClassHeaderAnnotationVisitor()
createClassReader().accept(object : ClassVisitor(API, classBuilder.visitor) {
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
@@ -60,6 +71,15 @@ class AnonymousObjectTransformer(
innerClassNodes.add(InnerClassNode(name, outerName, innerName, access))
}
override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? {
if (desc == JvmAnnotationNames.METADATA_DESC) {
// Empty inner class info because no inner classes are used in kotlin.Metadata and its arguments
val innerClassesInfo = FileBasedKotlinClass.InnerClassesInfo()
return FileBasedKotlinClass.convertAnnotationVisitor(metadataReader, desc, innerClassesInfo)
}
return super.visitAnnotation(desc, visible)
}
override fun visitMethod(
access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?
): MethodVisitor {
@@ -150,6 +170,11 @@ class AnonymousObjectTransformer(
visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access)
}
val header = metadataReader.createHeader()
if (header != null) {
transformMetadata(header, classBuilder)
}
writeOuterInfo(visitor)
classBuilder.done()
@@ -157,6 +182,26 @@ class AnonymousObjectTransformer(
return transformationResult
}
private fun transformMetadata(header: KotlinClassHeader, classBuilder: ClassBuilder) {
val newProto: MessageLite
val newStringTable: JvmStringTable
if (header.kind == KotlinClassHeader.Kind.CLASS) {
val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(header.data!!, header.strings!!)
newStringTable = JvmStringTable(state.typeMapper, nameResolver as JvmNameResolver)
newProto = classProto.toBuilder().apply {
setExtension(JvmProtoBuf.anonymousObjectOriginName, newStringTable.getStringIndex(oldObjectType.internalName))
}.build()
} else if (header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS) {
// TODO: transform metadata for synthetic classes
return
} else return
writeKotlinMetadata(classBuilder, state, header.kind, header.extraInt) { av ->
AsmUtil.writeAnnotationData(av, newProto, newStringTable)
}
}
private fun writeOuterInfo(visitor: ClassVisitor) {
val info = inliningContext.callSiteInfo
visitor.visitOuterClass(info.ownerClassName, info.functionName, info.functionDesc)
@@ -28,14 +28,22 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record
import org.jetbrains.kotlin.types.ErrorUtils
import java.io.OutputStream
import java.util.*
// TODO: optimize by reordering records to minimize storage of 'range' fields
class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
val strings = ArrayList<String>()
private val records = ArrayList<Record.Builder>()
private val map = HashMap<String, Int>()
private val localNames = HashSet<Int>()
private val localNames = LinkedHashSet<Int>()
constructor(typeMapper: KotlinTypeMapper, nameResolver: JvmNameResolver) : this(typeMapper) {
strings.addAll(nameResolver.strings)
nameResolver.records.mapTo(records, JvmProtoBuf.StringTableTypes.Record::toBuilder)
for (index in strings.indices) {
map[nameResolver.getString(index)] = index
}
localNames.addAll(nameResolver.types.localNameList)
}
override fun getStringIndex(string: String): Int =
map.getOrPut(string) {
@@ -159,7 +159,7 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
}
@Nullable
private static org.jetbrains.org.objectweb.asm.AnnotationVisitor convertAnnotationVisitor(
public static org.jetbrains.org.objectweb.asm.AnnotationVisitor convertAnnotationVisitor(
@NotNull AnnotationVisitor visitor, @NotNull String desc, @NotNull InnerClassesInfo innerClasses
) {
AnnotationArgumentVisitor v = visitor.visitAnnotation(resolveNameByDesc(desc, innerClasses), SourceElement.NO_SOURCE);
@@ -40,13 +40,6 @@ class DescriptorSerializer private constructor(
) {
private val contractSerializer = ContractSerializer()
fun serialize(message: MessageLite): ByteArray {
return ByteArrayOutputStream().apply {
stringTable.serializeTo(this)
message.writeTo(this)
}.toByteArray()
}
private fun createChildSerializer(descriptor: DeclarationDescriptor): DescriptorSerializer =
DescriptorSerializer(descriptor, Interner(typeParameters), extension, typeTable, versionRequirementTable,
serializeTypeTableToFunction = false)
@@ -715,6 +708,14 @@ class DescriptorSerializer private constructor(
return serializer
}
@JvmStatic
fun serialize(message: MessageLite, stringTable: StringTable): ByteArray {
return ByteArrayOutputStream().apply {
stringTable.serializeTo(this)
message.writeTo(this)
}.toByteArray()
}
private fun variance(variance: Variance): ProtoBuf.TypeParameter.Variance = when (variance) {
Variance.INVARIANT -> ProtoBuf.TypeParameter.Variance.INV
Variance.IN_VARIANCE -> ProtoBuf.TypeParameter.Variance.IN
@@ -114,6 +114,10 @@ extend Class {
optional int32 class_module_name = 101 [(string_id_in_table) = true];
repeated Property class_local_variable = 102;
// For anonymous objects from bodies of inline functions copied to the use site, the JVM internal name of the original
// anonymous object this class is copied from
optional int32 anonymous_object_origin_name = 103 [(string_id_in_table) = true];
}
extend Package {
@@ -26,13 +26,13 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Recor
import java.util.*
class JvmNameResolver(
private val types: JvmProtoBuf.StringTableTypes,
private val strings: Array<String>
val types: JvmProtoBuf.StringTableTypes,
val strings: Array<String>
) : NameResolver {
private val localNameIndices = types.localNameList.run { if (isEmpty()) emptySet() else toSet() }
// Here we expand the 'range' field of the Record message for simplicity to a list of records
private val records: List<Record> = ArrayList<Record>().apply {
val records: List<Record> = ArrayList<Record>().apply {
val records = types.recordList
this.ensureCapacity(records.size)
for (record in records) {
@@ -15,6 +15,7 @@ public final class JvmProtoBuf {
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.typeParameterAnnotation);
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.classModuleName);
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.classLocalVariable);
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.anonymousObjectOriginName);
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.packageModuleName);
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.packageLocalVariable);
}
@@ -3919,6 +3920,27 @@ public final class JvmProtoBuf {
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.MESSAGE,
false,
org.jetbrains.kotlin.serialization.ProtoBuf.Property.class);
public static final int ANONYMOUS_OBJECT_ORIGIN_NAME_FIELD_NUMBER = 103;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Class { ... }</code>
*
* <pre>
* For anonymous objects from bodies of inline functions copied to the use site, the JVM internal name of the original
* anonymous object this class is copied from
* </pre>
*/
public static final
org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension<
org.jetbrains.kotlin.serialization.ProtoBuf.Class,
java.lang.Integer> anonymousObjectOriginName = org.jetbrains.kotlin.protobuf.GeneratedMessageLite
.newSingularGeneratedExtension(
org.jetbrains.kotlin.serialization.ProtoBuf.Class.getDefaultInstance(),
0,
null,
null,
103,
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.INT32,
java.lang.Integer.class);
public static final int PACKAGE_MODULE_NAME_FIELD_NUMBER = 101;
/**
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>