[COROUTINE] NPE exception fix if no DebugMetadata in target jvm exists
This commit is contained in:
+31
-15
@@ -27,9 +27,6 @@ class AsyncStackTraceContext(
|
|||||||
val method: Method
|
val method: Method
|
||||||
) {
|
) {
|
||||||
val log by logger
|
val log by logger
|
||||||
val debugMetadataKtType = context.findClassSafe(
|
|
||||||
DEBUG_METADATA_KT
|
|
||||||
)!!
|
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val DEBUG_METADATA_KT = "kotlin.coroutines.jvm.internal.DebugMetadataKt"
|
const val DEBUG_METADATA_KT = "kotlin.coroutines.jvm.internal.DebugMetadataKt"
|
||||||
@@ -76,20 +73,33 @@ class AsyncStackTraceContext(
|
|||||||
val continuationType = continuation.referenceType() as? ClassType ?: return
|
val continuationType = continuation.referenceType() as? ClassType ?: return
|
||||||
val baseContinuationSupertype = findBaseContinuationSuperSupertype(continuationType) ?: return
|
val baseContinuationSupertype = findBaseContinuationSuperSupertype(continuationType) ?: return
|
||||||
|
|
||||||
val location = createLocation(continuation)
|
val debugMetadataKtType = debugMetadataKtType()
|
||||||
|
if (debugMetadataKtType is ClassType) {
|
||||||
|
val location = createLocation(continuation, debugMetadataKtType)
|
||||||
|
|
||||||
location?.let {
|
location?.let {
|
||||||
val spilledVariables = getSpilledVariables(continuation) ?: emptyList()
|
val spilledVariables = getSpilledVariables(continuation, debugMetadataKtType) ?: emptyList()
|
||||||
consumer.add(DefaultCoroutineStackFrameItem(location, spilledVariables))
|
consumer.add(DefaultCoroutineStackFrameItem(location, spilledVariables))
|
||||||
|
}
|
||||||
|
|
||||||
|
val completionField = baseContinuationSupertype.fieldByName("completion") ?: return
|
||||||
|
val completion = continuation.getValue(completionField) as? ObjectReference ?: return
|
||||||
|
collectFramesRecursively(completion, consumer)
|
||||||
}
|
}
|
||||||
|
|
||||||
val completionField = baseContinuationSupertype.fieldByName("completion") ?: return
|
|
||||||
val completion = continuation.getValue(completionField) as? ObjectReference ?: return
|
|
||||||
collectFramesRecursively(completion, consumer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createLocation(continuation: ObjectReference): GeneratedLocation? {
|
fun debugMetadataKtType(): ClassType? {
|
||||||
val instance = invokeGetStackTraceElement(continuation) ?: return null
|
val debugMetadataKtType = context.findClassSafe(DEBUG_METADATA_KT)
|
||||||
|
if (debugMetadataKtType != null) {
|
||||||
|
return debugMetadataKtType
|
||||||
|
} else {
|
||||||
|
log.warn("Continuation information found but no $DEBUG_METADATA_KT class exists. Please check kotlin-stdlib version.")
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createLocation(continuation: ObjectReference, debugMetadataKtType: ClassType): GeneratedLocation? {
|
||||||
|
val instance = invokeGetStackTraceElement(continuation, debugMetadataKtType) ?: return null
|
||||||
val className = context.invokeMethodAsString(instance, "getClassName") ?: return null
|
val className = context.invokeMethodAsString(instance, "getClassName") ?: return null
|
||||||
val methodName = context.invokeMethodAsString(instance, "getMethodName") ?: return null
|
val methodName = context.invokeMethodAsString(instance, "getMethodName") ?: return null
|
||||||
val lineNumber = context.invokeMethodAsInt(instance, "getLineNumber")?.takeIf {
|
val lineNumber = context.invokeMethodAsInt(instance, "getLineNumber")?.takeIf {
|
||||||
@@ -99,10 +109,10 @@ class AsyncStackTraceContext(
|
|||||||
return GeneratedLocation(context.debugProcess, locationClass, methodName, lineNumber)
|
return GeneratedLocation(context.debugProcess, locationClass, methodName, lineNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invokeGetStackTraceElement(continuation: ObjectReference): ObjectReference? {
|
private fun invokeGetStackTraceElement(continuation: ObjectReference, debugMetadataKtType: ClassType): ObjectReference? {
|
||||||
val stackTraceElement =
|
val stackTraceElement =
|
||||||
context.invokeMethodAsObject(debugMetadataKtType, "getStackTraceElement", continuation) ?: return null
|
context.invokeMethodAsObject(debugMetadataKtType, "getStackTraceElement", continuation) ?: return null
|
||||||
// redundant i believe
|
|
||||||
stackTraceElement.referenceType().takeIf { it.name() == StackTraceElement::class.java.name } ?: return null
|
stackTraceElement.referenceType().takeIf { it.name() == StackTraceElement::class.java.name } ?: return null
|
||||||
|
|
||||||
context.keepReference(stackTraceElement)
|
context.keepReference(stackTraceElement)
|
||||||
@@ -110,7 +120,13 @@ class AsyncStackTraceContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getSpilledVariables(continuation: ObjectReference): List<XNamedValue>? {
|
fun getSpilledVariables(continuation: ObjectReference): List<XNamedValue>? {
|
||||||
|
debugMetadataKtType()?.let {
|
||||||
|
return getSpilledVariables(continuation, it)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSpilledVariables(continuation: ObjectReference, debugMetadataKtType: ClassType): List<XNamedValue>? {
|
||||||
val rawSpilledVariables =
|
val rawSpilledVariables =
|
||||||
context.invokeMethodAsArray(
|
context.invokeMethodAsArray(
|
||||||
debugMetadataKtType,
|
debugMetadataKtType,
|
||||||
|
|||||||
Reference in New Issue
Block a user