Use compiling evaluator only if there is non-inline lambda or a loop in the bytecode
This commit is contained in:
+3
-7
@@ -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<ClassToLoad>): 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? {
|
||||
|
||||
+38
-5
@@ -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<ClassToLoad>): ClassLoaderHandler {
|
||||
fun loadClasses(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): 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<Label>()
|
||||
var currentInsn = methodToRun.instructions.first
|
||||
while (currentInsn != null) {
|
||||
if (currentInsn is LabelNode) {
|
||||
labelsVisited += currentInsn.label
|
||||
}
|
||||
else if (currentInsn is JumpInsnNode) {
|
||||
if (currentInsn.label.label in labelsVisited) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
currentInsn = currentInsn.next
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun isApplicable(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): Boolean
|
||||
fun isApplicable(context: EvaluationContextImpl, hasAdditionalClasses: Boolean, hasLoops: Boolean): Boolean
|
||||
|
||||
fun loadClasses(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): ClassLoaderHandler
|
||||
|
||||
|
||||
+3
-3
@@ -26,6 +26,7 @@ import com.intellij.openapi.util.SystemInfo
|
||||
import com.sun.jdi.ClassLoaderReference
|
||||
import com.sun.jdi.ClassType
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.CompilingEvaluatorUtils
|
||||
import org.jetbrains.kotlin.idea.debugger.isDexDebug
|
||||
|
||||
class OrdinaryClassLoadingAdapter : ClassLoadingAdapter {
|
||||
private companion object {
|
||||
@@ -36,9 +37,8 @@ class OrdinaryClassLoadingAdapter : ClassLoadingAdapter {
|
||||
private val LAMBDA_SUPERCLASSES = listOf(ClassBytes("kotlin.jvm.internal.Lambda"))
|
||||
}
|
||||
|
||||
override fun isApplicable(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): Boolean {
|
||||
val classLoader = context.classLoader
|
||||
return classLoader != null && !classLoader.isDalvikClassLoader
|
||||
override fun isApplicable(context: EvaluationContextImpl, hasAdditionalClasses: Boolean, hasLoops: Boolean): Boolean {
|
||||
return (hasAdditionalClasses || hasLoops) && context.classLoader != null && !context.debugProcess.isDexDebug()
|
||||
}
|
||||
|
||||
override fun loadClasses(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): ClassLoaderHandler {
|
||||
|
||||
Reference in New Issue
Block a user