Move additional stack filling in ExceptionState class

This commit is contained in:
Ivan Kylchik
2020-03-27 15:31:49 +03:00
parent 900e78b39b
commit ad7055b8a0
2 changed files with 32 additions and 29 deletions
@@ -123,7 +123,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
else -> TODO("${this.javaClass} not supported")
}
return when (code) {
return when (code) { // TODO move to label class
Code.RETURN -> when (this) {
is IrCall -> if (code.info == this.symbol.descriptor.toString()) Code.NEXT else code
is IrReturnableBlock -> if (code.info == this.symbol.descriptor.toString()) Code.NEXT else code
@@ -150,36 +150,12 @@ class IrInterpreter(irModule: IrModuleFragment) {
val exceptionName = e::class.java.simpleName
val irExceptionClass = irExceptions.firstOrNull { it.name.asString() == exceptionName } ?: irBuiltIns.throwableClass.owner
// TODO do we really need this?... It will point to JVM stdlib
val additionalStack = mutableListOf<String>()
if (e.stackTrace.any { it.className == "java.lang.invoke.MethodHandle" }) {
for ((index, stackTraceElement) in e.stackTrace.withIndex()) {
if (stackTraceElement.methodName == "invokeWithArguments") {
additionalStack.addAll(e.stackTrace.slice(0 until index).reversed().map { "at $it" })
break
}
}
var cause = e.cause
val lastNeededValue = e.stackTrace.first().className + "." + e.stackTrace.first().methodName
while (cause != null) {
for ((causeStackIndex, causeStackTraceElement) in cause.stackTrace.withIndex()) {
val currentStackTraceValue = causeStackTraceElement.className + "." + causeStackTraceElement.methodName
if (currentStackTraceValue == lastNeededValue) {
cause.stackTrace = cause.stackTrace.sliceArray(0 until causeStackIndex).reversedArray()
break
}
}
cause = cause.cause
}
}
val exceptionState = when {
// this block is used to replace jvm null pointer exception with common one
// TODO figure something better
irExceptionClass == irBuiltIns.throwableClass.owner && exceptionName == "KotlinNullPointerException" ->
ExceptionState(e, irExceptions.first { it.name.asString() == "NullPointerException" }, stackTrace + additionalStack)
else -> ExceptionState(e, irExceptionClass, stackTrace + additionalStack)
ExceptionState(e, irExceptions.first { it.name.asString() == "NullPointerException" }, stackTrace)
else -> ExceptionState(e, irExceptionClass, stackTrace)
}
data.pushReturnValue(exceptionState)
@@ -322,7 +322,7 @@ class ExceptionState private constructor(
init {
instance = this
this.stackTrace = stackTrace.reversed()
if (!this::exceptionFqName.isInitialized) this.exceptionFqName = irClass.fqNameForIrSerialization.asString()
if (!this::exceptionFqName.isInitialized) this.exceptionFqName = irClassFqName()
if (fields.none { it.descriptor.equalTo(messageProperty.descriptor) }) {
setMessage()
@@ -341,7 +341,7 @@ class ExceptionState private constructor(
constructor(
exception: Throwable, irClass: IrClass, stackTrace: List<String>
) : this(irClass, evaluateFields(exception, irClass, stackTrace), stackTrace) {
) : this(irClass, evaluateFields(exception, irClass, stackTrace), stackTrace + evaluateAdditionalStackTrace(exception)) {
if (irClass.name.asString() != exception::class.java.simpleName) {
// ir class wasn't found in classpath, a stub was passed => need to save java class hierarchy
this.exceptionFqName = exception::class.java.name
@@ -414,6 +414,33 @@ class ExceptionState private constructor(
}
return listOfNotNull(messageVar, causeVar).toMutableList()
}
private fun evaluateAdditionalStackTrace(e: Throwable): List<String> {
// TODO do we really need this?... It will point to JVM stdlib
val additionalStack = mutableListOf<String>()
if (e.stackTrace.any { it.className == "java.lang.invoke.MethodHandle" }) {
for ((index, stackTraceElement) in e.stackTrace.withIndex()) {
if (stackTraceElement.methodName == "invokeWithArguments") {
additionalStack.addAll(e.stackTrace.slice(0 until index).reversed().map { "at $it" })
break
}
}
var cause = e.cause
val lastNeededValue = e.stackTrace.first().let { it.className + "." + it.methodName }
while (cause != null) {
for ((causeStackIndex, causeStackTraceElement) in cause.stackTrace.withIndex()) {
val currentStackTraceValue = causeStackTraceElement.let { it.className + "." + it.methodName }
if (currentStackTraceValue == lastNeededValue) {
cause.stackTrace = cause.stackTrace.sliceArray(0 until causeStackIndex).reversedArray()
break
}
}
cause = cause.cause
}
}
return additionalStack
}
}
}