classTrack.c 6.5 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * 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
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
21 22 23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
24
 */
25

D
duke 已提交
26 27
/*
 * This module tracks classes that have been prepared, so as to
28 29 30 31 32 33 34
 * be able to report which have been unloaded. On VM start-up
 * and whenever new classes are loaded, all prepared classes'
 * signatures are attached as JVMTI tag to the class object.
 * Class unloading is tracked by registering
 * ObjectFree callback on class objects. When this happens, we find
 * the signature of the unloaded class(es) and report them back
 * to the event handler to synthesize class-unload-events.
D
duke 已提交
35 36 37 38 39 40
 */

#include "util.h"
#include "bag.h"
#include "classTrack.h"

41
#define NOT_TAGGED 0
D
duke 已提交
42 43

/*
44
 * The JVMTI tracking env to keep track of klass tags for class-unloads
D
duke 已提交
45
 */
46
static jvmtiEnv* trackingEnv;
D
duke 已提交
47 48

/*
49 50
 * A bag containing all the deleted classes' signatures. Must be accessed under
 * classTrackLock.
D
duke 已提交
51
 */
52
struct bag* deletedSignatures;
D
duke 已提交
53 54

/*
55
 * Lock to keep integrity of deletedSignatures.
D
duke 已提交
56
 */
57
static jrawMonitorID classTrackLock;
D
duke 已提交
58 59

/*
60 61 62
 * Invoke the callback when classes are freed, find and record the signature
 * in deletedSignatures. Those are only used in addPreparedClass() by the
 * same thread.
D
duke 已提交
63
 */
64 65
static void JNICALL
cbTrackingObjectFree(jvmtiEnv* jvmti_env, jlong tag)
D
duke 已提交
66
{
67 68 69 70
    debugMonitorEnter(classTrackLock);
    if (deletedSignatures == NULL) {
      debugMonitorExit(classTrackLock);
      return;
D
duke 已提交
71
    }
72
    *(char**)bagAdd(deletedSignatures) = (char*)jlong_to_ptr(tag);
D
duke 已提交
73

74
    debugMonitorExit(classTrackLock);
D
duke 已提交
75 76 77
}

/*
78 79
 * Called after class unloads have occurred.
 * The signatures of classes which were unloaded are returned.
D
duke 已提交
80 81 82 83
 */
struct bag *
classTrack_processUnloads(JNIEnv *env)
{
84 85 86 87 88
    debugMonitorEnter(classTrackLock);
    if (deletedSignatures == NULL) {
        // Class tracking not initialized, nobody's interested.
        debugMonitorExit(classTrackLock);
        return NULL;
D
duke 已提交
89
    }
90 91 92 93
    struct bag* deleted = deletedSignatures;
    deletedSignatures = bagCreateBag(sizeof(char*), 10);
    debugMonitorExit(classTrackLock);
    return deleted;
D
duke 已提交
94 95 96
}

/*
97
 * Add a class to the prepared class table.
D
duke 已提交
98 99
 */
void
100
classTrack_addPreparedClass(JNIEnv *env_unused, jclass klass)
D
duke 已提交
101 102
{
    jvmtiError error;
103 104 105 106 107 108 109 110
    jvmtiEnv* env = trackingEnv;

    if (gdata && gdata->assertOn) {
        // Check this is not already tagged.
        jlong tag;
        error = JVMTI_FUNC_PTR(trackingEnv, GetTag)(env, klass, &tag);
        if (error != JVMTI_ERROR_NONE) {
            EXIT_ERROR(error, "Unable to GetTag with class trackingEnv");
D
duke 已提交
111
        }
112
        JDI_ASSERT(tag == NOT_TAGGED);
D
duke 已提交
113 114
    }

115 116
    char* signature;
    error = classSignature(klass, &signature, NULL);
D
duke 已提交
117 118 119
    if (error != JVMTI_ERROR_NONE) {
        EXIT_ERROR(error,"signature");
    }
120
    error = JVMTI_FUNC_PTR(trackingEnv, SetTag)(env, klass, ptr_to_jlong(signature));
121 122 123
    if (error != JVMTI_ERROR_NONE) {
        jvmtiDeallocate(signature);
        EXIT_ERROR(error,"SetTag");
D
duke 已提交
124
    }
125
}
D
duke 已提交
126

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
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;
D
duke 已提交
149 150 151
}

/*
152
 * Called once to initialize class-tracking.
D
duke 已提交
153 154 155 156
 */
void
classTrack_initialize(JNIEnv *env)
{
157 158 159 160 161 162
    deletedSignatures = NULL;
    classTrackLock = debugMonitorCreate("Deleted class tag lock");
    trackingEnv = getSpecialJvmti();
    if (trackingEnv == NULL) {
        EXIT_ERROR(AGENT_ERROR_INTERNAL, "Failed to allocate tag-tracking jvmtiEnv");
    }
D
duke 已提交
163 164


165 166 167
    if (!setupEvents()) {
        EXIT_ERROR(AGENT_ERROR_INTERNAL, "Unable to setup ObjectFree tracking");
    }
D
duke 已提交
168

169 170 171 172 173 174 175 176 177 178 179 180 181 182
    jint classCount;
    jclass *classes;
    jvmtiError error;
    jint i;

    error = allLoadedClasses(&classes, &classCount);
    if ( error == JVMTI_ERROR_NONE ) {
        for (i = 0; i < classCount; i++) {
            jclass klass = classes[i];
            jint status;
            jint wanted = JVMTI_CLASS_STATUS_PREPARED | JVMTI_CLASS_STATUS_ARRAY;
            status = classStatus(klass);
            if ((status & wanted) != 0) {
                classTrack_addPreparedClass(env, klass);
D
duke 已提交
183 184
            }
        }
185 186 187 188 189
        jvmtiDeallocate(classes);
    } else {
        EXIT_ERROR(error,"loaded classes array");
    }
}
D
duke 已提交
190

191 192 193 194 195 196 197 198 199 200
/*
 * Called to activate class-tracking when a listener registers for EI_GC_FINISH.
 */
void
classTrack_activate(JNIEnv *env)
{
    debugMonitorEnter(classTrackLock);
    deletedSignatures = bagCreateBag(sizeof(char*), 1000);
    debugMonitorExit(classTrackLock);
}
D
duke 已提交
201

202 203 204 205 206 207
static jboolean
cleanDeleted(void *signatureVoid, void *arg)
{
    char* sig = *(char**)signatureVoid;
    jvmtiDeallocate(sig);
    return JNI_TRUE;
D
duke 已提交
208 209
}

210 211 212
/*
 * Called when agent detaches.
 */
D
duke 已提交
213 214 215
void
classTrack_reset(void)
{
216 217 218 219 220 221 222 223 224
    debugMonitorEnter(classTrackLock);

    if (deletedSignatures != NULL) {
        bagEnumerateOver(deletedSignatures, cleanDeleted, NULL);
        bagDestroyBag(deletedSignatures);
        deletedSignatures = NULL;
    }

    debugMonitorExit(classTrackLock);
D
duke 已提交
225
}