jvm-abi-gen: Support removeDebugInfo option
This option removes debug info, such as: - SourceFile attribute on classes - LocalVariableTable, LineNumberTable, SourceDebugExtension attributes on inline functions - @SourceDebugExtension annotation on inline functions #KT-33020 Fixed
This commit is contained in:
committed by
Space Team
parent
73af0fffa9
commit
fe1e2b8b34
@@ -22,17 +22,28 @@ class JvmAbiCommandLineProcessor : CommandLineProcessor {
|
|||||||
"Output path for generated files. This can be either a directory or a jar file.",
|
"Output path for generated files. This can be either a directory or a jar file.",
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val REMOVE_DEBUG_INFO_OPTION: CliOption =
|
||||||
|
CliOption(
|
||||||
|
"removeDebugInfo",
|
||||||
|
"true/false",
|
||||||
|
"Remove debug info from the generated class files. False by default. Note that if ABI jars are used for incremental " +
|
||||||
|
"compilation, it's not safe to remove debug info because debugger will behave incorrectly on non-recompiled call " +
|
||||||
|
"sites of inline functions.",
|
||||||
|
false,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val pluginId: String
|
override val pluginId: String
|
||||||
get() = COMPILER_PLUGIN_ID
|
get() = COMPILER_PLUGIN_ID
|
||||||
|
|
||||||
override val pluginOptions: Collection<CliOption>
|
override val pluginOptions: Collection<CliOption>
|
||||||
get() = listOf(OUTPUT_PATH_OPTION)
|
get() = listOf(OUTPUT_PATH_OPTION, REMOVE_DEBUG_INFO_OPTION)
|
||||||
|
|
||||||
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
|
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
|
||||||
when (option) {
|
when (option) {
|
||||||
OUTPUT_PATH_OPTION -> configuration.put(JvmAbiConfigurationKeys.OUTPUT_PATH, value)
|
OUTPUT_PATH_OPTION -> configuration.put(JvmAbiConfigurationKeys.OUTPUT_PATH, value)
|
||||||
|
REMOVE_DEBUG_INFO_OPTION -> configuration.put(JvmAbiConfigurationKeys.REMOVE_DEBUG_INFO, value == "true")
|
||||||
else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}")
|
else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ class JvmAbiComponentRegistrar : CompilerPluginRegistrar() {
|
|||||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
|
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
|
||||||
configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
||||||
val builderExtension = JvmAbiClassBuilderInterceptor()
|
val builderExtension = JvmAbiClassBuilderInterceptor()
|
||||||
val outputExtension = JvmAbiOutputExtension(File(outputPath), builderExtension.abiClassInfo, messageCollector)
|
val outputExtension = JvmAbiOutputExtension(
|
||||||
|
File(outputPath), builderExtension.abiClassInfo, messageCollector,
|
||||||
|
configuration.getBoolean(JvmAbiConfigurationKeys.REMOVE_DEBUG_INFO),
|
||||||
|
)
|
||||||
ClassGeneratorExtension.registerExtension(builderExtension)
|
ClassGeneratorExtension.registerExtension(builderExtension)
|
||||||
ClassFileFactoryFinalizerExtension.registerExtension(outputExtension)
|
ClassFileFactoryFinalizerExtension.registerExtension(outputExtension)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
|||||||
object JvmAbiConfigurationKeys {
|
object JvmAbiConfigurationKeys {
|
||||||
val OUTPUT_PATH: CompilerConfigurationKey<String> =
|
val OUTPUT_PATH: CompilerConfigurationKey<String> =
|
||||||
CompilerConfigurationKey.create(JvmAbiCommandLineProcessor.OUTPUT_PATH_OPTION.description)
|
CompilerConfigurationKey.create(JvmAbiCommandLineProcessor.OUTPUT_PATH_OPTION.description)
|
||||||
|
val REMOVE_DEBUG_INFO: CompilerConfigurationKey<Boolean> =
|
||||||
|
CompilerConfigurationKey.create(JvmAbiCommandLineProcessor.REMOVE_DEBUG_INFO_OPTION.description)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,12 @@ class JvmAbiOutputExtension(
|
|||||||
private val outputPath: File,
|
private val outputPath: File,
|
||||||
private val abiClassInfos: Map<String, AbiClassInfo>,
|
private val abiClassInfos: Map<String, AbiClassInfo>,
|
||||||
private val messageCollector: MessageCollector,
|
private val messageCollector: MessageCollector,
|
||||||
|
private val removeDebugInfo: Boolean,
|
||||||
) : ClassFileFactoryFinalizerExtension {
|
) : ClassFileFactoryFinalizerExtension {
|
||||||
override fun finalizeClassFactory(factory: ClassFileFactory) {
|
override fun finalizeClassFactory(factory: ClassFileFactory) {
|
||||||
// We need to wait until the end to produce any output in order to strip classes
|
// We need to wait until the end to produce any output in order to strip classes
|
||||||
// from the InnerClasses attributes.
|
// from the InnerClasses attributes.
|
||||||
val outputFiles = AbiOutputFiles(abiClassInfos, factory)
|
val outputFiles = AbiOutputFiles(abiClassInfos, factory, removeDebugInfo)
|
||||||
if (outputPath.extension == "jar") {
|
if (outputPath.extension == "jar") {
|
||||||
// We don't include the runtime or main class in interface jars and always reset time stamps.
|
// We don't include the runtime or main class in interface jars and always reset time stamps.
|
||||||
CompileEnvironmentUtil.writeToJar(
|
CompileEnvironmentUtil.writeToJar(
|
||||||
@@ -47,8 +48,11 @@ class JvmAbiOutputExtension(
|
|||||||
|
|
||||||
private class InnerClassInfo(val name: String, val outerName: String?, val innerName: String?, val access: Int)
|
private class InnerClassInfo(val name: String, val outerName: String?, val innerName: String?, val access: Int)
|
||||||
|
|
||||||
private class AbiOutputFiles(val abiClassInfos: Map<String, AbiClassInfo>, val outputFiles: OutputFileCollection) :
|
private class AbiOutputFiles(
|
||||||
OutputFileCollection {
|
val abiClassInfos: Map<String, AbiClassInfo>,
|
||||||
|
val outputFiles: OutputFileCollection,
|
||||||
|
val removeDebugInfo: Boolean,
|
||||||
|
) : OutputFileCollection {
|
||||||
override fun get(relativePath: String): OutputFile? {
|
override fun get(relativePath: String): OutputFile? {
|
||||||
error("AbiOutputFiles does not implement `get`.")
|
error("AbiOutputFiles does not implement `get`.")
|
||||||
}
|
}
|
||||||
@@ -104,9 +108,23 @@ class JvmAbiOutputExtension(
|
|||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
val visitor = super.visitMethod(access, name, descriptor, signature, exceptions)
|
val visitor = super.visitMethod(access, name, descriptor, signature, exceptions)
|
||||||
|
if (info == AbiMethodInfo.KEEP || access and (Opcodes.ACC_NATIVE or Opcodes.ACC_ABSTRACT) != 0) {
|
||||||
|
return object : MethodVisitor(Opcodes.API_VERSION, visitor) {
|
||||||
|
override fun visitLineNumber(line: Int, start: Label?) {
|
||||||
|
if (!removeDebugInfo) {
|
||||||
|
super.visitLineNumber(line, start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (info == AbiMethodInfo.KEEP || access and (Opcodes.ACC_NATIVE or Opcodes.ACC_ABSTRACT) != 0)
|
override fun visitLocalVariable(
|
||||||
return visitor
|
name: String?, descriptor: String?, signature: String?, start: Label?, end: Label?, index: Int,
|
||||||
|
) {
|
||||||
|
if (!removeDebugInfo) {
|
||||||
|
super.visitLocalVariable(name, descriptor, signature, start, end, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return object : MethodVisitor(Opcodes.API_VERSION, visitor) {
|
return object : MethodVisitor(Opcodes.API_VERSION, visitor) {
|
||||||
override fun visitCode() {
|
override fun visitCode() {
|
||||||
@@ -123,13 +141,15 @@ class JvmAbiOutputExtension(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip source debug extensions if there are no inline functions.
|
|
||||||
override fun visitSource(source: String?, debug: String?) {
|
override fun visitSource(source: String?, debug: String?) {
|
||||||
// TODO Normalize and strip unused line numbers from SourceDebugExtensions
|
when {
|
||||||
if (methodInfo.values.any { it == AbiMethodInfo.KEEP })
|
removeDebugInfo -> super.visitSource(null, null)
|
||||||
super.visitSource(source, debug)
|
methodInfo.values.none { it == AbiMethodInfo.KEEP } -> {
|
||||||
else
|
// Strip SourceDebugExtension attribute if there are no inline functions.
|
||||||
super.visitSource(source, null)
|
super.visitSource(source, null)
|
||||||
|
}
|
||||||
|
else -> super.visitSource(source, debug)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove inner classes which are not present in the abi jar.
|
// Remove inner classes which are not present in the abi jar.
|
||||||
@@ -139,11 +159,15 @@ class JvmAbiOutputExtension(
|
|||||||
innerClassInfos[name] = InnerClassInfo(name, outerName, innerName, access)
|
innerClassInfos[name] = InnerClassInfo(name, outerName, innerName, access)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip private declarations from the Kotlin Metadata annotation.
|
override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? {
|
||||||
override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor {
|
// Strip @SourceDebugExtension annotation if we're removing debug info.
|
||||||
|
if (removeDebugInfo && descriptor == JvmAnnotationNames.SOURCE_DEBUG_EXTENSION_DESC)
|
||||||
|
return null
|
||||||
|
|
||||||
val delegate = super.visitAnnotation(descriptor, visible)
|
val delegate = super.visitAnnotation(descriptor, visible)
|
||||||
if (descriptor != JvmAnnotationNames.METADATA_DESC)
|
if (descriptor != JvmAnnotationNames.METADATA_DESC)
|
||||||
return delegate
|
return delegate
|
||||||
|
// Strip private declarations from the Kotlin Metadata annotation.
|
||||||
return abiMetadataProcessor(delegate)
|
return abiMetadataProcessor(delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,9 +75,12 @@ abstract class BaseJvmAbiTest : TestCase() {
|
|||||||
freeArgs = listOf(compilation.srcDir.canonicalPath)
|
freeArgs = listOf(compilation.srcDir.canonicalPath)
|
||||||
classpath = (abiDependencies + kotlinJvmStdlib).joinToString(File.pathSeparator) { it.canonicalPath }
|
classpath = (abiDependencies + kotlinJvmStdlib).joinToString(File.pathSeparator) { it.canonicalPath }
|
||||||
pluginClasspaths = arrayOf(abiPluginJar.canonicalPath)
|
pluginClasspaths = arrayOf(abiPluginJar.canonicalPath)
|
||||||
pluginOptions = arrayOf(
|
pluginOptions = listOfNotNull(
|
||||||
abiOption(JvmAbiCommandLineProcessor.OUTPUT_PATH_OPTION.optionName, compilation.abiDir.canonicalPath),
|
abiOption(JvmAbiCommandLineProcessor.OUTPUT_PATH_OPTION.optionName, compilation.abiDir.canonicalPath),
|
||||||
)
|
abiOption(JvmAbiCommandLineProcessor.REMOVE_DEBUG_INFO_OPTION.optionName, true.toString()).takeIf {
|
||||||
|
InTextDirectivesUtils.findStringWithPrefixes(directives, "// REMOVE_DEBUG_INFO") != null
|
||||||
|
}
|
||||||
|
).toTypedArray()
|
||||||
destination = compilation.destinationDir.canonicalPath
|
destination = compilation.destinationDir.canonicalPath
|
||||||
noSourceDebugExtension = InTextDirectivesUtils.findStringWithPrefixes(directives, "// NO_SOURCE_DEBUG_EXTENSION") != null
|
noSourceDebugExtension = InTextDirectivesUtils.findStringWithPrefixes(directives, "// NO_SOURCE_DEBUG_EXTENSION") != null
|
||||||
|
|
||||||
|
|||||||
+25
@@ -55,6 +55,26 @@ public class CompareJvmAbiTestGenerated extends AbstractCompareJvmAbiTest {
|
|||||||
runTest("plugins/jvm-abi-gen/testData/compare/constant/");
|
runTest("plugins/jvm-abi-gen/testData/compare/constant/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("debugInfoLineNumberTable")
|
||||||
|
public void testDebugInfoLineNumberTable() throws Exception {
|
||||||
|
runTest("plugins/jvm-abi-gen/testData/compare/debugInfoLineNumberTable/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("debugInfoLocalVariableTable")
|
||||||
|
public void testDebugInfoLocalVariableTable() throws Exception {
|
||||||
|
runTest("plugins/jvm-abi-gen/testData/compare/debugInfoLocalVariableTable/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("debugInfoSourceDebugExtension")
|
||||||
|
public void testDebugInfoSourceDebugExtension() throws Exception {
|
||||||
|
runTest("plugins/jvm-abi-gen/testData/compare/debugInfoSourceDebugExtension/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("debugInfoSourceFile")
|
||||||
|
public void testDebugInfoSourceFile() throws Exception {
|
||||||
|
runTest("plugins/jvm-abi-gen/testData/compare/debugInfoSourceFile/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("declarationOrderInline")
|
@TestMetadata("declarationOrderInline")
|
||||||
public void testDeclarationOrderInline() throws Exception {
|
public void testDeclarationOrderInline() throws Exception {
|
||||||
runTest("plugins/jvm-abi-gen/testData/compare/declarationOrderInline/");
|
runTest("plugins/jvm-abi-gen/testData/compare/declarationOrderInline/");
|
||||||
@@ -105,6 +125,11 @@ public class CompareJvmAbiTestGenerated extends AbstractCompareJvmAbiTest {
|
|||||||
runTest("plugins/jvm-abi-gen/testData/compare/privateTypealias/");
|
runTest("plugins/jvm-abi-gen/testData/compare/privateTypealias/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("removeDebugInfo")
|
||||||
|
public void testRemoveDebugInfo() throws Exception {
|
||||||
|
runTest("plugins/jvm-abi-gen/testData/compare/removeDebugInfo/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("returnType")
|
@TestMetadata("returnType")
|
||||||
public void testReturnType() throws Exception {
|
public void testReturnType() throws Exception {
|
||||||
runTest("plugins/jvm-abi-gen/testData/compare/returnType/");
|
runTest("plugins/jvm-abi-gen/testData/compare/returnType/");
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun sum(x: Int, y: Int): Int {
|
||||||
|
// Comment before local variable
|
||||||
|
val result = x + y
|
||||||
|
return result
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun sum(x: Int, y: Int): Int {
|
||||||
|
val result = x + y
|
||||||
|
// Comment after local variable
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun sum(x: Int, y: Int): Int {
|
||||||
|
val result = x + y
|
||||||
|
return result
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun sum(x: Int, y: Int): Int {
|
||||||
|
val resultResult = x + y
|
||||||
|
return resultResult
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
fun <T> forEach0(list: List<T>, block: (T) -> Unit) {
|
||||||
|
// Comment before the function
|
||||||
|
list.forEach(block)
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
fun <T> forEach0(list: List<T>, block: (T) -> Unit) {
|
||||||
|
list.forEach(block)
|
||||||
|
// Comment after the function
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class C
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class C
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun <T> forEach0(list: List<T>, block: (T) -> Unit): List<T> {
|
||||||
|
val list1 = list
|
||||||
|
list1.forEach(block)
|
||||||
|
return list1
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class C
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// REMOVE_DEBUG_INFO
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun <T> forEach0(list: List<T>, block: (T) -> Unit): List<T> {
|
||||||
|
val list2 = list
|
||||||
|
|
||||||
|
list2.forEach(block)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return list2
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class C
|
||||||
Reference in New Issue
Block a user