On Thu, 20 Oct 2022 01:21:19 GMT, Chris Plummer <cjplum...@openjdk.org> wrote:

> The debug agent needs to keep track of all loaded classes, and also be 
> notified when they are unloaded. It tracks classes loading by getting 
> CLASS_PREPARE events and it tracks their unloading by tagging them, which 
> triggers OBJECT_FREE events when they are unloaded. The tagging and 
> OBJECT_FREE events are handled by a separate JVMTIEnv from the one that does 
> main event handling, mostly in support of the attached debugger. However, the 
> CLASS_PREPARE events are piggy backed on the main event handler. As a result, 
> we have this special check in filterAndHandleEvent():
> 
>         /* We must keep track of all classes prepared to know what's unloaded 
> */
>         if (evinfo->ei == EI_CLASS_PREPARE) {
>             classTrack_addPreparedClass(env, evinfo->clazz);
>         }
> 
> We also have to always keep CLASS_PREPARE events enabled on the main event 
> handler, even if the debugger is not requesting them. The main event handler 
> has a lot of overhead that isn't necessary when simply wanting to use the 
> CLASS_PREPARE event for class tracking.
> 
> Another downside of this piggy backing is it causes problems for addressing 
> [JDK-8295376](https://bugs.openjdk.org/browse/JDK-8295376), which is 
> attempting to not track virtual threads when the debugger is not attached (no 
> VIRTUAL_THREAD_START and VIRTUAL_THREAD_END events). The problem is when the 
> debugger is not attached and a CLASS_PREPARE event comes in on a virtual 
> thread, the debug agent unnecessarily creates a ThreadNode for it. Since 
> there won't be a corresponding VIRTUAL_THREAD_END event when the virtual 
> thread is destroyed (as long as the debugger is not attached), the debug 
> agent ends up keeping this ThreadNode around even after the thread is gone. 
> This usually eventually leads to an assert.
> 
> The fix for this is pretty simple. We already have the separate JVMTIEnv that 
> the class tracker uses to handle OBJECT_FREE. This is easily purposed to also 
> handle CLASS_PREPARE events. By doing so we can get rid of the special 
> CLASS_PREPARE code above in filterAndHandleEvent(), and we also only need to 
> enable CLASS_PREPARE events for the main event handler when a debugger is 
> attached and is requesting them.

src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c line 1268:

> 1266:         case EI_VM_INIT:
> 1267:         case EI_VM_DEATH:
> 1268:         case EI_CLASS_PREPARE:

Since CLASS_PREPARE is no longer globally and permanently enabled, we remove it 
from this list so the code below can enable it as needed based on whether or 
not the debugger as requested CLASS_PREPARE events.

src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c line 553:

> 551:             classTrack_addPreparedClass(env, evinfo->clazz);
> 552:         }
> 553: 

We no longer need this hack here since the class tracking code now installs its 
own CLASS_PREPARE event handler.

src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c line 1516:

> 1514:     if (error != JVMTI_ERROR_NONE) {
> 1515:         EXIT_ERROR(error,"Can't enable class prepare events");
> 1516:     }

We no longer permanently enable CLASS_PREPARE events here. It's now done in 
classTrack.c, and only impacts the JVMTIEnv that us used for class tracking.

-------------

PR: https://git.openjdk.org/jdk/pull/10776

Reply via email to