< prev index next >

src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -59,10 +59,46 @@
  * to a linked list of KlassNode.
  */
 static KlassNode **table;
 
 /*
+ * The JVMTI env we use to keep track of klass tags which allows us to detect class-unloads.
+ */
+static jvmtiEnv *trackingEnv;
+
+/*
+ * The current highest tag number in use by the trackingEnv.
+ *
+ * No need for synchronization since everything is done under the handlerLock.
+ */
+static jlong currentKlassTag;
+
+/*
+ * A lock to protect access to 'deletedTagBag'
+ */
+static jrawMonitorID deletedTagLock;
+
+/*
+ * A flag indicating whether classes have been unloaded.
+ *
+ * It is cleared each time classTrack_processUnloads is called.
+ */
+jboolean hasUnloadedClasses;
+
+/*
+ * The callback for when classes are freed. Only classes are called because this is registered with
+ * the trackingEnv which only tags classes.
+ */
+static void JNICALL
+cbTrackingObjectFree(jvmtiEnv* jvmti_env, jlong tag)
+{
+    debugMonitorEnter(deletedTagLock);
+    hasUnloadedClasses = JNI_TRUE;
+    debugMonitorExit(deletedTagLock);
+}
+
+/*
  * Return slot in hash table to use for this class.
  */
 static jint
 hashKlass(jclass klass)
 {

@@ -175,11 +211,18 @@
 
             jint classCount;
             jclass *classes;
             jvmtiError error;
             int i;
+            jboolean hasUnloaded = JNI_FALSE;
+
+            debugMonitorEnter(deletedTagLock);
+            hasUnloaded = hasUnloadedClasses;
+            hasUnloadedClasses = JNI_FALSE;
+            debugMonitorExit(deletedTagLock);
 
+            if (hasUnloaded) {
             error = allLoadedClasses(&classes, &classCount);
             if ( error != JVMTI_ERROR_NONE ) {
                 jvmtiDeallocate(newTable);
                 EXIT_ERROR(error,"loaded classes");
             } else {

@@ -193,11 +236,11 @@
 
                 /* Delete old table, install new one */
                 unloadedSignatures = deleteTable(env, table);
                 table = newTable;
             }
-
+            }
         } END_WITH_LOCAL_REFS(env)
 
     }
 
     return unloadedSignatures;

@@ -232,10 +275,17 @@
     error = classSignature(klass, &(node->signature), NULL);
     if (error != JVMTI_ERROR_NONE) {
         jvmtiDeallocate(node);
         EXIT_ERROR(error,"signature");
     }
+    ++currentKlassTag;
+    error = JVMTI_FUNC_PTR(trackingEnv,SetTag)(trackingEnv, klass, currentKlassTag);
+    if (error != JVMTI_ERROR_NONE) {
+        jvmtiDeallocate(node->signature);
+        jvmtiDeallocate(node);
+        EXIT_ERROR(error,"SetTag");
+    }
     if ((node->klass = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, klass)) == NULL) {
         jvmtiDeallocate(node->signature);
         jvmtiDeallocate(node);
         EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"NewWeakGlobalRef");
     }

@@ -243,16 +293,55 @@
     /* Insert the new node */
     node->next = *head;
     *head = node;
 }
 
+static jboolean
+setupEvents()
+{
+    jvmtiCapabilities caps;
+    memset(&caps, 0, sizeof(caps));
+    caps.can_generate_object_free_events = 1;
+    jvmtiError error = JVMTI_FUNC_PTR(trackingEnv,AddCapabilities)(trackingEnv, &caps);
+    if (error != JVMTI_ERROR_NONE) {
+        return JNI_FALSE;
+    }
+    jvmtiEventCallbacks cb;
+    memset(&cb, 0, sizeof(cb));
+    cb.ObjectFree = cbTrackingObjectFree;
+    error = JVMTI_FUNC_PTR(trackingEnv,SetEventCallbacks)(trackingEnv, &cb, sizeof(cb));
+    if (error != JVMTI_ERROR_NONE) {
+        return JNI_FALSE;
+    }
+    error = JVMTI_FUNC_PTR(trackingEnv,SetEventNotificationMode)
+             (trackingEnv, JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL);
+    if (error != JVMTI_ERROR_NONE) {
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
 /*
  * Called once to build the initial prepared class hash table.
  */
 void
 classTrack_initialize(JNIEnv *env)
 {
+    /* Setup the tracking env */
+    trackingEnv = getSpecialJvmti();
+    if ( trackingEnv == NULL ) {
+        EXIT_ERROR(AGENT_ERROR_INTERNAL,"Failed to allocate tag-tracking jvmtiEnv");
+    }
+    /* We want to create these before turning on the events or tagging anything. */
+    deletedTagLock = debugMonitorCreate("Deleted class tag lock");
+    hasUnloadedClasses = JNI_FALSE;
+    /* Setup the trackingEnv's ObjectFree event */
+    if (!setupEvents()) {
+        ERROR_MESSAGE(("Unable to setup class ObjectFree tracking! Class unloads will not "
+                       "be reported!"));
+    }
+    currentKlassTag = 0l;
     WITH_LOCAL_REFS(env, 1) {
 
         jint classCount;
         jclass *classes;
         jvmtiError error;
< prev index next >