alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (hprof_class.c)

This example Java source code file (hprof_class.c) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

classindex, classinfo, classkey, classstatus, fieldinfo, hprof_assert, hprof_free, loaderindex, method, methodinfo, name, null, objectindex, stringindex

The hprof_class.c Java example source code

/*
 * Copyright (c) 2003, 2013, 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.
 */


/* Table of class information.
 *
 *   Each element in this table is identified with a ClassIndex.
 *   Each element is uniquely identified by it's signature and loader.
 *   Every class load has a unique class serial number.
 *   While loaded, each element will have a cache of a global reference
 *     to it's jclass object, plus jmethodID's as needed.
 *   Method signatures and names are obtained via BCI.
 *   Methods can be identified with a ClassIndex and MethodIndex pair,
 *     where the MethodIndex matches the index of the method name and
 *     signature arrays obtained from the BCI pass.
 *   Strings are stored in the string table and a StringIndex is used.
 *   Class Loaders are stored in the loader table and a LoaderIndex is used.
 *   Since the jclass object is an object, at some point an object table
 *      entry may be allocated for the jclass as an ObjectIndex.
 */

#include "hprof.h"

/* Effectively represents a jclass object. */

/* These table elements are made unique by and sorted by signature name. */

typedef struct ClassKey {
    StringIndex    sig_string_index;    /* Signature of class */
    LoaderIndex    loader_index;        /* Index for class loader */
} ClassKey;

/* Each class could contain method information, gotten from BCI callback */

typedef struct MethodInfo {
    StringIndex  name_index;    /* Method name, index into string table */
    StringIndex  sig_index;     /* Method signature, index into string table */
    jmethodID    method_id;     /* Method ID, possibly NULL at first */
} MethodInfo;

/* The basic class information we save */

typedef struct ClassInfo {
    jclass         classref;            /* Global ref to jclass */
    MethodInfo    *method;              /* Array of method data */
    int            method_count;        /* Count of methods */
    ObjectIndex    object_index;        /* Optional object index for jclass */
    SerialNumber   serial_num;          /* Unique to the actual class load */
    ClassStatus    status;              /* Current class status (bit mask) */
    ClassIndex     super;               /* Super class in this table */
    StringIndex    name;                /* Name of class */
    jint           inst_size;           /* #bytes needed for instance fields */
    jint           field_count;         /* Number of all fields */
    FieldInfo     *field;               /* Pointer to all FieldInfo's */
} ClassInfo;

/* Private interfaces */

static ClassKey*
get_pkey(ClassIndex index)
{
    void *key_ptr;
    int   key_len;

    table_get_key(gdata->class_table, index, (void*)&key_ptr, &key_len);
    HPROF_ASSERT(key_len==sizeof(ClassKey));
    HPROF_ASSERT(key_ptr!=NULL);
    return (ClassKey*)key_ptr;
}

static void
fillin_pkey(const char *sig, LoaderIndex loader_index, ClassKey *pkey)
{
    static ClassKey empty_key;

    HPROF_ASSERT(loader_index!=0);
    *pkey                  = empty_key;
    pkey->sig_string_index = string_find_or_create(sig);
    pkey->loader_index     = loader_index;
}

static ClassInfo *
get_info(ClassIndex index)
{
    ClassInfo *info;

    info = (ClassInfo*)table_get_info(gdata->class_table, index);
    return info;
}

static void
fill_info(TableIndex index, ClassKey *pkey)
{
    ClassInfo *info;
    char      *sig;

    info = get_info(index);
    info->serial_num = gdata->class_serial_number_counter++;
    info->method_count = 0;
    info->inst_size = -1;
    info->field_count = -1;
    info->field = NULL;
    sig = string_get(pkey->sig_string_index);
    if ( sig[0] != JVM_SIGNATURE_CLASS ) {
        info->name = pkey->sig_string_index;
    } else {
        int        len;

        len = string_get_len(pkey->sig_string_index);
        if ( len > 2  ) {
            char      *name;

            /* Class signature looks like "Lname;", we want "name" here. */
            name = HPROF_MALLOC(len-1);
            (void)memcpy(name, sig+1, len-2);
            name[len-2] = 0;
            info->name = string_find_or_create(name);
            HPROF_FREE(name);
        } else {
            /* This would be strange, a class signature not in "Lname;" form? */
            info->name = pkey->sig_string_index;
        }
   }
}

static ClassIndex
find_entry(ClassKey *pkey)
{
    ClassIndex index;

    index = table_find_entry(gdata->class_table,
                                (void*)pkey, (int)sizeof(ClassKey));
    return index;
}

static ClassIndex
create_entry(ClassKey *pkey)
{
    ClassIndex index;

    index = table_create_entry(gdata->class_table,
                                (void*)pkey, (int)sizeof(ClassKey), NULL);
    fill_info(index, pkey);
    return index;
}

static ClassIndex
find_or_create_entry(ClassKey *pkey)
{
    ClassIndex      index;

    HPROF_ASSERT(pkey!=NULL);
    HPROF_ASSERT(pkey->loader_index!=0);
    index = find_entry(pkey);
    if ( index == 0 ) {
        index = create_entry(pkey);
    }
    return index;
}

static void
delete_classref(JNIEnv *env, ClassInfo *info, jclass klass)
{
    jclass ref;
    int    i;

    HPROF_ASSERT(env!=NULL);
    HPROF_ASSERT(info!=NULL);

    for ( i = 0 ; i < info->method_count ; i++ ) {
        info->method[i].method_id  = NULL;
    }
    ref = info->classref;
    if ( klass != NULL ) {
        info->classref = newGlobalReference(env, klass);
    } else {
        info->classref = NULL;
    }
    if ( ref != NULL ) {
        deleteGlobalReference(env, ref);
    }
}

static void
cleanup_item(TableIndex index, void *key_ptr, int key_len,
                                void *info_ptr, void *arg)
{
    ClassInfo *info;

    /* Cleanup any information in this ClassInfo structure. */
    HPROF_ASSERT(key_ptr!=NULL);
    HPROF_ASSERT(key_len==sizeof(ClassKey));
    HPROF_ASSERT(info_ptr!=NULL);
    info = (ClassInfo *)info_ptr;
    if ( info->method_count > 0 ) {
        HPROF_FREE((void*)info->method);
        info->method_count = 0;
        info->method       = NULL;
    }
    if ( info->field != NULL ) {
        HPROF_FREE((void*)info->field);
        info->field_count = 0;
        info->field      = NULL;
    }
}

static void
delete_ref_item(TableIndex index, void *key_ptr, int key_len,
                                void *info_ptr, void *arg)
{
    delete_classref((JNIEnv*)arg, (ClassInfo*)info_ptr, NULL);
}

static void
list_item(TableIndex index, void *key_ptr, int key_len,
                                void *info_ptr, void *arg)
{
    ClassInfo *info;
    ClassKey   key;
    char      *sig;
    int        i;

    HPROF_ASSERT(key_ptr!=NULL);
    HPROF_ASSERT(key_len==sizeof(ClassKey));
    HPROF_ASSERT(info_ptr!=NULL);
    key = *((ClassKey*)key_ptr);
    sig = string_get(key.sig_string_index);
    info = (ClassInfo *)info_ptr;
    debug_message(
             "0x%08x: Class %s, SN=%u, status=0x%08x, ref=%p,"
             " method_count=%d\n",
             index,
             (const char *)sig,
             info->serial_num,
             info->status,
             (void*)info->classref,
             info->method_count);
    if ( info->method_count > 0 ) {
        for ( i = 0 ; i < info->method_count ; i++ ) {
            debug_message(
                "    Method %d: \"%s\", sig=\"%s\", method=%p\n",
                i,
                string_get(info->method[i].name_index),
                string_get(info->method[i].sig_index),
                (void*)info->method[i].method_id);
        }
    }
}

static void
all_status_remove(TableIndex index, void *key_ptr, int key_len,
                                void *info_ptr, void *arg)
{
    ClassInfo   *info;
    ClassStatus  status;

    HPROF_ASSERT(info_ptr!=NULL);
    /*LINTED*/
    status = (ClassStatus)(long)(ptrdiff_t)arg;
    info = (ClassInfo *)info_ptr;
    info->status &= (~status);
}

static void
unload_walker(TableIndex index, void *key_ptr, int key_len,
                                void *info_ptr, void *arg)
{
    ClassInfo        *info;

    HPROF_ASSERT(info_ptr!=NULL);
    info = (ClassInfo *)info_ptr;
    if ( ! ( info->status & CLASS_IN_LOAD_LIST ) ) {
        if ( ! (info->status & (CLASS_SPECIAL|CLASS_SYSTEM|CLASS_UNLOADED)) ) {
            io_write_class_unload(info->serial_num, info->object_index);
            info->status |= CLASS_UNLOADED;
            delete_classref((JNIEnv*)arg, info, NULL);
        }
    }
}

/* External interfaces */

void
class_init(void)
{
    HPROF_ASSERT(gdata->class_table==NULL);
    gdata->class_table = table_initialize("Class", 512, 512, 511,
                                    (int)sizeof(ClassInfo));
}

ClassIndex
class_find_or_create(const char *sig, LoaderIndex loader_index)
{
    ClassKey key;

    fillin_pkey(sig, loader_index, &key);
    return find_or_create_entry(&key);
}

ClassIndex
class_create(const char *sig, LoaderIndex loader_index)
{
    ClassKey key;

    fillin_pkey(sig, loader_index, &key);
    return create_entry(&key);
}

void
class_prime_system_classes(void)
{
    /* Prime System classes? Anything before VM_START is System class.
     *   Or classes loaded before env arg is non-NULL.
     *   Or any of the classes listed below.
     */
    static const char * signatures[] =
        {
            "Ljava/lang/Object;",
            "Ljava/io/Serializable;",
            "Ljava/lang/String;",
            "Ljava/lang/Class;",
            "Ljava/lang/ClassLoader;",
            "Ljava/lang/System;",
            "Ljava/lang/Thread;",
            "Ljava/lang/ThreadGroup;",
        };
    int n_signatures;
    int i;
    LoaderIndex loader_index;

    n_signatures = (int)sizeof(signatures)/(int)sizeof(signatures[0]);
    loader_index = loader_find_or_create(NULL, NULL);
    for ( i = 0 ; i < n_signatures ; i++ ) {
        ClassInfo  *info;
        ClassIndex  index;
        ClassKey    key;

        fillin_pkey(signatures[i], loader_index, &key);
        index = find_or_create_entry(&key);
        info = get_info(index);
        info->status |= CLASS_SYSTEM;
    }
}

void
class_add_status(ClassIndex index, ClassStatus status)
{
    ClassInfo *info;

    info = get_info(index);
    info->status |= status;
}

ClassStatus
class_get_status(ClassIndex index)
{
    ClassInfo *info;

    info = get_info(index);
    return info->status;
}

StringIndex
class_get_signature(ClassIndex index)
{
    ClassKey *pkey;

    pkey = get_pkey(index);
    return pkey->sig_string_index;
}

SerialNumber
class_get_serial_number(ClassIndex index)
{
    ClassInfo *info;

    if ( index == 0 ) {
        return 0;
    }
    info = get_info(index);
    return info->serial_num;
}

void
class_all_status_remove(ClassStatus status)
{
    table_walk_items(gdata->class_table, &all_status_remove,
                (void*)(ptrdiff_t)(long)status);
}

void
class_do_unloads(JNIEnv *env)
{
    table_walk_items(gdata->class_table, &unload_walker, (void*)env);
}

void
class_list(void)
{
    debug_message(
        "--------------------- Class Table ------------------------\n");
    table_walk_items(gdata->class_table, &list_item, NULL);
    debug_message(
        "----------------------------------------------------------\n");
}

void
class_cleanup(void)
{
    table_cleanup(gdata->class_table, &cleanup_item, NULL);
    gdata->class_table = NULL;
}

void
class_delete_global_references(JNIEnv* env)
{
    table_walk_items(gdata->class_table, &delete_ref_item, (void*)env);
}

void
class_set_methods(ClassIndex index, const char **name, const char **sig,
                        int count)
{
    ClassInfo *info;
    int        i;

    info               = get_info(index);
    if ( info->method_count > 0 ) {
        HPROF_FREE((void*)info->method);
        info->method_count = 0;
        info->method       = NULL;
    }
    info->method_count = count;
    if ( count > 0 ) {
        info->method = (MethodInfo *)HPROF_MALLOC(count*(int)sizeof(MethodInfo));
        for ( i = 0 ; i < count ; i++ ) {
            info->method[i].name_index = string_find_or_create(name[i]);
            info->method[i].sig_index  = string_find_or_create(sig[i]);
            info->method[i].method_id  = NULL;
        }
    }
}

jclass
class_new_classref(JNIEnv *env, ClassIndex index, jclass classref)
{
    ClassInfo *info;

    HPROF_ASSERT(classref!=NULL);
    info = get_info(index);
    if ( ! isSameObject(env, classref, info->classref) ) {
        delete_classref(env, info, classref);
    }
    return info->classref;
}

jclass
class_get_class(JNIEnv *env, ClassIndex index)
{
    ClassInfo *info;
    jclass     clazz;

    info        = get_info(index);
    clazz       = info->classref;
    if ( env != NULL && clazz == NULL ) {
        WITH_LOCAL_REFS(env, 1) {
            jclass   new_clazz;
            char    *class_name;

            class_name = string_get(info->name);
            /* This really only makes sense for the bootclass classes,
             *   since FindClass doesn't provide a way to load a class in
             *   a specific class loader.
             */
            new_clazz = findClass(env, class_name);
            if ( new_clazz == NULL ) {
                HPROF_ERROR(JNI_TRUE, "Cannot load class with findClass");
            }
            HPROF_ASSERT(new_clazz!=NULL);
            clazz = class_new_classref(env, index, new_clazz);
        } END_WITH_LOCAL_REFS;
        HPROF_ASSERT(clazz!=NULL);
    }
    return clazz;
}

jmethodID
class_get_methodID(JNIEnv *env, ClassIndex index, MethodIndex mnum)
{
    ClassInfo *info;
    jmethodID  method;

    info = get_info(index);
    if (mnum >= info->method_count) {
        jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
        (*env)->ThrowNew(env, newExcCls, "Illegal mnum");

        return NULL;
    }
    method = info->method[mnum].method_id;
    if ( method == NULL ) {
        char * name;
        char * sig;
        jclass clazz;

        name  = (char *)string_get(info->method[mnum].name_index);
        if (name==NULL) {
            jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
            (*env)->ThrowNew(env, newExcCls, "Name not found");

            return NULL;
        }
        sig   = (char *)string_get(info->method[mnum].sig_index);
        HPROF_ASSERT(sig!=NULL);
        clazz = class_get_class(env, index);
        if ( clazz != NULL ) {
            method = getMethodID(env, clazz, name, sig);
            HPROF_ASSERT(method!=NULL);
            info = get_info(index);
            info->method[mnum].method_id = method;
        }
    }
    return method;
}

void
class_set_inst_size(ClassIndex index, jint inst_size)
{
    ClassInfo *info;

    info = get_info(index);
    info->inst_size = inst_size;
}

jint
class_get_inst_size(ClassIndex index)
{
    ClassInfo *info;

    info = get_info(index);
    return info->inst_size;
}

void
class_set_object_index(ClassIndex index, ObjectIndex object_index)
{
    ClassInfo *info;

    info = get_info(index);
    info->object_index = object_index;
}

ObjectIndex
class_get_object_index(ClassIndex index)
{
    ClassInfo *info;

    info = get_info(index);
    return info->object_index;
}

ClassIndex
class_get_super(ClassIndex index)
{
    ClassInfo *info;

    info = get_info(index);
    return info->super;
}

void
class_set_super(ClassIndex index, ClassIndex super)
{
    ClassInfo *info;

    info = get_info(index);
    info->super = super;
}

LoaderIndex
class_get_loader(ClassIndex index)
{
    ClassKey *pkey;

    pkey = get_pkey(index);
    HPROF_ASSERT(pkey->loader_index!=0);
    return pkey->loader_index;
}

/* Get ALL class fields (supers too), return 1 on error, 0 if ok */
jint
class_get_all_fields(JNIEnv *env, ClassIndex index,
                jint *pfield_count, FieldInfo **pfield)
{
    ClassInfo  *info;
    FieldInfo  *finfo;
    jint        count;
    jint        ret;

    count = 0;
    finfo = NULL;
    ret   = 1;       /* Default is to return an error condition */

    info = get_info(index);
    if ( info != NULL ) {
        if ( info->field_count >= 0 ) {
            /* Get cache */
            count = info->field_count;
            finfo = info->field;
            ret   = 0;                 /* Return of cache data, no error */
        } else {
            jclass     klass;

            klass = info->classref;
            if ( klass == NULL || isSameObject(env, klass, NULL) ) {
                /* This is probably an error because this will cause the field
                 *    index values to be off, but I'm hesitant to generate a
                 *    fatal error here, so I will issue something and continue.
                 *    I should have been holding a global reference to all the
                 *    jclass, so I'm not sure how this could happen.
                 *    Issuing a FindClass() here is just asking for trouble
                 *    because if the class went away, we aren't even sure
                 *    what ClassLoader to use.
                 */
                HPROF_ERROR(JNI_FALSE, "Missing jclass when fields needed");
            } else {
                jint status;

                status = getClassStatus(klass);
                if ( status &
                    (JVMTI_CLASS_STATUS_PRIMITIVE|JVMTI_CLASS_STATUS_ARRAY) ) {
                    /* Set cache */
                    info->field_count = count;
                    info->field       = finfo;
                    ret               = 0;      /* Primitive or array ok */
                } else if ( status & JVMTI_CLASS_STATUS_PREPARED ) {
                    /* Call JVMTI to get them */
                    getAllClassFieldInfo(env, klass, &count, &finfo);
                    /* Set cache */
                    info->field_count = count;
                    info->field       = finfo;
                    ret               = 0;
                }
            }
        }
    }
    *pfield_count = count;
    *pfield       = finfo;
    return ret;
}

Other Java examples (source code examples)

Here is a short list of links related to this Java hprof_class.c source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.