| /* |
| * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * - Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * - Neither the name of Oracle nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* |
| * This source code is provided to illustrate the usage of a given feature |
| * or technique and has been deliberately simplified. Additional steps |
| * required for a production-quality application, such as security checks, |
| * input validation and proper error handling, might not be present in |
| * this sample code. |
| */ |
| |
| |
| /* The Class Loader table. */ |
| |
| /* |
| * The Class Loader objects show up so early in the VM process that a |
| * separate table was designated for Class Loaders. |
| * |
| * The Class Loader is unique by way of it's jobject uniqueness, unfortunately |
| * use of JNI too early for jobject comparisons is problematic. |
| * It is assumed that the number of class loaders will be limited, and |
| * a simple linear search will be performed for now. |
| * That logic is isolated here and can be changed to use the standard |
| * table hash table search once we know JNI can be called safely. |
| * |
| * A weak global reference is created to keep tabs on loaders, and as |
| * each search for a loader happens, NULL weak global references will |
| * trigger the freedom of those entries. |
| * |
| */ |
| |
| #include "hprof.h" |
| |
| typedef struct { |
| jobject globalref; /* Weak Global reference for object */ |
| ObjectIndex object_index; |
| } LoaderInfo; |
| |
| static LoaderInfo * |
| get_info(LoaderIndex index) |
| { |
| return (LoaderInfo*)table_get_info(gdata->loader_table, index); |
| } |
| |
| static void |
| delete_globalref(JNIEnv *env, LoaderInfo *info) |
| { |
| jobject ref; |
| |
| HPROF_ASSERT(env!=NULL); |
| HPROF_ASSERT(info!=NULL); |
| ref = info->globalref; |
| info->globalref = NULL; |
| if ( ref != NULL ) { |
| deleteWeakGlobalReference(env, ref); |
| } |
| info->object_index = 0; |
| } |
| |
| static void |
| cleanup_item(TableIndex index, void *key_ptr, int key_len, |
| void *info_ptr, void *arg) |
| { |
| } |
| |
| static void |
| delete_ref_item(TableIndex index, void *key_ptr, int key_len, |
| void *info_ptr, void *arg) |
| { |
| delete_globalref((JNIEnv*)arg, (LoaderInfo*)info_ptr); |
| } |
| |
| static void |
| list_item(TableIndex index, void *key_ptr, int key_len, |
| void *info_ptr, void *arg) |
| { |
| LoaderInfo *info; |
| |
| HPROF_ASSERT(info_ptr!=NULL); |
| |
| info = (LoaderInfo*)info_ptr; |
| debug_message( "Loader 0x%08x: globalref=%p, object_index=%d\n", |
| index, (void*)info->globalref, info->object_index); |
| } |
| |
| static void |
| free_entry(JNIEnv *env, LoaderIndex index) |
| { |
| LoaderInfo *info; |
| |
| info = get_info(index); |
| delete_globalref(env, info); |
| table_free_entry(gdata->loader_table, index); |
| } |
| |
| typedef struct SearchData { |
| JNIEnv *env; |
| jobject loader; |
| LoaderIndex found; |
| } SearchData; |
| |
| static void |
| search_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg) |
| { |
| LoaderInfo *info; |
| SearchData *data; |
| |
| HPROF_ASSERT(info_ptr!=NULL); |
| HPROF_ASSERT(arg!=NULL); |
| info = (LoaderInfo*)info_ptr; |
| data = (SearchData*)arg; |
| if ( data->loader == info->globalref ) { |
| /* Covers when looking for NULL too. */ |
| HPROF_ASSERT(data->found==0); /* Did we find more than one? */ |
| data->found = index; |
| } else if ( data->env != NULL && data->loader != NULL && |
| info->globalref != NULL ) { |
| jobject lref; |
| |
| lref = newLocalReference(data->env, info->globalref); |
| if ( lref == NULL ) { |
| /* Object went away, free reference and entry */ |
| free_entry(data->env, index); |
| } else if ( isSameObject(data->env, data->loader, lref) ) { |
| HPROF_ASSERT(data->found==0); /* Did we find more than one? */ |
| data->found = index; |
| } |
| if ( lref != NULL ) { |
| deleteLocalReference(data->env, lref); |
| } |
| } |
| |
| } |
| |
| static LoaderIndex |
| search(JNIEnv *env, jobject loader) |
| { |
| SearchData data; |
| |
| data.env = env; |
| data.loader = loader; |
| data.found = 0; |
| table_walk_items(gdata->loader_table, &search_item, (void*)&data); |
| return data.found; |
| } |
| |
| LoaderIndex |
| loader_find_or_create(JNIEnv *env, jobject loader) |
| { |
| LoaderIndex index; |
| |
| /* See if we remembered the system loader */ |
| if ( loader==NULL && gdata->system_loader != 0 ) { |
| return gdata->system_loader; |
| } |
| if ( loader==NULL ) { |
| env = NULL; |
| } |
| index = search(env, loader); |
| if ( index == 0 ) { |
| static LoaderInfo empty_info; |
| LoaderInfo info; |
| |
| info = empty_info; |
| if ( loader != NULL ) { |
| HPROF_ASSERT(env!=NULL); |
| info.globalref = newWeakGlobalReference(env, loader); |
| info.object_index = 0; |
| } |
| index = table_create_entry(gdata->loader_table, NULL, 0, (void*)&info); |
| } |
| HPROF_ASSERT(search(env,loader)==index); |
| /* Remember the system loader */ |
| if ( loader==NULL && gdata->system_loader == 0 ) { |
| gdata->system_loader = index; |
| } |
| return index; |
| } |
| |
| void |
| loader_init(void) |
| { |
| gdata->loader_table = table_initialize("Loader", |
| 16, 16, 0, (int)sizeof(LoaderInfo)); |
| } |
| |
| void |
| loader_list(void) |
| { |
| debug_message( |
| "--------------------- Loader Table ------------------------\n"); |
| table_walk_items(gdata->loader_table, &list_item, NULL); |
| debug_message( |
| "----------------------------------------------------------\n"); |
| } |
| |
| void |
| loader_cleanup(void) |
| { |
| table_cleanup(gdata->loader_table, &cleanup_item, NULL); |
| gdata->loader_table = NULL; |
| } |
| |
| void |
| loader_delete_global_references(JNIEnv *env) |
| { |
| table_walk_items(gdata->loader_table, &delete_ref_item, (void*)env); |
| } |
| |
| /* Get the object index for a class loader */ |
| ObjectIndex |
| loader_object_index(JNIEnv *env, LoaderIndex index) |
| { |
| LoaderInfo *info; |
| ObjectIndex object_index; |
| jobject wref; |
| |
| /* Assume no object index at first (default class loader) */ |
| info = get_info(index); |
| object_index = info->object_index; |
| wref = info->globalref; |
| if ( wref != NULL && object_index == 0 ) { |
| jobject lref; |
| |
| object_index = 0; |
| lref = newLocalReference(env, wref); |
| if ( lref != NULL && !isSameObject(env, lref, NULL) ) { |
| jlong tag; |
| |
| /* Get the tag on the object and extract the object_index */ |
| tag = getTag(lref); |
| if ( tag != (jlong)0 ) { |
| object_index = tag_extract(tag); |
| } |
| } |
| if ( lref != NULL ) { |
| deleteLocalReference(env, lref); |
| } |
| info->object_index = object_index; |
| } |
| return object_index; |
| } |