Write anonymousObjectOriginName for classes copied during inline
#KT-21320
This commit is contained in:
@@ -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
|
||||
|
||||
+45
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user