diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidOClassLoadingAdapter.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidOClassLoadingAdapter.kt index a06fae047d9..a056b70806f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidOClassLoadingAdapter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidOClassLoadingAdapter.kt @@ -21,15 +21,11 @@ import com.intellij.debugger.engine.evaluation.EvaluateException import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import com.intellij.debugger.impl.DebuggerUtilsEx import com.sun.jdi.* +import org.jetbrains.kotlin.idea.debugger.isDexDebug class AndroidOClassLoadingAdapter : AbstractAndroidClassLoadingAdapter() { - override fun isApplicable(context: EvaluationContextImpl, classes: Collection): Boolean { - if (classes.size <= 1) { - // Dex takes significant amount of time so we load classes only if we have some non-inline lambdas - return false - } - - return context.classLoader?.isDalvikClassLoader ?: false + override fun isApplicable(context: EvaluationContextImpl, hasAdditionalClasses: Boolean, hasLoops: Boolean): Boolean { + return (hasAdditionalClasses || hasLoops) && context.debugProcess.isDexDebug() } private fun resolveClassLoaderClass(context: EvaluationContextImpl): ClassType? { diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt index f8f2a5d0af2..8c815db5c40 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt @@ -22,6 +22,11 @@ import com.intellij.debugger.impl.DebuggerUtilsEx import com.sun.jdi.ArrayReference import com.sun.jdi.ArrayType import com.sun.jdi.Value +import org.jetbrains.org.objectweb.asm.ClassReader +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.tree.ClassNode +import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode +import org.jetbrains.org.objectweb.asm.tree.LabelNode interface ClassLoadingAdapter { companion object { @@ -29,19 +34,47 @@ interface ClassLoadingAdapter { AndroidOClassLoadingAdapter(), OrdinaryClassLoadingAdapter()) - fun loadClasses(context: EvaluationContextImpl, classes: Collection): ClassLoaderHandler { + fun loadClasses(context: EvaluationContextImpl, classes: Collection): ClassLoaderHandler? { + val hasAdditionalClasses = classes.size > 1 + val hasLoops = classes.isNotEmpty() && doesContainLoops(classes.first().bytes) + for (adapter in ADAPTERS) { - if (adapter.isApplicable(context, classes)) { + if (adapter.isApplicable( + context, + hasAdditionalClasses = hasAdditionalClasses, + hasLoops = hasLoops + )) { return adapter.loadClasses(context, classes) } } - // Should never happen because OrdinaryClassLoadingAdapter is always applicable - throw IllegalStateException("Class loading adapter not found for $context") + return null + } + + private fun doesContainLoops(clazz: ByteArray): Boolean { + val classNode = ClassNode().apply { ClassReader(clazz).accept(this, ClassReader.EXPAND_FRAMES) } + val methodToRun = classNode.methods.single() + + val labelsVisited = hashSetOf