[K/N] Hide throwable constructor frames from stack traces.
Merge-request: KT-MR-8242 Merged-by: Alexey Glushko <aleksei.glushko@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
f20e5daa92
commit
20e80401b2
+9
-7
@@ -734,7 +734,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
private val scope by lazy {
|
||||
if (!context.shouldContainLocationDebugInfo() || declaration == null)
|
||||
return@lazy null
|
||||
declaration.scope() ?: llvmFunction.scope(0, debugInfo.subroutineType(codegen.llvmTargetData, listOf(context.irBuiltIns.intType)))
|
||||
declaration.scope() ?: llvmFunction.scope(0, debugInfo.subroutineType(codegen.llvmTargetData, listOf(context.irBuiltIns.intType)), false)
|
||||
}
|
||||
|
||||
private val fileScope = (fileScope() as? FileScope)
|
||||
@@ -2189,11 +2189,13 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
else -> codegen.llvmFunctionOrNull(this)?.llvmValue
|
||||
}
|
||||
return with(debugInfo) {
|
||||
val f = this@scope
|
||||
val nodebug = f is IrConstructor && f.parentAsClass.isSubclassOf(context.irBuiltIns.throwableClass.owner)
|
||||
if (functionLlvmValue != null) {
|
||||
subprograms.getOrPut(functionLlvmValue) {
|
||||
memScoped {
|
||||
val subroutineType = subroutineType(codegen.llvmTargetData)
|
||||
diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType).also {
|
||||
diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType, nodebug).also {
|
||||
if (!this@scope.isInline)
|
||||
DIFunctionAddSubprogram(functionLlvmValue, it)
|
||||
}
|
||||
@@ -2203,7 +2205,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
inlinedSubprograms.getOrPut(this@scope) {
|
||||
memScoped {
|
||||
val subroutineType = subroutineType(codegen.llvmTargetData)
|
||||
diFunctionScope(name.asString(), "<inlined-out:$name>", startLine, subroutineType)
|
||||
diFunctionScope(name.asString(), "<inlined-out:$name>", startLine, subroutineType, nodebug)
|
||||
}
|
||||
} as DIScopeOpaqueRef
|
||||
}
|
||||
@@ -2212,19 +2214,19 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef): DIScopeOpaqueRef? {
|
||||
private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean): DIScopeOpaqueRef? {
|
||||
return debugInfo.subprograms.getOrPut(this) {
|
||||
diFunctionScope(name!!, name!!, startLine, subroutineType).also {
|
||||
diFunctionScope(name!!, name!!, startLine, subroutineType, nodebug).also {
|
||||
DIFunctionAddSubprogram(this@scope, it)
|
||||
}
|
||||
} as DIScopeOpaqueRef
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef) = DICreateFunction(
|
||||
private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef, nodebug: Boolean) = DICreateFunction(
|
||||
builder = debugInfo.builder,
|
||||
scope = debugInfo.compilationUnit,
|
||||
name = name,
|
||||
name = (if (nodebug) "<NODEBUG>" else "") + name,
|
||||
linkageName = linkageName,
|
||||
file = file().file(),
|
||||
lineNo = startLine,
|
||||
|
||||
@@ -2735,15 +2735,10 @@ task extend_exception(type: KonanLocalTest) {
|
||||
source = "runtime/exceptions/extend0.kt"
|
||||
}
|
||||
|
||||
standaloneTest("check_stacktrace_format") {
|
||||
disabled = !supportsCoreSymbolication(project) || project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g']
|
||||
source = "runtime/exceptions/check_stacktrace_format.kt"
|
||||
}
|
||||
|
||||
standaloneTest("check_stacktrace_format_coresymbolication") {
|
||||
disabled = !supportsCoreSymbolication(project) || project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g', '-Xbinary=sourceInfoType=coresymbolication']
|
||||
arguments = ['coresymbolication']
|
||||
source = "runtime/exceptions/check_stacktrace_format.kt"
|
||||
}
|
||||
|
||||
@@ -2751,9 +2746,7 @@ standaloneTest("stack_trace_inline") {
|
||||
disabled = !supportsCoreSymbolication(project) || project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g', '-Xg-generate-debug-trampoline=enable', '-Xbinary=sourceInfoType=coresymbolication']
|
||||
source = "runtime/exceptions/stack_trace_inline.kt"
|
||||
// test on simulator is writing Invalid connection: com.apple.coresymbolicationd by unknown reason
|
||||
// so we need to use custom checker as workaround
|
||||
outputChecker = { str -> str.split("\n").contains("0") }
|
||||
arguments = ['coresymbolication']
|
||||
}
|
||||
|
||||
standaloneTest("kt-49240-stack-trace-completeness") {
|
||||
@@ -2771,30 +2764,41 @@ standaloneTest("stack_trace_out_of_bounds") {
|
||||
standaloneTest("kt-37572") {
|
||||
disabled = !supportsCoreSymbolication(project) || project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g', '-Xbinary=sourceInfoType=coresymbolication']
|
||||
arguments = ['coresymbolication']
|
||||
source = "runtime/exceptions/kt-37572.kt"
|
||||
// test on simulator is writing Invalid connection: com.apple.coresymbolicationd by unknown reason
|
||||
// so we need to use custom checker as workaround
|
||||
outputChecker = { str -> str.split("\n").contains("0") }
|
||||
}
|
||||
|
||||
standaloneTest("check_stacktrace_format_libbacktrace") {
|
||||
disabled = !supportsLibBacktrace(project)|| project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace']
|
||||
arguments = ['libbacktrace']
|
||||
source = "runtime/exceptions/check_stacktrace_format.kt"
|
||||
}
|
||||
|
||||
standaloneTest("stack_trace_inline_libbacktrace") {
|
||||
disabled = !supportsLibBacktrace(project) || project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace']
|
||||
arguments = ['libbacktrace']
|
||||
source = "runtime/exceptions/stack_trace_inline.kt"
|
||||
outputChecker = { str -> str.split("\n").contains("1") }
|
||||
}
|
||||
|
||||
standaloneTest("kt-37572-libbacktrace") {
|
||||
disabled = !supportsLibBacktrace(project) || project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace']
|
||||
arguments = ['libbacktrace']
|
||||
source = "runtime/exceptions/kt-37572.kt"
|
||||
outputChecker = { str -> str.split("\n").contains("2") }
|
||||
}
|
||||
|
||||
standaloneTest("except_constr_w_default") {
|
||||
disabled = !supportsLibBacktrace(project) || project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace']
|
||||
source = "runtime/exceptions/except_constr_w_default.kt"
|
||||
}
|
||||
|
||||
standaloneTest("throw_from_except_constr") {
|
||||
disabled = !supportsLibBacktrace(project) || project.globalTestArgs.contains('-opt')
|
||||
flags = ['-g', '-Xbinary=sourceInfoType=libbacktrace']
|
||||
source = "runtime/exceptions/throw_from_except_constr.kt"
|
||||
}
|
||||
|
||||
standaloneTest("custom_hook") {
|
||||
|
||||
+7
-9
@@ -3,15 +3,13 @@ import StacktraceByLibbacktrace
|
||||
|
||||
func testStackTrace() throws {
|
||||
let trace = StacktraceByLibbacktraceKt.getStackTrace()
|
||||
try assertTrue(trace[0].contains("Throwable.kt"))
|
||||
try assertTrue(trace[1].contains("Exceptions.kt"))
|
||||
try assertTrue(trace[2].contains("stacktraceByLibbacktrace.kt:7"))
|
||||
try assertTrue(trace[2].contains("[inlined]"))
|
||||
try assertTrue(trace[3].contains("stacktraceByLibbacktrace.kt:11"))
|
||||
try assertTrue(trace[4].contains("stacktraceByLibbacktrace.kt:16"))
|
||||
try assertTrue(trace[5].contains("<compiler-generated>"))
|
||||
try assertTrue(trace[6].contains("stacktraceByLibbacktrace.swift:5"))
|
||||
try assertTrue(trace[7].contains("main.swift:126"))
|
||||
try assertTrue(trace[0].contains("stacktraceByLibbacktrace.kt:7"))
|
||||
try assertTrue(trace[0].contains("[inlined]"))
|
||||
try assertTrue(trace[1].contains("stacktraceByLibbacktrace.kt:11"))
|
||||
try assertTrue(trace[2].contains("stacktraceByLibbacktrace.kt:16"))
|
||||
try assertTrue(trace[3].contains("<compiler-generated>"))
|
||||
try assertTrue(trace[4].contains("stacktraceByLibbacktrace.swift:5"))
|
||||
try assertTrue(trace[5].contains("main.swift:126"))
|
||||
}
|
||||
|
||||
class StacktraceByLibbacktraceTests : TestProvider {
|
||||
|
||||
@@ -29,9 +29,16 @@ fun functionB() {
|
||||
functionA()
|
||||
}
|
||||
|
||||
const val depth = 5
|
||||
var depth = 3
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
val sourceInfoType = args.first()
|
||||
val exceptionalFrames = when (sourceInfoType) {
|
||||
"libbacktrace" -> 0
|
||||
"coresymbolication" -> 2
|
||||
else -> throw AssertionError("Unknown source info type " + sourceInfoType)
|
||||
}
|
||||
depth += exceptionalFrames
|
||||
try {
|
||||
functionB()
|
||||
} catch (e: Throwable) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import kotlin.text.Regex
|
||||
import kotlin.test.*
|
||||
|
||||
class CustomException(msg: String = "Exceptional message") : Exception(msg) {
|
||||
}
|
||||
|
||||
fun exception() {
|
||||
throw CustomException()
|
||||
}
|
||||
|
||||
fun main() {
|
||||
try {
|
||||
exception()
|
||||
}
|
||||
catch (e:Exception) {
|
||||
val stackTrace = e.getStackTrace().filter { "kfun:" in it }
|
||||
println("Kotlin part of call stack is:")
|
||||
for (entry in stackTrace)
|
||||
println(entry)
|
||||
println("Verifying...")
|
||||
val goldValues = arrayOf(
|
||||
"kfun:#exception(){}",
|
||||
"kfun:#main(){}",
|
||||
)
|
||||
assertEquals(goldValues.size, stackTrace.size)
|
||||
goldValues.zip(stackTrace).forEach { checkFrame(it.first, it.second) }
|
||||
println("Passed")
|
||||
}
|
||||
}
|
||||
|
||||
internal val regex = Regex("(kfun.+) \\+ (\\d+)")
|
||||
internal fun checkFrame(goldFunName: String, actualLine: String) {
|
||||
val findResult = regex.find(actualLine)
|
||||
|
||||
val (funName, offset) = findResult?.destructured ?: throw Error("Cannot find '$goldFunName + <int>' in $actualLine")
|
||||
assertEquals(goldFunName, funName)
|
||||
assertTrue(offset.toInt() > 0)
|
||||
}
|
||||
@@ -1,17 +1,28 @@
|
||||
import kotlin.text.Regex
|
||||
import kotlin.test.*
|
||||
|
||||
var inlinesCount = 0
|
||||
var expectedInlinesCount = 0
|
||||
var expectedExceptionContrFrames = 0
|
||||
|
||||
fun main() {
|
||||
fun main(args: Array<String>) {
|
||||
val sourceInfoType = args.first()
|
||||
val (e, i) = when (sourceInfoType) {
|
||||
"libbacktrace" -> Pair(0, 2)
|
||||
"coresymbolication" -> Pair(2, 0)
|
||||
else -> throw AssertionError("Unknown source info type " + sourceInfoType)
|
||||
}
|
||||
expectedExceptionContrFrames = e
|
||||
expectedInlinesCount = i
|
||||
|
||||
var actualInlinesCount = 0
|
||||
try {
|
||||
foo()
|
||||
} catch (tw:Throwable) {
|
||||
val stackTrace = tw.getStackTrace();
|
||||
inlinesCount = stackTrace.count { it.contains("[inlined]")}
|
||||
stackTrace.take(6).forEach(::checkFrame)
|
||||
actualInlinesCount = stackTrace.count { it.contains("[inlined]")}
|
||||
stackTrace.take(expectedExceptionContrFrames + 4).forEach(::checkFrame)
|
||||
}
|
||||
println(inlinesCount)
|
||||
assertEquals(expectedInlinesCount, actualInlinesCount)
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
@@ -32,16 +43,15 @@ internal val regex = Regex("^(\\d+)\\ +.*/(.*):(\\d+):.*$")
|
||||
|
||||
internal fun checkFrame(value:String) {
|
||||
val goldValues = arrayOf<Pair<String, Int>?>(
|
||||
null,
|
||||
null,
|
||||
"kt-37572.kt" to 29,
|
||||
"kt-37572.kt" to 20,
|
||||
*(if (inlinesCount != 0) arrayOf(
|
||||
"kt-37572.kt" to 25,
|
||||
"kt-37572.kt" to 18,
|
||||
*arrayOfNulls(expectedExceptionContrFrames),
|
||||
"kt-37572.kt" to 40,
|
||||
"kt-37572.kt" to 31,
|
||||
*(if (expectedInlinesCount != 0) arrayOf(
|
||||
"kt-37572.kt" to 36,
|
||||
"kt-37572.kt" to 29,
|
||||
) else emptyArray()),
|
||||
"kt-37572.kt" to 8,
|
||||
"kt-37572.kt" to 6)
|
||||
"kt-37572.kt" to 19,
|
||||
"kt-37572.kt" to 7)
|
||||
|
||||
val (pos, file, line) = regex.find(value)!!.destructured
|
||||
goldValues[pos.toInt()]?.let {
|
||||
|
||||
@@ -1,33 +1,41 @@
|
||||
import kotlin.text.Regex
|
||||
import kotlin.test.*
|
||||
|
||||
var inlinesCount = 0
|
||||
var expectedInlinesCount = 0
|
||||
var expectedExceptionContrFrames = 0
|
||||
|
||||
fun exception() {
|
||||
error("FAIL!")
|
||||
}
|
||||
|
||||
fun main() {
|
||||
fun main(args: Array<String>) {
|
||||
val sourceInfoType = args.first()
|
||||
val (e, i) = when (sourceInfoType) {
|
||||
"libbacktrace" -> Pair(0, 1)
|
||||
"coresymbolication" -> Pair(4, 0)
|
||||
else -> throw AssertionError("Unknown source info type " + sourceInfoType)
|
||||
}
|
||||
expectedExceptionContrFrames = e
|
||||
expectedInlinesCount = i
|
||||
|
||||
var actualInlinesCount = 0
|
||||
try {
|
||||
exception()
|
||||
}
|
||||
catch (e:Exception) {
|
||||
val stackTrace = e.getStackTrace()
|
||||
inlinesCount = stackTrace.count { it.contains("[inlined]")}
|
||||
stackTrace.take(6).forEach(::checkFrame)
|
||||
actualInlinesCount = stackTrace.count { it.contains("[inlined]")}
|
||||
stackTrace.take(expectedExceptionContrFrames + 2).forEach(::checkFrame)
|
||||
}
|
||||
println(inlinesCount)
|
||||
assertEquals(expectedInlinesCount, actualInlinesCount)
|
||||
}
|
||||
internal val regex = Regex("^(\\d+)\\ +.*/(.*):(\\d+):.*$")
|
||||
internal fun checkFrame(value:String) {
|
||||
val goldValues = arrayOf<Pair<String, Int>?>(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
*(if (inlinesCount != 0) arrayOf(null) else emptyArray()),
|
||||
"stack_trace_inline.kt" to 7,
|
||||
"stack_trace_inline.kt" to 12)
|
||||
*arrayOfNulls(expectedExceptionContrFrames),
|
||||
*arrayOfNulls(expectedInlinesCount),
|
||||
"stack_trace_inline.kt" to 8,
|
||||
"stack_trace_inline.kt" to 23)
|
||||
val (pos, file, line) = regex.find(value)!!.destructured
|
||||
goldValues[pos.toInt()]?.let {
|
||||
assertEquals(it.first, file)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import kotlin.text.Regex
|
||||
import kotlin.test.*
|
||||
|
||||
class CustomException(msg: String) : Exception(msg) {
|
||||
init {
|
||||
constrException()
|
||||
}
|
||||
|
||||
fun constrException() {
|
||||
throw Exception("Exception during exception's construction")
|
||||
}
|
||||
}
|
||||
|
||||
fun exception() {
|
||||
throw CustomException("Exceptional message")
|
||||
}
|
||||
|
||||
fun main() {
|
||||
try {
|
||||
exception()
|
||||
}
|
||||
catch (e:Exception) {
|
||||
val stackTrace = e.getStackTrace().filter { "kfun:" in it }
|
||||
println("Kotlin part of call stack is:")
|
||||
for (entry in stackTrace)
|
||||
println(entry)
|
||||
println("Verifying...")
|
||||
val goldValues = arrayOf(
|
||||
"kfun:CustomException#constrException(){}",
|
||||
"kfun:#exception(){}",
|
||||
"kfun:#main(){}",
|
||||
)
|
||||
assertEquals(goldValues.size, stackTrace.size)
|
||||
goldValues.zip(stackTrace).forEach { checkFrame(it.first, it.second) }
|
||||
println("Passed")
|
||||
}
|
||||
}
|
||||
|
||||
internal val regex = Regex("(kfun.+) \\+ (\\d+)")
|
||||
internal fun checkFrame(goldFunName: String, actualLine: String) {
|
||||
val findResult = regex.find(actualLine)
|
||||
|
||||
val (funName, offset) = findResult?.destructured ?: throw Error("Cannot find '$goldFunName + <int>' in $actualLine")
|
||||
assertEquals(goldFunName, funName)
|
||||
assertTrue(offset.toInt() > 0)
|
||||
}
|
||||
Reference in New Issue
Block a user