Debugger: Some way to notify target process using JDI?
Our language plugin, not generating class files on disk, needs to notify the debugged process of class changes. Our type system dynamically compiles to bytecode in memory. So what I'd like to do is notify the target process's type system via JDI ClassType.invokeMethod(). The general idea is our type system would detect the jdwp agent and if present create a dedicated thread to receive the call. However, it appears that JDI does not accommodate this scenario; it seems that invokeMethod() can be called only when the thread is suspended during a breakpoint, which is not always the case when compiling in the debugger and it certainly isn't the case for the dedicated thread. So my question is, is there some way to use JDI from IntelliJ to notify the target process? I'd really like to piggyback on the existing JDI socket and not have to create a separate line of communication.
Please sign in to leave a comment.
Hi Scott,
This depends on what is the real goal. The method invocation via JDI is not a good idea for the reasons you mentioned. If the goal is to reload classes then the "redefineClasses" API call will do the job. This call does not require the VM to be suspended at a breakpoint. However, there are other limitations instead.
If you described the real goal of this operation, we'd probably suggest something.
Thanks for the quick response Eugene.
The real goal is indeed to redefine classes, however the bytecode for the classes must be compiled within the target process, so our plugin can't use the conventional method of compiling in IJ and redefining classes by sending the byte across the wire. Our type system in the target process performs the compilation and eventually does call through to this method, but it does so directly to the jvmti via native code to avoid the one-connection limit imposed by the jdwp. The challenge then is for our IJ plugin to somehow notify the target process that it needs to recompile and redefine classes. We'd like to do this during a compile operation in IJ. My goal is to somehow piggyback on IJ's jdwp agent as a way to avoid creating an additional line of communication, but any other ideas are quite welcome!
You may get access to DebuggerSession object via
DebuggerManagerEx.getSessions() method
Then you may obtain a DebugProcess object and get a reverence to VirtualMachineProxy
Notifications from compiler subsystem can be received by subscribing to CompilerTopics.COMPILATION_STATUS topic via MessageBus.
Thanks again for your reply. What I need is a way for my IJ plugin to talk to the remote process somehow using JDI if possible. Our compiler in IJ needs to notify the target process of type changes in the form of source code (our language does not compile to bytecode in IJ). So, essentially, i'd like to be able to send a collection of source strings to the target process where it compiles to bytecode and then calls redefine classes directly. Thanks.
> So, essentially, i'd like to be able to send a collection of source strings to the target process where it compiles to bytecode and then calls redefine classes directly.
This is only possible via method invocation, which, in turn, is available only when the debuggee's VM is paused at a breakpoint.
So the only possibility here is to establish a different way of communication between processes.
Have a look at "Netty" or "Mina" NIO-based frameworks. They both are lightweight and convenient to use when you need inter-process communication using some custom protocol. For our purposes Netty works pretty good.
Thanks again, but what I'm after is a way to avoid creating another line of communication; I don't want to burden the user with having to provide more information such as a port on a socket or what have you. Instead I prefer a way to piggyback on the JDWP, which is what I finally did. Basically, I created a class in our API for the exclusive purpose of transporting information to the target process over JDWP. This class is dynamically compiled and redefined to include static information about types that have changed and is always included in the call to redefine classes. The target process, always having our language's runtime involved, starts a dedicated thread if it is being debugged. This thread polls for changes to the class and handles stuff specific to maintaining the freshness of our type system. A little sneaky, but works just fine.