/*
* Copyright (c) 2003, 2005, 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.
*/
/* Object references table (used in hprof_object.c). */
/*
* This table is used by the object table to store object reference
* and primitive data information obtained from iterations over the
* heap (see hprof_site.c).
*
* Most of these table entries have no Key, but the key is used to store
* the primitive array and primitive field jvalue. None of these entries
* are ever looked up, there will be no hash table, use of the
* LookupTable was just an easy way to handle a unbounded table of
* entries. The object table (see hprof_object.c) will completely
* free this reference table after each heap dump or after processing the
* references and primitive data.
*
* The hprof format required this accumulation of all heap iteration
* references and primitive data from objects in order to compose an
* hprof records for it.
*
* This file contains detailed understandings of how an hprof CLASS
* and INSTANCE dump is constructed, most of this is derived from the
* original hprof code, but some has been derived by reading the HAT
* code that accepts this format.
*
*/
#include "hprof.h"
/* The flavor of data being saved in the RefInfo */
enum {
INFO_OBJECT_REF_DATA = 1,
INFO_PRIM_FIELD_DATA = 2,
INFO_PRIM_ARRAY_DATA = 3
};
/* Reference information, object reference or primitive data information */
typedef struct RefInfo {
ObjectIndex object_index; /* If an object reference, the referree index */
jint index; /* If array or field, array or field index */
jint length; /* If array the element count, if not -1 */
RefIndex next; /* The next table element */
unsigned flavor : 8; /* INFO_*, flavor of RefInfo */
unsigned refKind : 8; /* The kind of reference */
unsigned primType : 8; /* If primitive data involved, it's type */
} RefInfo;
/* Private internal functions. */
/* Get the RefInfo structure from an entry */
static RefInfo *
get_info(RefIndex index)
{
RefInfo *info;
info = (RefInfo*)table_get_info(gdata->reference_table, index);
return info;
}
/* Get a jvalue that was stored as the key. */
static jvalue
get_key_value(RefIndex index)
{
void *key;
int len;
jvalue value;
static jvalue empty_value;
key = NULL;
table_get_key(gdata->reference_table, index, &key, &len);
HPROF_ASSERT(key!=NULL);
HPROF_ASSERT(len==(int)sizeof(jvalue));
if ( key != NULL ) {
(void)memcpy(&value, key, (int)sizeof(jvalue));
} else {
value = empty_value;
}
return value;
}
/* Get size of a primitive type */
static jint
get_prim_size(jvmtiPrimitiveType primType)
{
jint size;
switch ( primType ) {
case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
size = (jint)sizeof(jboolean);
break;
case JVMTI_PRIMITIVE_TYPE_BYTE:
size = (jint)sizeof(jbyte);
break;
case JVMTI_PRIMITIVE_TYPE_CHAR:
size = (jint)sizeof(jchar);
break;
case JVMTI_PRIMITIVE_TYPE_SHORT:
size = (jint)sizeof(jshort);
break;
case JVMTI_PRIMITIVE_TYPE_INT:
size = (jint)sizeof(jint);
break;
case JVMTI_PRIMITIVE_TYPE_FLOAT:
size = (jint)sizeof(jfloat);
break;
case JVMTI_PRIMITIVE_TYPE_LONG:
size = (jint)sizeof(jlong);
break;
case JVMTI_PRIMITIVE_TYPE_DOUBLE:
size = (jint)sizeof(jdouble);
break;
default:
HPROF_ASSERT(0);
size = 1;
break;
}
return size;
}
/* Get a void* elements array that was stored as the key. */
static void *
get_key_elements(RefIndex index, jvmtiPrimitiveType primType,
jint *nelements, jint *nbytes)
{
void *key;
jint byteLen;
HPROF_ASSERT(nelements!=NULL);
HPROF_ASSERT(nbytes!=NULL);
table_get_key(gdata->reference_table, index, &key, &byteLen);
HPROF_ASSERT(byteLen>=0);
HPROF_ASSERT(byteLen!=0?key!=NULL:key==NULL);
*nbytes = byteLen;
*nelements = byteLen / get_prim_size(primType);
return key;
}
/* Dump a RefInfo* structure */
static void
dump_ref_info(RefInfo *info)
{
debug_message("[%d]: flavor=%d"
", refKind=%d"
", primType=%d"
", object_index=0x%x"
", length=%d"
", next=0x%x"
"\n",
info->index,
info->flavor,
info->refKind,
info->primType,
info->object_index,
info->length,
info->next);
}
/* Dump a RefIndex list */
static void
dump_ref_list(RefIndex list)
{
RefInfo *info;
RefIndex index;
debug_message("\nFOLLOW REFERENCES RETURNED:\n");
index = list;
while ( index != 0 ) {
info = get_info(index);
dump_ref_info(info);
index = info->next;
}
}
/* Dump information about a field and what ref data we had on it */
static void
dump_field(FieldInfo *fields, jvalue *fvalues, int n_fields,
jint index, jvalue value, jvmtiPrimitiveType primType)
{
ClassIndex cnum;
StringIndex name;
StringIndex sig;
cnum = fields[index].cnum;
name = fields[index].name_index;
sig = fields[index].sig_index;
debug_message("[%d] %s \"%s\" \"%s\"",
index,
cnum!=0?string_get(class_get_signature(cnum)):"?",
name!=0?string_get(name):"?",
sig!=0?string_get(sig):"?");
if ( fields[index].primType!=0 || fields[index].primType!=primType ) {
debug_message(" (primType=%d(%c)",
fields[index].primType,
primTypeToSigChar(fields[index].primType));
if ( primType != fields[index].primType ) {
debug_message(", got %d(%c)",
primType,
primTypeToSigChar(primType));
}
debug_message(")");
} else {
debug_message("(ty=OBJ)");
}
if ( value.j != (jlong)0 || fvalues[index].j != (jlong)0 ) {
debug_message(" val=[0x%08x,0x%08x] or [0x%08x,0x%08x]",
jlong_high(value.j), jlong_low(value.j),
jlong_high(fvalues[index].j), jlong_low(fvalues[index].j));
}
debug_message("\n");
}
/* Dump all the fields of interest */
static void
dump_fields(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields)
{
int i;
debug_message("\nHPROF LIST OF ALL FIELDS:\n");
for ( i = 0 ; i < n_fields ; i++ ) {
if ( fields[i].name_index != 0 ) {
dump_field(fields, fvalues, n_fields, i, fvalues[i], fields[i].primType);
}
}
dump_ref_list(list);
}
/* Verify field data */
static void
verify_field(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields,
jint index, jvalue value, jvmtiPrimitiveType primType)
{
HPROF_ASSERT(fvalues != NULL);
HPROF_ASSERT(n_fields > 0);
HPROF_ASSERT(index < n_fields);
HPROF_ASSERT(index >= 0 );
if ( primType!=fields[index].primType ) {
dump_fields(list, fields, fvalues, n_fields);
debug_message("\nPROBLEM WITH:\n");
dump_field(fields, fvalues, n_fields, index, value, primType);
debug_message("\n");
HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data");
}
if ( primType == JVMTI_PRIMITIVE_TYPE_BOOLEAN &&
( value.b != 1 && value.b != 0 ) ) {
dump_fields(list, fields, fvalues, n_fields);
debug_message("\nPROBLEM WITH:\n");
dump_field(fields, fvalues, n_fields, index, value, primType);
debug_message("\n");
HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data");
}
}
/* Fill in a field value, making sure the index is safe */
static void
fill_in_field_value(RefIndex list, FieldInfo *fields, jvalue *fvalues,
int n_fields, jint index, jvalue value,
jvmtiPrimitiveType primType)
{
HPROF_ASSERT(fvalues != NULL);
HPROF_ASSERT(n_fields > 0);
HPROF_ASSERT(index < n_fields);
HPROF_ASSERT(index >= 0 );
HPROF_ASSERT(fvalues[index].j==(jlong)0);
verify_field(list, fields, fvalues, n_fields, index, value, primType);
if (index >= 0 && index < n_fields) {
fvalues[index] = value;
}
}
/* Walk all references for an ObjectIndex and construct the hprof CLASS dump. */
static void
dump_class_and_supers(JNIEnv *env, ObjectIndex object_index, RefIndex list)
{
SiteIndex site_index;
SerialNumber trace_serial_num;
RefIndex index;
ClassIndex super_cnum;
ObjectIndex super_index;
LoaderIndex loader_index;
ObjectIndex signers_index;
ObjectIndex domain_index;
FieldInfo *fields;
jvalue *fvalues;
jint n_fields;
jboolean skip_fields;
jint n_fields_set;
jlong size;
ClassIndex cnum;
char *sig;
ObjectKind kind;
TraceIndex trace_index;
Stack *cpool_values;
ConstantPoolValue *cpool;
jint cpool_count;
HPROF_ASSERT(object_index!=0);
kind = object_get_kind(object_index);
if ( kind != OBJECT_CLASS ) {
return;
}
site_index = object_get_site(object_index);
HPROF_ASSERT(site_index!=0);
cnum = site_get_class_index(site_index);
HPROF_ASSERT(cnum!=0);
if ( class_get_status(cnum) & CLASS_DUMPED ) {
return;
}
class_add_status(cnum, CLASS_DUMPED);
size = (jlong)object_get_size(object_index);
super_index = 0;
super_cnum = class_get_super(cnum);
if ( super_cnum != 0 ) {
super_index = class_get_object_index(super_cnum);
if ( super_index != 0 ) {
dump_class_and_supers(env, super_index,
object_get_references(super_index));
}
}
trace_index = site_get_trace_index(site_index);
HPROF_ASSERT(trace_index!=0);
trace_serial_num = trace_get_serial_number(trace_index);
sig = string_get(class_get_signature(cnum));
loader_index = class_get_loader(cnum);
signers_index = 0;
domain_index = 0;
/* Get field information */
n_fields = 0;
skip_fields = JNI_FALSE;
n_fields_set = 0;
fields = NULL;
fvalues = NULL;
if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) {
/* Problems getting all the fields, can't trust field index values */
skip_fields = JNI_TRUE;
/* Class with no references at all? (ok to be unprepared if list==0?) */
if ( list != 0 ) {
/* It is assumed that the reason why we didn't get the fields
* was because the class is not prepared.
*/
if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) {
dump_ref_list(list);
debug_message("Unprepared class with references: %s\n",
sig);
}
HPROF_ERROR(JNI_FALSE, "Trouble with unprepared classes");
}
/* Why would an unprepared class contain references? */
}
if ( n_fields > 0 ) {
fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue));
(void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue));
}
/* We use a Stack just because it will automatically expand as needed */
cpool_values = stack_init(16, 16, sizeof(ConstantPoolValue));
cpool = NULL;
cpool_count = 0;
index = list;
while ( index != 0 ) {
RefInfo *info;
jvalue ovalue;
static jvalue empty_value;
info = get_info(index);
switch ( info->flavor ) {
case INFO_OBJECT_REF_DATA:
switch ( info->refKind ) {
case JVMTI_HEAP_REFERENCE_FIELD:
case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
/* Should never be seen on a class dump */
HPROF_ASSERT(0);
break;
case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
if ( skip_fields == JNI_TRUE ) {
break;
}
ovalue = empty_value;
ovalue.i = info->object_index;
fill_in_field_value(list, fields, fvalues, n_fields,
info->index, ovalue, 0);
n_fields_set++;
HPROF_ASSERT(n_fields_set <= n_fields);
break;
case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: {
ConstantPoolValue cpv;
ObjectIndex cp_object_index;
SiteIndex cp_site_index;
ClassIndex cp_cnum;
cp_object_index = info->object_index;
HPROF_ASSERT(cp_object_index!=0);
cp_site_index = object_get_site(cp_object_index);
HPROF_ASSERT(cp_site_index!=0);
cp_cnum = site_get_class_index(cp_site_index);
cpv.constant_pool_index = info->index;
cpv.sig_index = class_get_signature(cp_cnum);
cpv.value.i = cp_object_index;
stack_push(cpool_values, (void*)&cpv);
cpool_count++;
break;
}
case JVMTI_HEAP_REFERENCE_SIGNERS:
signers_index = info->object_index;
break;
case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
domain_index = info->object_index;
break;
case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
case JVMTI_HEAP_REFERENCE_INTERFACE:
default:
/* Ignore, not needed */
break;
}
break;
case INFO_PRIM_FIELD_DATA:
if ( skip_fields == JNI_TRUE ) {
break;
}
HPROF_ASSERT(info->primType!=0);
HPROF_ASSERT(info->length==-1);
HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_STATIC_FIELD);
ovalue = get_key_value(index);
fill_in_field_value(list, fields, fvalues, n_fields,
info->index, ovalue, info->primType);
n_fields_set++;
HPROF_ASSERT(n_fields_set <= n_fields);
break;
case INFO_PRIM_ARRAY_DATA:
default:
/* Should never see these */
HPROF_ASSERT(0);
break;
}
index = info->next;
}
/* Get constant pool data if we have any */
HPROF_ASSERT(cpool_count==stack_depth(cpool_values));
if ( cpool_count > 0 ) {
cpool = (ConstantPoolValue*)stack_element(cpool_values, 0);
}
io_heap_class_dump(cnum, sig, object_index, trace_serial_num,
super_index,
loader_object_index(env, loader_index),
signers_index, domain_index,
(jint)size, cpool_count, cpool, n_fields, fields, fvalues);
stack_term(cpool_values);
if ( fvalues != NULL ) {
HPROF_FREE(fvalues);
}
}
/* Walk all references for an ObjectIndex and construct the hprof INST dump. */
static void
dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list)
{
jvmtiPrimitiveType primType;
SiteIndex site_index;
SerialNumber trace_serial_num;
RefIndex index;
ObjectIndex class_index;
jlong size;
ClassIndex cnum;
char *sig;
void *elements;
jint num_elements;
jint num_bytes;
ObjectIndex *values;
FieldInfo *fields;
jvalue *fvalues;
jint n_fields;
jboolean skip_fields;
jint n_fields_set;
ObjectKind kind;
TraceIndex trace_index;
jboolean is_array;
jboolean is_prim_array;
HPROF_ASSERT(object_index!=0);
kind = object_get_kind(object_index);
if ( kind == OBJECT_CLASS ) {
return;
}
site_index = object_get_site(object_index);
HPROF_ASSERT(site_index!=0);
cnum = site_get_class_index(site_index);
HPROF_ASSERT(cnum!=0);
size = (jlong)object_get_size(object_index);
trace_index = site_get_trace_index(site_index);
HPROF_ASSERT(trace_index!=0);
trace_serial_num = trace_get_serial_number(trace_index);
sig = string_get(class_get_signature(cnum));
class_index = class_get_object_index(cnum);
values = NULL;
elements = NULL;
num_elements = 0;
num_bytes = 0;
n_fields = 0;
skip_fields = JNI_FALSE;
n_fields_set = 0;
fields = NULL;
fvalues = NULL;
index = list;
is_array = JNI_FALSE;
is_prim_array = JNI_FALSE;
if ( sig[0] != JVM_SIGNATURE_ARRAY ) {
if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) {
/* Trouble getting all the fields, can't trust field index values */
skip_fields = JNI_TRUE;
/* It is assumed that the reason why we didn't get the fields
* was because the class is not prepared.
*/
if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) {
if ( list != 0 ) {
dump_ref_list(list);
debug_message("Instance of unprepared class with refs: %s\n",
sig);
} else {
debug_message("Instance of unprepared class without refs: %s\n",
sig);
}
HPROF_ERROR(JNI_FALSE, "Big Trouble with unprepared class instances");
}
}
if ( n_fields > 0 ) {
fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue));
(void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue));
}
} else {
is_array = JNI_TRUE;
if ( sig[0] != 0 && sigToPrimSize(sig+1) != 0 ) {
is_prim_array = JNI_TRUE;
}
}
while ( index != 0 ) {
RefInfo *info;
jvalue ovalue;
static jvalue empty_value;
info = get_info(index);
/* Process reference objects, many not used right now. */
switch ( info->flavor ) {
case INFO_OBJECT_REF_DATA:
switch ( info->refKind ) {
case JVMTI_HEAP_REFERENCE_SIGNERS:
case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
case JVMTI_HEAP_REFERENCE_INTERFACE:
case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
/* Should never be seen on an instance dump */
HPROF_ASSERT(0);
break;
case JVMTI_HEAP_REFERENCE_FIELD:
if ( skip_fields == JNI_TRUE ) {
break;
}
HPROF_ASSERT(is_array!=JNI_TRUE);
ovalue = empty_value;
ovalue.i = info->object_index;
fill_in_field_value(list, fields, fvalues, n_fields,
info->index, ovalue, 0);
n_fields_set++;
HPROF_ASSERT(n_fields_set <= n_fields);
break;
case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
/* We get each object element one at a time. */
HPROF_ASSERT(is_array==JNI_TRUE);
HPROF_ASSERT(is_prim_array!=JNI_TRUE);
if ( num_elements <= info->index ) {
int nbytes;
if ( values == NULL ) {
num_elements = info->index + 1;
nbytes = num_elements*(int)sizeof(ObjectIndex);
values = (ObjectIndex*)HPROF_MALLOC(nbytes);
(void)memset(values, 0, nbytes);
} else {
void *new_values;
int new_size;
int obytes;
obytes = num_elements*(int)sizeof(ObjectIndex);
new_size = info->index + 1;
nbytes = new_size*(int)sizeof(ObjectIndex);
new_values = (void*)HPROF_MALLOC(nbytes);
(void)memcpy(new_values, values, obytes);
(void)memset(((char*)new_values)+obytes, 0,
nbytes-obytes);
HPROF_FREE(values);
num_elements = new_size;
values = new_values;
}
}
HPROF_ASSERT(values[info->index]==0);
values[info->index] = info->object_index;
break;
default:
/* Ignore, not needed */
break;
}
break;
case INFO_PRIM_FIELD_DATA:
if ( skip_fields == JNI_TRUE ) {
break;
}
HPROF_ASSERT(info->primType!=0);
HPROF_ASSERT(info->length==-1);
HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_FIELD);
HPROF_ASSERT(is_array!=JNI_TRUE);
ovalue = get_key_value(index);
fill_in_field_value(list, fields, fvalues, n_fields,
info->index, ovalue, info->primType);
n_fields_set++;
HPROF_ASSERT(n_fields_set <= n_fields);
break;
case INFO_PRIM_ARRAY_DATA:
/* Should only be one, and it's handled below */
HPROF_ASSERT(info->refKind==0);
/* We assert that nothing else was saved with this array */
HPROF_ASSERT(index==list&&info->next==0);
HPROF_ASSERT(is_array==JNI_TRUE);
HPROF_ASSERT(is_prim_array==JNI_TRUE);
primType = info->primType;
elements = get_key_elements(index, primType,
&num_elements, &num_bytes);
HPROF_ASSERT(info->length==num_elements);
size = num_bytes;
break;
default:
HPROF_ASSERT(0);
break;
}
index = info->next;
}
if ( is_array == JNI_TRUE ) {
if ( is_prim_array == JNI_TRUE ) {
HPROF_ASSERT(values==NULL);
io_heap_prim_array(object_index, trace_serial_num,
(jint)size, num_elements, sig, elements);
} else {
HPROF_ASSERT(elements==NULL);
io_heap_object_array(object_index, trace_serial_num,
(jint)size, num_elements, sig, values, class_index);
}
} else {
io_heap_instance_dump(cnum, object_index, trace_serial_num,
class_index, (jint)size, sig, fields, fvalues, n_fields);
}
if ( values != NULL ) {
HPROF_FREE(values);
}
if ( fvalues != NULL ) {
HPROF_FREE(fvalues);
}
if ( elements != NULL ) {
/* Do NOT free elements, it's a key in the table, leave it be */
}
}
/* External interfaces. */
void
reference_init(void)
{
HPROF_ASSERT(gdata->reference_table==NULL);
gdata->reference_table = table_initialize("Ref", 2048, 4096, 0,
(int)sizeof(RefInfo));
}
/* Save away a reference to an object */
RefIndex
reference_obj(RefIndex next, jvmtiHeapReferenceKind refKind,
ObjectIndex object_index, jint index, jint length)
{
static RefInfo empty_info;
RefIndex entry;
RefInfo info;
info = empty_info;
info.flavor = INFO_OBJECT_REF_DATA;
info.refKind = refKind;
info.object_index = object_index;
info.index = index;
info.length = length;
info.next = next;
entry = table_create_entry(gdata->reference_table, NULL, 0, (void*)&info);
return entry;
}
/* Save away some primitive field data */
RefIndex
reference_prim_field(RefIndex next, jvmtiHeapReferenceKind refKind,
jvmtiPrimitiveType primType, jvalue field_value, jint field_index)
{
static RefInfo empty_info;
RefIndex entry;
RefInfo info;
HPROF_ASSERT(primType==JVMTI_PRIMITIVE_TYPE_BOOLEAN?(field_value.b==1||field_value.b==0):1);
info = empty_info;
info.flavor = INFO_PRIM_FIELD_DATA;
info.refKind = refKind;
info.primType = primType;
info.index = field_index;
info.length = -1;
info.next = next;
entry = table_create_entry(gdata->reference_table,
(void*)&field_value, (int)sizeof(jvalue), (void*)&info);
return entry;
}
/* Save away some primitive array data */
RefIndex
reference_prim_array(RefIndex next, jvmtiPrimitiveType primType,
const void *elements, jint elementCount)
{
static RefInfo empty_info;
RefIndex entry;
RefInfo info;
HPROF_ASSERT(next == 0);
HPROF_ASSERT(elementCount >= 0);
HPROF_ASSERT(elements != NULL);
info = empty_info;
info.flavor = INFO_PRIM_ARRAY_DATA;
info.refKind = 0;
info.primType = primType;
info.index = 0;
info.length = elementCount;
info.next = next;
entry = table_create_entry(gdata->reference_table, (void*)elements,
elementCount * get_prim_size(primType), (void*)&info);
return entry;
}
void
reference_cleanup(void)
{
if ( gdata->reference_table == NULL ) {
return;
}
table_cleanup(gdata->reference_table, NULL, NULL);
gdata->reference_table = NULL;
}
void
reference_dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list)
{
dump_instance(env, object_index, list);
}
void
reference_dump_class(JNIEnv *env, ObjectIndex object_index, RefIndex list)
{
dump_class_and_supers(env, object_index, list);
}