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
@@ -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) {