1 /* 2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 /* The Class Loader table. */ 42 43 /* 44 * The Class Loader objects show up so early in the VM process that a 45 * separate table was designated for Class Loaders. 46 * 47 * The Class Loader is unique by way of it's jobject uniqueness, unfortunately 48 * use of JNI too early for jobject comparisons is problematic. 49 * It is assumed that the number of class loaders will be limited, and 50 * a simple linear search will be performed for now. 51 * That logic is isolated here and can be changed to use the standard 52 * table hash table search once we know JNI can be called safely. 53 * 54 * A weak global reference is created to keep tabs on loaders, and as 55 * each search for a loader happens, NULL weak global references will 56 * trigger the freedom of those entries. 57 * 58 */ 59 60 #include "hprof.h" 61 62 typedef struct { 63 jobject globalref; /* Weak Global reference for object */ 64 ObjectIndex object_index; 65 } LoaderInfo; 66 67 static LoaderInfo * 68 get_info(LoaderIndex index) 69 { 70 return (LoaderInfo*)table_get_info(gdata->loader_table, index); 71 } 72 73 static void 74 delete_globalref(JNIEnv *env, LoaderInfo *info) 75 { 76 jobject ref; 77 78 HPROF_ASSERT(env!=NULL); 79 HPROF_ASSERT(info!=NULL); 80 ref = info->globalref; 81 info->globalref = NULL; 82 if ( ref != NULL ) { 83 deleteWeakGlobalReference(env, ref); 84 } 85 info->object_index = 0; 86 } 87 88 static void 89 cleanup_item(TableIndex index, void *key_ptr, int key_len, 90 void *info_ptr, void *arg) 91 { 92 } 93 94 static void 95 delete_ref_item(TableIndex index, void *key_ptr, int key_len, 96 void *info_ptr, void *arg) 97 { 98 delete_globalref((JNIEnv*)arg, (LoaderInfo*)info_ptr); 99 } 100 101 static void 102 list_item(TableIndex index, void *key_ptr, int key_len, 103 void *info_ptr, void *arg) 104 { 105 LoaderInfo *info; 106 107 HPROF_ASSERT(info_ptr!=NULL); 108 109 info = (LoaderInfo*)info_ptr; 110 debug_message( "Loader 0x%08x: globalref=%p, object_index=%d\n", 111 index, (void*)info->globalref, info->object_index); 112 } 113 114 static void 115 free_entry(JNIEnv *env, LoaderIndex index) 116 { 117 LoaderInfo *info; 118 119 info = get_info(index); 120 delete_globalref(env, info); 121 table_free_entry(gdata->loader_table, index); 122 } 123 124 typedef struct SearchData { 125 JNIEnv *env; 126 jobject loader; 127 LoaderIndex found; 128 } SearchData; 129 130 static void 131 search_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg) 132 { 133 LoaderInfo *info; 134 SearchData *data; 135 136 HPROF_ASSERT(info_ptr!=NULL); 137 HPROF_ASSERT(arg!=NULL); 138 info = (LoaderInfo*)info_ptr; 139 data = (SearchData*)arg; 140 if ( data->loader == info->globalref ) { 141 /* Covers when looking for NULL too. */ 142 HPROF_ASSERT(data->found==0); /* Did we find more than one? */ 143 data->found = index; 144 } else if ( data->env != NULL && data->loader != NULL && 145 info->globalref != NULL ) { 146 jobject lref; 147 148 lref = newLocalReference(data->env, info->globalref); 149 if ( lref == NULL ) { 150 /* Object went away, free reference and entry */ 151 free_entry(data->env, index); 152 } else if ( isSameObject(data->env, data->loader, lref) ) { 153 HPROF_ASSERT(data->found==0); /* Did we find more than one? */ 154 data->found = index; 155 } 156 if ( lref != NULL ) { 157 deleteLocalReference(data->env, lref); 158 } 159 } 160 161 } 162 163 static LoaderIndex 164 search(JNIEnv *env, jobject loader) 165 { 166 SearchData data; 167 168 data.env = env; 169 data.loader = loader; 170 data.found = 0; 171 table_walk_items(gdata->loader_table, &search_item, (void*)&data); 172 return data.found; 173 } 174 175 LoaderIndex 176 loader_find_or_create(JNIEnv *env, jobject loader) 177 { 178 LoaderIndex index; 179 180 /* See if we remembered the system loader */ 181 if ( loader==NULL && gdata->system_loader != 0 ) { 182 return gdata->system_loader; 183 } 184 if ( loader==NULL ) { 185 env = NULL; 186 } 187 index = search(env, loader); 188 if ( index == 0 ) { 189 static LoaderInfo empty_info; 190 LoaderInfo info; 191 192 info = empty_info; 193 if ( loader != NULL ) { 194 HPROF_ASSERT(env!=NULL); 195 info.globalref = newWeakGlobalReference(env, loader); 196 info.object_index = 0; 197 } 198 index = table_create_entry(gdata->loader_table, NULL, 0, (void*)&info); 199 } 200 HPROF_ASSERT(search(env,loader)==index); 201 /* Remember the system loader */ 202 if ( loader==NULL && gdata->system_loader == 0 ) { 203 gdata->system_loader = index; 204 } 205 return index; 206 } 207 208 void 209 loader_init(void) 210 { 211 gdata->loader_table = table_initialize("Loader", 212 16, 16, 0, (int)sizeof(LoaderInfo)); 213 } 214 215 void 216 loader_list(void) 217 { 218 debug_message( 219 "--------------------- Loader Table ------------------------\n"); 220 table_walk_items(gdata->loader_table, &list_item, NULL); 221 debug_message( 222 "----------------------------------------------------------\n"); 223 } 224 225 void 226 loader_cleanup(void) 227 { 228 table_cleanup(gdata->loader_table, &cleanup_item, NULL); 229 gdata->loader_table = NULL; 230 } 231 232 void 233 loader_delete_global_references(JNIEnv *env) 234 { 235 table_walk_items(gdata->loader_table, &delete_ref_item, (void*)env); 236 } 237 238 /* Get the object index for a class loader */ 239 ObjectIndex 240 loader_object_index(JNIEnv *env, LoaderIndex index) 241 { 242 LoaderInfo *info; 243 ObjectIndex object_index; 244 jobject wref; 245 246 /* Assume no object index at first (default class loader) */ 247 info = get_info(index); 248 object_index = info->object_index; 249 wref = info->globalref; 250 if ( wref != NULL && object_index == 0 ) { 251 jobject lref; 252 253 object_index = 0; 254 lref = newLocalReference(env, wref); 255 if ( lref != NULL && !isSameObject(env, lref, NULL) ) { 256 jlong tag; 257 258 /* Get the tag on the object and extract the object_index */ 259 tag = getTag(lref); 260 if ( tag != (jlong)0 ) { 261 object_index = tag_extract(tag); 262 } 263 } 264 if ( lref != NULL ) { 265 deleteLocalReference(env, lref); 266 } 267 info->object_index = object_index; 268 } 269 return object_index; 270 }