diff --git a/idea/jvm-debugger/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt b/idea/jvm-debugger/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt index 3721f5fe19b..b17f3e559da 100644 --- a/idea/jvm-debugger/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt +++ b/idea/jvm-debugger/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt @@ -31,10 +31,10 @@ private val CLASS = Type.getType(Class::class.java) private val OBJECT = Type.getType(Any::class.java) private val BOOTSTRAP_CLASS_DESCRIPTORS = setOf("Ljava/lang/String;", "Ljava/lang/ClassLoader;", "Ljava/lang/Class;") -class JDIEval( +open class JDIEval( private val vm: VirtualMachine, private val defaultClassLoader: ClassLoaderReference?, - private val thread: ThreadReference, + protected val thread: ThreadReference, private val invokePolicy: Int ) : Eval { @@ -268,6 +268,14 @@ class JDIEval( return null } + open fun jdiInvokeStaticMethod(type: ClassType, method: Method, args: List, invokePolicy: Int): jdi_Value? { + return type.invokeMethod(thread, method, args, invokePolicy) + } + + open fun jdiInvokeStaticMethod(type: InterfaceType, method: Method, args: List, invokePolicy: Int): jdi_Value? { + return type.invokeMethod(thread, method, args, invokePolicy) + } + override fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List): Value { val method = findMethod(methodDesc) if (!method.isStatic) { @@ -284,14 +292,14 @@ class JDIEval( val result = mayThrow { when (declaringType) { - is ClassType -> declaringType.invokeMethod(thread, method, args, invokePolicy) + is ClassType -> jdiInvokeStaticMethod(declaringType, method, args, invokePolicy) is InterfaceType -> { if (!isJava8OrLater) { val message = "Calling interface static methods is not supported in JVM ${vm.version()} ($method)" throwBrokenCodeException(NoSuchMethodError(message)) } - declaringType.invokeMethod(thread, method, args, invokePolicy) + jdiInvokeStaticMethod(declaringType, method, args, invokePolicy) } else -> { val message = "Calling static methods is only supported for classes and interfaces ($method)" @@ -344,6 +352,10 @@ class JDIEval( return invokeMethod(boxedValue, method, listOf(), true) } + open fun jdiInvokeMethod(obj: ObjectReference, method: Method, args: List, policy: Int): jdi_Value? { + return obj.invokeMethod(thread, method, args, policy) + } + override fun invokeMethod(instance: Value, methodDesc: MethodDescription, arguments: List, invokespecial: Boolean): Value { if (invokespecial && methodDesc.name == "") { // Constructor call @@ -365,7 +377,7 @@ class JDIEval( } args.disableCollection() - val result = mayThrow { obj.invokeMethod(thread, method, args, policy) }.ifFail(method, obj) + val result = mayThrow { jdiInvokeMethod(obj, method, args, policy) }.ifFail(method, obj) args.enableCollection() return result.asValue() } diff --git a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt index cfc9f46960c..5696fe082a7 100644 --- a/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt +++ b/idea/jvm-debugger/jvm-debugger-evaluation/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluatorBuilder.kt @@ -330,7 +330,19 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi val thread = context.suspendContext.thread?.threadReference?.takeIf { it.isSuspended } ?: error("Can not find a thread to run evaluation on") - val eval = JDIEval(vm, classLoader, thread, context.invokePolicy) + val eval = object : JDIEval(vm, classLoader, thread, context.invokePolicy) { + override fun jdiInvokeStaticMethod(type: ClassType, method: Method, args: List, invokePolicy: Int): Value? { + return context.invokeMethod(type, method, args) + } + + override fun jdiInvokeStaticMethod(type: InterfaceType, method: Method, args: List, invokePolicy: Int): Value? { + return context.invokeMethod(type, method, args) + } + + override fun jdiInvokeMethod(obj: ObjectReference, method: Method, args: List, policy: Int): Value? { + return context.invokeMethod(obj, method, args, ObjectReference.INVOKE_NONVIRTUAL) + } + } interpreterLoop(mainMethod, makeInitialFrame(mainMethod, args.map { it.asValue() }), eval) } } @@ -347,22 +359,20 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi .filter { !it.isMainClass } .forEach { context.findClass(it.className, classLoader) } - return context.vm.virtualMachine.executeWithBreakpointsDisabled { - for (parameterType in compiledData.mainMethodSignature.parameterTypes) { - context.findClass(parameterType, classLoader) - } - - val variableFinder = VariableFinder(context) - val args = calculateMainMethodCallArguments(variableFinder, compiledData, status) - - val result = block(args) - - for (wrapper in variableFinder.refWrappers) { - updateLocalVariableValue(variableFinder.evaluatorValueConverter, wrapper) - } - - return@executeWithBreakpointsDisabled result + for (parameterType in compiledData.mainMethodSignature.parameterTypes) { + context.findClass(parameterType, classLoader) } + + val variableFinder = VariableFinder(context) + val args = calculateMainMethodCallArguments(variableFinder, compiledData, status) + + val result = block(args) + + for (wrapper in variableFinder.refWrappers) { + updateLocalVariableValue(variableFinder.evaluatorValueConverter, wrapper) + } + + return result } private fun updateLocalVariableValue(converter: EvaluatorValueConverter, ref: VariableFinder.RefWrapper) { @@ -465,17 +475,6 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi } } -private fun VirtualMachine.executeWithBreakpointsDisabled(block: () -> T): T { - val allRequests = eventRequestManager().breakpointRequests() + eventRequestManager().classPrepareRequests() - - try { - allRequests.forEach { it.disable() } - return block() - } finally { - allRequests.forEach { it.enable() } - } -} - private fun isSpecialException(th: Throwable): Boolean { return when (th) { is ClassNotPreparedException, diff --git a/idea/jvm-debugger/jvm-debugger-util/src/org/jetbrains/kotlin/idea/debugger/evaluate/ExecutionContext.kt b/idea/jvm-debugger/jvm-debugger-util/src/org/jetbrains/kotlin/idea/debugger/evaluate/ExecutionContext.kt index 9ce6d26d21c..98a66fa6ef5 100644 --- a/idea/jvm-debugger/jvm-debugger-util/src/org/jetbrains/kotlin/idea/debugger/evaluate/ExecutionContext.kt +++ b/idea/jvm-debugger/jvm-debugger-util/src/org/jetbrains/kotlin/idea/debugger/evaluate/ExecutionContext.kt @@ -40,14 +40,18 @@ class ExecutionContext(val evaluationContext: EvaluationContextImpl, val framePr } @Throws(EvaluateException::class) - fun invokeMethod(obj: ObjectReference, method: Method, args: List): Value? { - return debugProcess.invokeInstanceMethod(evaluationContext, obj, method, args, invokePolicy) + fun invokeMethod(obj: ObjectReference, method: Method, args: List, invocationOptions: Int = 0): Value? { + return debugProcess.invokeInstanceMethod(evaluationContext, obj, method, args, invocationOptions) } fun invokeMethod(type: ClassType, method: Method, args: List): Value? { return debugProcess.invokeMethod(evaluationContext, type, method, args) } + fun invokeMethod(type: InterfaceType, method: Method, args: List): Value? { + return debugProcess.invokeMethod(evaluationContext, type, method, args) + } + @Throws(EvaluateException::class) fun newInstance(type: ClassType, constructor: Method, args: List): ObjectReference { return debugProcess.newInstance(evaluationContext, type, constructor, args)