Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/hprof/hprof_class.c
38829 views
/*1* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/383940/* Table of class information.41*42* Each element in this table is identified with a ClassIndex.43* Each element is uniquely identified by it's signature and loader.44* Every class load has a unique class serial number.45* While loaded, each element will have a cache of a global reference46* to it's jclass object, plus jmethodID's as needed.47* Method signatures and names are obtained via BCI.48* Methods can be identified with a ClassIndex and MethodIndex pair,49* where the MethodIndex matches the index of the method name and50* signature arrays obtained from the BCI pass.51* Strings are stored in the string table and a StringIndex is used.52* Class Loaders are stored in the loader table and a LoaderIndex is used.53* Since the jclass object is an object, at some point an object table54* entry may be allocated for the jclass as an ObjectIndex.55*/5657#include "hprof.h"5859/* Effectively represents a jclass object. */6061/* These table elements are made unique by and sorted by signature name. */6263typedef struct ClassKey {64StringIndex sig_string_index; /* Signature of class */65LoaderIndex loader_index; /* Index for class loader */66} ClassKey;6768/* Each class could contain method information, gotten from BCI callback */6970typedef struct MethodInfo {71StringIndex name_index; /* Method name, index into string table */72StringIndex sig_index; /* Method signature, index into string table */73jmethodID method_id; /* Method ID, possibly NULL at first */74} MethodInfo;7576/* The basic class information we save */7778typedef struct ClassInfo {79jclass classref; /* Global ref to jclass */80MethodInfo *method; /* Array of method data */81int method_count; /* Count of methods */82ObjectIndex object_index; /* Optional object index for jclass */83SerialNumber serial_num; /* Unique to the actual class load */84ClassStatus status; /* Current class status (bit mask) */85ClassIndex super; /* Super class in this table */86StringIndex name; /* Name of class */87jint inst_size; /* #bytes needed for instance fields */88jint field_count; /* Number of all fields */89FieldInfo *field; /* Pointer to all FieldInfo's */90} ClassInfo;9192/* Private interfaces */9394static ClassKey*95get_pkey(ClassIndex index)96{97void *key_ptr;98int key_len;99100table_get_key(gdata->class_table, index, (void*)&key_ptr, &key_len);101HPROF_ASSERT(key_len==sizeof(ClassKey));102HPROF_ASSERT(key_ptr!=NULL);103return (ClassKey*)key_ptr;104}105106static void107fillin_pkey(const char *sig, LoaderIndex loader_index, ClassKey *pkey)108{109static ClassKey empty_key;110111HPROF_ASSERT(loader_index!=0);112*pkey = empty_key;113pkey->sig_string_index = string_find_or_create(sig);114pkey->loader_index = loader_index;115}116117static ClassInfo *118get_info(ClassIndex index)119{120ClassInfo *info;121122info = (ClassInfo*)table_get_info(gdata->class_table, index);123return info;124}125126static void127fill_info(TableIndex index, ClassKey *pkey)128{129ClassInfo *info;130char *sig;131132info = get_info(index);133info->serial_num = gdata->class_serial_number_counter++;134info->method_count = 0;135info->inst_size = -1;136info->field_count = -1;137info->field = NULL;138sig = string_get(pkey->sig_string_index);139if ( sig[0] != JVM_SIGNATURE_CLASS ) {140info->name = pkey->sig_string_index;141} else {142int len;143144len = string_get_len(pkey->sig_string_index);145if ( len > 2 ) {146char *name;147148/* Class signature looks like "Lname;", we want "name" here. */149name = HPROF_MALLOC(len-1);150(void)memcpy(name, sig+1, len-2);151name[len-2] = 0;152info->name = string_find_or_create(name);153HPROF_FREE(name);154} else {155/* This would be strange, a class signature not in "Lname;" form? */156info->name = pkey->sig_string_index;157}158}159}160161static ClassIndex162find_entry(ClassKey *pkey)163{164ClassIndex index;165166index = table_find_entry(gdata->class_table,167(void*)pkey, (int)sizeof(ClassKey));168return index;169}170171static ClassIndex172create_entry(ClassKey *pkey)173{174ClassIndex index;175176index = table_create_entry(gdata->class_table,177(void*)pkey, (int)sizeof(ClassKey), NULL);178fill_info(index, pkey);179return index;180}181182static ClassIndex183find_or_create_entry(ClassKey *pkey)184{185ClassIndex index;186187HPROF_ASSERT(pkey!=NULL);188HPROF_ASSERT(pkey->loader_index!=0);189index = find_entry(pkey);190if ( index == 0 ) {191index = create_entry(pkey);192}193return index;194}195196static void197delete_classref(JNIEnv *env, ClassInfo *info, jclass klass)198{199jclass ref;200int i;201202HPROF_ASSERT(env!=NULL);203HPROF_ASSERT(info!=NULL);204205for ( i = 0 ; i < info->method_count ; i++ ) {206info->method[i].method_id = NULL;207}208ref = info->classref;209if ( klass != NULL ) {210info->classref = newGlobalReference(env, klass);211} else {212info->classref = NULL;213}214if ( ref != NULL ) {215deleteGlobalReference(env, ref);216}217}218219static void220cleanup_item(TableIndex index, void *key_ptr, int key_len,221void *info_ptr, void *arg)222{223ClassInfo *info;224225/* Cleanup any information in this ClassInfo structure. */226HPROF_ASSERT(key_ptr!=NULL);227HPROF_ASSERT(key_len==sizeof(ClassKey));228HPROF_ASSERT(info_ptr!=NULL);229info = (ClassInfo *)info_ptr;230if ( info->method_count > 0 ) {231HPROF_FREE((void*)info->method);232info->method_count = 0;233info->method = NULL;234}235if ( info->field != NULL ) {236HPROF_FREE((void*)info->field);237info->field_count = 0;238info->field = NULL;239}240}241242static void243delete_ref_item(TableIndex index, void *key_ptr, int key_len,244void *info_ptr, void *arg)245{246delete_classref((JNIEnv*)arg, (ClassInfo*)info_ptr, NULL);247}248249static void250list_item(TableIndex index, void *key_ptr, int key_len,251void *info_ptr, void *arg)252{253ClassInfo *info;254ClassKey key;255char *sig;256int i;257258HPROF_ASSERT(key_ptr!=NULL);259HPROF_ASSERT(key_len==sizeof(ClassKey));260HPROF_ASSERT(info_ptr!=NULL);261key = *((ClassKey*)key_ptr);262sig = string_get(key.sig_string_index);263info = (ClassInfo *)info_ptr;264debug_message(265"0x%08x: Class %s, SN=%u, status=0x%08x, ref=%p,"266" method_count=%d\n",267index,268(const char *)sig,269info->serial_num,270info->status,271(void*)info->classref,272info->method_count);273if ( info->method_count > 0 ) {274for ( i = 0 ; i < info->method_count ; i++ ) {275debug_message(276" Method %d: \"%s\", sig=\"%s\", method=%p\n",277i,278string_get(info->method[i].name_index),279string_get(info->method[i].sig_index),280(void*)info->method[i].method_id);281}282}283}284285static void286all_status_remove(TableIndex index, void *key_ptr, int key_len,287void *info_ptr, void *arg)288{289ClassInfo *info;290ClassStatus status;291292HPROF_ASSERT(info_ptr!=NULL);293/*LINTED*/294status = (ClassStatus)(long)(ptrdiff_t)arg;295info = (ClassInfo *)info_ptr;296info->status &= (~status);297}298299static void300unload_walker(TableIndex index, void *key_ptr, int key_len,301void *info_ptr, void *arg)302{303ClassInfo *info;304305HPROF_ASSERT(info_ptr!=NULL);306info = (ClassInfo *)info_ptr;307if ( ! ( info->status & CLASS_IN_LOAD_LIST ) ) {308if ( ! (info->status & (CLASS_SPECIAL|CLASS_SYSTEM|CLASS_UNLOADED)) ) {309io_write_class_unload(info->serial_num, info->object_index);310info->status |= CLASS_UNLOADED;311delete_classref((JNIEnv*)arg, info, NULL);312}313}314}315316/* External interfaces */317318void319class_init(void)320{321HPROF_ASSERT(gdata->class_table==NULL);322gdata->class_table = table_initialize("Class", 512, 512, 511,323(int)sizeof(ClassInfo));324}325326ClassIndex327class_find_or_create(const char *sig, LoaderIndex loader_index)328{329ClassKey key;330331fillin_pkey(sig, loader_index, &key);332return find_or_create_entry(&key);333}334335ClassIndex336class_create(const char *sig, LoaderIndex loader_index)337{338ClassKey key;339340fillin_pkey(sig, loader_index, &key);341return create_entry(&key);342}343344void345class_prime_system_classes(void)346{347/* Prime System classes? Anything before VM_START is System class.348* Or classes loaded before env arg is non-NULL.349* Or any of the classes listed below.350*/351static const char * signatures[] =352{353"Ljava/lang/Object;",354"Ljava/io/Serializable;",355"Ljava/lang/String;",356"Ljava/lang/Class;",357"Ljava/lang/ClassLoader;",358"Ljava/lang/System;",359"Ljava/lang/Thread;",360"Ljava/lang/ThreadGroup;",361};362int n_signatures;363int i;364LoaderIndex loader_index;365366n_signatures = (int)sizeof(signatures)/(int)sizeof(signatures[0]);367loader_index = loader_find_or_create(NULL, NULL);368for ( i = 0 ; i < n_signatures ; i++ ) {369ClassInfo *info;370ClassIndex index;371ClassKey key;372373fillin_pkey(signatures[i], loader_index, &key);374index = find_or_create_entry(&key);375info = get_info(index);376info->status |= CLASS_SYSTEM;377}378}379380void381class_add_status(ClassIndex index, ClassStatus status)382{383ClassInfo *info;384385info = get_info(index);386info->status |= status;387}388389ClassStatus390class_get_status(ClassIndex index)391{392ClassInfo *info;393394info = get_info(index);395return info->status;396}397398StringIndex399class_get_signature(ClassIndex index)400{401ClassKey *pkey;402403pkey = get_pkey(index);404return pkey->sig_string_index;405}406407SerialNumber408class_get_serial_number(ClassIndex index)409{410ClassInfo *info;411412if ( index == 0 ) {413return 0;414}415info = get_info(index);416return info->serial_num;417}418419void420class_all_status_remove(ClassStatus status)421{422table_walk_items(gdata->class_table, &all_status_remove,423(void*)(ptrdiff_t)(long)status);424}425426void427class_do_unloads(JNIEnv *env)428{429table_walk_items(gdata->class_table, &unload_walker, (void*)env);430}431432void433class_list(void)434{435debug_message(436"--------------------- Class Table ------------------------\n");437table_walk_items(gdata->class_table, &list_item, NULL);438debug_message(439"----------------------------------------------------------\n");440}441442void443class_cleanup(void)444{445table_cleanup(gdata->class_table, &cleanup_item, NULL);446gdata->class_table = NULL;447}448449void450class_delete_global_references(JNIEnv* env)451{452table_walk_items(gdata->class_table, &delete_ref_item, (void*)env);453}454455void456class_set_methods(ClassIndex index, const char **name, const char **sig,457int count)458{459ClassInfo *info;460int i;461462info = get_info(index);463if ( info->method_count > 0 ) {464HPROF_FREE((void*)info->method);465info->method_count = 0;466info->method = NULL;467}468info->method_count = count;469if ( count > 0 ) {470info->method = (MethodInfo *)HPROF_MALLOC(count*(int)sizeof(MethodInfo));471for ( i = 0 ; i < count ; i++ ) {472info->method[i].name_index = string_find_or_create(name[i]);473info->method[i].sig_index = string_find_or_create(sig[i]);474info->method[i].method_id = NULL;475}476}477}478479jclass480class_new_classref(JNIEnv *env, ClassIndex index, jclass classref)481{482ClassInfo *info;483484HPROF_ASSERT(classref!=NULL);485info = get_info(index);486if ( ! isSameObject(env, classref, info->classref) ) {487delete_classref(env, info, classref);488}489return info->classref;490}491492jclass493class_get_class(JNIEnv *env, ClassIndex index)494{495ClassInfo *info;496jclass clazz;497498info = get_info(index);499clazz = info->classref;500if ( env != NULL && clazz == NULL ) {501WITH_LOCAL_REFS(env, 1) {502jclass new_clazz;503char *class_name;504505class_name = string_get(info->name);506/* This really only makes sense for the bootclass classes,507* since FindClass doesn't provide a way to load a class in508* a specific class loader.509*/510new_clazz = findClass(env, class_name);511if ( new_clazz == NULL ) {512HPROF_ERROR(JNI_TRUE, "Cannot load class with findClass");513}514HPROF_ASSERT(new_clazz!=NULL);515clazz = class_new_classref(env, index, new_clazz);516} END_WITH_LOCAL_REFS;517HPROF_ASSERT(clazz!=NULL);518}519return clazz;520}521522jmethodID523class_get_methodID(JNIEnv *env, ClassIndex index, MethodIndex mnum)524{525ClassInfo *info;526jmethodID method;527528info = get_info(index);529if (mnum >= info->method_count) {530jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");531if ((*env)->ExceptionCheck(env)) {532(*env)->ExceptionClear(env);533HPROF_ERROR(JNI_TRUE,534"Could not find the java/lang/IllegalArgumentException class");535}536(*env)->ThrowNew(env, newExcCls, "Illegal mnum");537538return NULL;539}540method = info->method[mnum].method_id;541if ( method == NULL ) {542char * name;543char * sig;544jclass clazz;545546name = (char *)string_get(info->method[mnum].name_index);547if (name==NULL) {548jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");549if ((*env)->ExceptionCheck(env)) {550(*env)->ExceptionClear(env);551HPROF_ERROR(JNI_TRUE,552"Could not find the java/lang/IllegalArgumentException class");553}554(*env)->ThrowNew(env, newExcCls, "Name not found");555556return NULL;557}558sig = (char *)string_get(info->method[mnum].sig_index);559HPROF_ASSERT(sig!=NULL);560clazz = class_get_class(env, index);561if ( clazz != NULL ) {562method = getMethodID(env, clazz, name, sig);563HPROF_ASSERT(method!=NULL);564info = get_info(index);565info->method[mnum].method_id = method;566}567}568return method;569}570571void572class_set_inst_size(ClassIndex index, jint inst_size)573{574ClassInfo *info;575576info = get_info(index);577info->inst_size = inst_size;578}579580jint581class_get_inst_size(ClassIndex index)582{583ClassInfo *info;584585info = get_info(index);586return info->inst_size;587}588589void590class_set_object_index(ClassIndex index, ObjectIndex object_index)591{592ClassInfo *info;593594info = get_info(index);595info->object_index = object_index;596}597598ObjectIndex599class_get_object_index(ClassIndex index)600{601ClassInfo *info;602603info = get_info(index);604return info->object_index;605}606607ClassIndex608class_get_super(ClassIndex index)609{610ClassInfo *info;611612info = get_info(index);613return info->super;614}615616void617class_set_super(ClassIndex index, ClassIndex super)618{619ClassInfo *info;620621info = get_info(index);622info->super = super;623}624625LoaderIndex626class_get_loader(ClassIndex index)627{628ClassKey *pkey;629630pkey = get_pkey(index);631HPROF_ASSERT(pkey->loader_index!=0);632return pkey->loader_index;633}634635/* Get ALL class fields (supers too), return 1 on error, 0 if ok */636jint637class_get_all_fields(JNIEnv *env, ClassIndex index,638jint *pfield_count, FieldInfo **pfield)639{640ClassInfo *info;641FieldInfo *finfo;642jint count;643jint ret;644645count = 0;646finfo = NULL;647ret = 1; /* Default is to return an error condition */648649info = get_info(index);650if ( info != NULL ) {651if ( info->field_count >= 0 ) {652/* Get cache */653count = info->field_count;654finfo = info->field;655ret = 0; /* Return of cache data, no error */656} else {657jclass klass;658659klass = info->classref;660if ( klass == NULL || isSameObject(env, klass, NULL) ) {661/* This is probably an error because this will cause the field662* index values to be off, but I'm hesitant to generate a663* fatal error here, so I will issue something and continue.664* I should have been holding a global reference to all the665* jclass, so I'm not sure how this could happen.666* Issuing a FindClass() here is just asking for trouble667* because if the class went away, we aren't even sure668* what ClassLoader to use.669*/670HPROF_ERROR(JNI_FALSE, "Missing jclass when fields needed");671} else {672jint status;673674status = getClassStatus(klass);675if ( status &676(JVMTI_CLASS_STATUS_PRIMITIVE|JVMTI_CLASS_STATUS_ARRAY) ) {677/* Set cache */678info->field_count = count;679info->field = finfo;680ret = 0; /* Primitive or array ok */681} else if ( status & JVMTI_CLASS_STATUS_PREPARED ) {682/* Call JVMTI to get them */683getAllClassFieldInfo(env, klass, &count, &finfo);684/* Set cache */685info->field_count = count;686info->field = finfo;687ret = 0;688}689}690}691}692*pfield_count = count;693*pfield = finfo;694return ret;695}696697698