Write a copy of SMAP to a new annotation

To make it available for dynamically attached JVMTI agents.

`@SourceDebugExtension` annotation value is equal to the
SourceDebugExtension attribute value, which is checked now for all box
tests. The difference is that the annotation stored in the constant
pool, which is available for dynamically attached JVMTI agents.

 #KT-53438 Fixed
This commit is contained in:
Alexander Udalov
2022-07-13 14:10:08 +02:00
parent 1e6f7f6d58
commit 87d3ce6ded
7 changed files with 109 additions and 13 deletions
@@ -10,8 +10,10 @@ import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.kotlin.codegen.inline.RangeMapping
import org.jetbrains.kotlin.codegen.inline.SMAPParser
import org.jetbrains.kotlin.codegen.inline.toRange
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.test.Assertions
import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -21,16 +23,55 @@ object CommonSMAPTestUtil {
fun extractSMAPFromClasses(outputFiles: Iterable<OutputFile>): List<SMAPAndFile> {
return outputFiles.map { outputFile ->
var debugInfo: String? = null
var sdeAnnotationValue: String? = null
ClassReader(outputFile.asByteArray()).accept(object : ClassVisitor(Opcodes.API_VERSION) {
override fun visitSource(source: String?, debug: String?) {
debugInfo = debug
}
override fun visitAnnotation(descriptor: String, visible: Boolean): AnnotationVisitor? {
if (descriptor != JvmAnnotationNames.SOURCE_DEBUG_EXTENSION_DESC) return super.visitAnnotation(descriptor, visible)
return object : AnnotationVisitor(Opcodes.API_VERSION) {
override fun visitArray(name: String): AnnotationVisitor? {
if (name != "value") return super.visitArray(name)
check(sdeAnnotationValue == null) { outputFile.relativePath }
return object : AnnotationVisitor(Opcodes.API_VERSION) {
val result = mutableListOf<String>()
override fun visit(name: String?, value: Any?) {
result.add(value as String)
}
override fun visitEnd() {
sdeAnnotationValue = result.joinToString("")
}
}
}
}
}
}, 0)
checkSmapVsAnnotation(outputFile.relativePath, debugInfo, sdeAnnotationValue)
SMAPAndFile(debugInfo, outputFile.sourceFiles.single(), outputFile.relativePath)
}
}
private fun checkSmapVsAnnotation(relativePath: String, debugInfo: String?, sdeAnnotationValue: String?) {
if (debugInfo == sdeAnnotationValue) return
if (debugInfo == null) {
error("@SourceDebugExtension is incorrectly generated for a class without SMAP: $relativePath")
}
if (sdeAnnotationValue == null) {
error("Missing @SourceDebugExtension annotation for a class with SMAP: $relativePath")
}
error(
"SMAP and @SourceDebugExtension value differs for $relativePath.\n" +
"SMAP:\n===\n$debugInfo\n===\n@SourceDebugExtension:\n===\n$sdeAnnotationValue\n"
)
}
fun checkNoConflictMappings(compiledSmap: List<SMAPAndFile>?, assertions: Assertions) {
if (compiledSmap == null) return