1 /* 2 * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * This module tracks classes that have been prepared, so as to 28 * be able to report which have been unloaded. On VM start-up 29 * and whenever new classes are loaded, all prepared classes' 30 * signatures are attached as JVMTI tag to the class object. 31 * Class unloading is tracked by registering 32 * ObjectFree callback on class objects. When this happens, we find 33 * the signature of the unloaded class(es) and report them back 34 * to the event handler to synthesize class-unload-events. 35 */ 36 37 #include "util.h" 38 #include "bag.h" 39 #include "classTrack.h" 40 41 /* 42 * The JVMTI tracking env to keep track of klass tags for class-unloads 43 */ 44 static jvmtiEnv* trackingEnv; 45 46 /* 47 * A bag containing all the deleted classes' signatures. Must be accessed under 48 * classTrackLock. 49 */ 50 struct bag* deletedSignatures; 51 52 /* 53 * Lock to keep integrity of deletedSignatures. 54 */ 55 static jrawMonitorID classTrackLock; 56 57 /* 58 * Invoke the callback when classes are freed, find and record the signature 59 * in deletedSignatures. Those are only used in addPreparedClass() by the 60 * same thread. 61 */ 62 static void JNICALL 63 cbTrackingObjectFree(jvmtiEnv* jvmti_env, jlong tag) 64 { 65 debugMonitorEnter(classTrackLock); 66 if (deletedSignatures == NULL) { 67 debugMonitorExit(classTrackLock); 68 return; 69 } 70 *(char**)bagAdd(deletedSignatures) = (char*)tag; 71 72 debugMonitorExit(classTrackLock); 73 } 74 75 /* 76 * Called after class unloads have occurred. 77 * The signatures of classes which were unloaded are returned. 78 */ 79 struct bag * 80 classTrack_processUnloads(JNIEnv *env) 81 { 82 debugMonitorEnter(classTrackLock); 83 if (deletedSignatures == NULL) { 84 // Class tracking not initialized, nobody's interested. 85 debugMonitorExit(classTrackLock); 86 return NULL; 87 } 88 struct bag* deleted = deletedSignatures; 89 deletedSignatures = bagCreateBag(sizeof(char*), 10); 90 debugMonitorExit(classTrackLock); 91 return deleted; 92 } 93 94 /* 95 * Add a class to the prepared class table. 96 */ 97 void 98 classTrack_addPreparedClass(JNIEnv *env_unused, jclass klass) 99 { 100 jvmtiError error; 101 102 jvmtiEnv* env = trackingEnv; 103 104 // Check this is not already tagged. 105 jlong tag; 106 error = JVMTI_FUNC_PTR(trackingEnv, GetTag)(env, klass, &tag); 107 if (error != JVMTI_ERROR_NONE) { 108 EXIT_ERROR(error, "Unable to GetTag with class trackingEnv"); 109 } 110 if (tag != 0l) { 111 return; // Already added 112 } 113 114 char* signature; 115 error = classSignature(klass, &signature, NULL); 116 if (error != JVMTI_ERROR_NONE) { 117 EXIT_ERROR(error,"signature"); 118 } 119 error = JVMTI_FUNC_PTR(trackingEnv, SetTag)(env, klass, (jlong)signature); 120 if (error != JVMTI_ERROR_NONE) { 121 jvmtiDeallocate(signature); 122 EXIT_ERROR(error,"SetTag"); 123 } 124 125 } 126 127 static jboolean 128 setupEvents() 129 { 130 jvmtiCapabilities caps; 131 memset(&caps, 0, sizeof(caps)); 132 caps.can_generate_object_free_events = 1; 133 jvmtiError error = JVMTI_FUNC_PTR(trackingEnv, AddCapabilities)(trackingEnv, &caps); 134 if (error != JVMTI_ERROR_NONE) { 135 return JNI_FALSE; 136 } 137 jvmtiEventCallbacks cb; 138 memset(&cb, 0, sizeof(cb)); 139 cb.ObjectFree = cbTrackingObjectFree; 140 error = JVMTI_FUNC_PTR(trackingEnv, SetEventCallbacks)(trackingEnv, &cb, sizeof(cb)); 141 if (error != JVMTI_ERROR_NONE) { 142 return JNI_FALSE; 143 } 144 error = JVMTI_FUNC_PTR(trackingEnv, SetEventNotificationMode)(trackingEnv, JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL); 145 if (error != JVMTI_ERROR_NONE) { 146 return JNI_FALSE; 147 } 148 return JNI_TRUE; 149 } 150 151 /* 152 * Called once to initialize class-tracking. 153 */ 154 void 155 classTrack_initialize(JNIEnv *env) 156 { 157 deletedSignatures = NULL; 158 classTrackLock = debugMonitorCreate("Deleted class tag lock"); 159 trackingEnv = getSpecialJvmti(); 160 if (trackingEnv == NULL) { 161 EXIT_ERROR(AGENT_ERROR_INTERNAL, "Failed to allocate tag-tracking jvmtiEnv"); 162 } 163 164 165 if (!setupEvents()) { 166 EXIT_ERROR(AGENT_ERROR_INTERNAL, "Unable to setup ObjectFree tracking"); 167 } 168 169 jint classCount; 170 jclass *classes; 171 jvmtiError error; 172 jint i; 173 174 error = allLoadedClasses(&classes, &classCount); 175 if ( error == JVMTI_ERROR_NONE ) { 176 for (i = 0; i < classCount; i++) { 177 jclass klass = classes[i]; 178 jint status; 179 jint wanted = JVMTI_CLASS_STATUS_PREPARED | JVMTI_CLASS_STATUS_ARRAY; 180 status = classStatus(klass); 181 if ((status & wanted) != 0) { 182 classTrack_addPreparedClass(env, klass); 183 } 184 } 185 jvmtiDeallocate(classes); 186 } else { 187 EXIT_ERROR(error,"loaded classes array"); 188 } 189 } 190 191 /* 192 * Called to activate class-tracking when a listener registers for EI_GC_FINISH. 193 */ 194 void 195 classTrack_activate(JNIEnv *env) 196 { 197 debugMonitorEnter(classTrackLock); 198 deletedSignatures = bagCreateBag(sizeof(char*), 1000); 199 debugMonitorExit(classTrackLock); 200 } 201 202 static jboolean 203 cleanDeleted(void *signatureVoid, void *arg) 204 { 205 char* sig = *(char**)signatureVoid; 206 jvmtiDeallocate(sig); 207 return JNI_TRUE; 208 } 209 210 /* 211 * Called when agent detaches. 212 */ 213 void 214 classTrack_reset(void) 215 { 216 debugMonitorEnter(classTrackLock); 217 218 bagEnumerateOver(deletedSignatures, cleanDeleted, NULL); 219 bagDestroyBag(deletedSignatures); 220 deletedSignatures = NULL; 221 222 debugMonitorExit(classTrackLock); 223 }