@@ -40,8 +40,11 @@
#include " oops/klass.inline.hpp"
#include " oops/objArrayKlass.hpp"
#include " oops/objArrayOop.inline.hpp"
#include " oops/flatArrayKlass.hpp"
#include " oops/flatArrayOop.inline.hpp"
#include " oops/oop.inline.hpp"
#include " oops/typeArrayOop.inline.hpp"
#include " runtime/fieldDescriptor.inline.hpp"
#include " runtime/frame.inline.hpp"
#include " runtime/handles.inline.hpp"
#include " runtime/javaCalls.hpp"
@@ -380,6 +383,22 @@ enum {
INITIAL_CLASS_COUNT = 200
};
// Inlined fields of primitive classes are dumped as identity objects and require unique object ids.
// We cannot use address of the object in container oop (as we do for identity objects)
// because the address can be the same for inlined object which contains inlined field with offset 0.
class InlinedObjectSupport : public StackObj {
friend class DumpWriter ;
InlinedObjectSupport (int initial_value = 1 ) : _counter(initial_value) {}
int _counter;
int getId () { return _counter++; }
public:
InlinedObjectSupport save () const {
return InlinedObjectSupport (_counter);
}
};
// Supports I/O operations for a dump
class DumpWriter : public StackObj {
@@ -414,6 +433,8 @@ class DumpWriter : public StackObj {
// Returns true if we have enough room in the buffer for 'len' bytes.
bool can_write_fast (size_t len);
InlinedObjectSupport _inlined_object_support;
public:
// Takes ownership of the writer and compressor.
DumpWriter (AbstractWriter* writer, AbstractCompressor* compressor);
@@ -425,13 +446,16 @@ class DumpWriter : public StackObj {
char const * error () const { return _backend.error (); }
InlinedObjectSupport& inlined_object_support () { return _inlined_object_support; }
// writer functions
void write_raw (void * s, size_t len);
void write_u1 (u1 x);
void write_u2 (u2 x);
void write_u4 (u4 x);
void write_u8 (u8 x);
void write_objectID (oop o);
void write_inlinedObjectID (InlinedObjectSupport &inlinedObjectSupport);
void write_symbolID (Symbol* o);
void write_classID (Klass* k);
void write_id (u4 x);
@@ -538,6 +562,14 @@ void DumpWriter::write_objectID(oop o) {
#endif
}
void DumpWriter::write_inlinedObjectID (InlinedObjectSupport& inlinedObjectSupport) {
#ifdef _LP64
write_u8 (inlinedObjectSupport.getId ());
#else
write_u4 (inlinedObjectSupport.getId ());
#endif
}
void DumpWriter::write_symbolID (Symbol* s) {
address a = (address)((uintptr_t )s);
#ifdef _LP64
@@ -637,18 +669,28 @@ class DumperSupport : AllStatic {
static void dump_float (DumpWriter* writer, jfloat f);
// dump a jdouble
static void dump_double (DumpWriter* writer, jdouble d);
// dumps the raw value of the given field
static void dump_field_value (DumpWriter* writer, char type, oop obj, int offset);
// dumps the raw value of the given field; obj and offset specify the object (offset is 0 for identity objects)
// for inlined fields writed object id generated by writer->inlined_object_support()
static void dump_field_value (DumpWriter* writer, const FieldStream& fld, oop obj, int offset);
// returns the size of the static fields; also counts the static fields
static u4 get_static_fields_size (InstanceKlass* ik, u2& field_count);
// dumps static fields of the given class
static void dump_static_fields (DumpWriter* writer, Klass* k);
// dump the raw values of the instance fields of the given object
static void dump_instance_fields (DumpWriter* writer, oop o);
// dump the raw values of the instance fields of the given identity or inlined object;
// for identity objects offset is 0 and 'klass' is o->klass(),
// for inlined objects offset is the offset in the holder object, 'klass' is inlined object class
static void dump_instance_fields (DumpWriter* writer, oop o, int offset, Klass* klass);
// dump inlined instance fields of the given object (identity or inlined);
// o is the holder object, offset and klass specify flattened field (or field of flattened field, etc.);
// for identity object offset is 0 and klass is o->klass()
static void dump_inlined_instance_fields (DumpWriter* writer, oop o, int offset, Klass* klass, InlinedObjectSupport &ios);
// get the count of the instance fields for a given class
static u2 get_instance_fields_count (InstanceKlass* ik);
// dumps the definition of the instance fields for a given class
static void dump_instance_field_descriptors (DumpWriter* writer, Klass* k);
// creates HPROF_GC_INSTANCE_DUMP record for the given inlined object
static void dump_inlined_object (DumpWriter* writer, oop holder, int offset, InlineKlass* klass, InlinedObjectSupport& ios);
// creates HPROF_GC_INSTANCE_DUMP record for the given object
static void dump_instance (DumpWriter* writer, oop o);
// creates HPROF_GC_CLASS_DUMP record for the given class and each of its
@@ -659,7 +701,8 @@ class DumperSupport : AllStatic {
static void dump_basic_type_array_class (DumpWriter* writer, Klass* k);
// creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array
static void dump_object_array (DumpWriter* writer, objArrayOop array);
// static void dump_object_array(DumpWriter* writer, objArrayOop array);
static void dump_object_array (DumpWriter* writer, arrayOop array);
// creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array
static void dump_prim_array (DumpWriter* writer, typeArrayOop array);
// create HPROF_FRAME record for the given method and bci
@@ -693,6 +736,7 @@ void DumperSupport:: write_header(DumpWriter* writer, hprofTag tag, u4 len) {
hprofTag DumperSupport::sig2tag (Symbol* sig) {
switch (sig->char_at (0 )) {
case JVM_SIGNATURE_CLASS : return HPROF_NORMAL_OBJECT;
case JVM_SIGNATURE_INLINE_TYPE: return HPROF_NORMAL_OBJECT;
case JVM_SIGNATURE_ARRAY : return HPROF_NORMAL_OBJECT;
case JVM_SIGNATURE_BYTE : return HPROF_BYTE;
case JVM_SIGNATURE_CHAR : return HPROF_CHAR;
@@ -723,6 +767,7 @@ hprofTag DumperSupport::type2tag(BasicType type) {
u4 DumperSupport::sig2size (Symbol* sig) {
switch (sig->char_at (0 )) {
case JVM_SIGNATURE_CLASS:
case JVM_SIGNATURE_INLINE_TYPE:
case JVM_SIGNATURE_ARRAY: return sizeof (address);
case JVM_SIGNATURE_BOOLEAN:
case JVM_SIGNATURE_BYTE: return 1 ;
@@ -765,9 +810,19 @@ void DumperSupport::dump_double(DumpWriter* writer, jdouble d) {
writer->write_u8 ((u8)u.l );
}
// dumps the raw value of the given field
void DumperSupport::dump_field_value (DumpWriter* writer, char type, oop obj, int offset) {
// dumps the raw value of the given field; obj and offset specify the object (offset is 0 for identity objects)
// for inlined fields writed object id generated by writer->inlined_object_support()
void DumperSupport::dump_field_value (DumpWriter* writer, const FieldStream& fld, oop obj, int offset) {
char type = fld.signature ()->char_at (0 );
offset += fld.offset ();
switch (type) {
case JVM_SIGNATURE_INLINE_TYPE: {
if (fld.field_descriptor ().is_inlined ()) {
writer->write_inlinedObjectID (writer->inlined_object_support ());
break ;
}
}
// pass through
case JVM_SIGNATURE_CLASS :
case JVM_SIGNATURE_ARRAY : {
oop o = obj->obj_field_access <ON_UNKNOWN_OOP_REF | AS_NO_KEEPALIVE>(offset);
@@ -895,8 +950,11 @@ void DumperSupport::dump_static_fields(DumpWriter* writer, Klass* k) {
writer->write_symbolID (fld.name ()); // name
writer->write_u1 (sig2tag (sig)); // type
// if this changes, need to handle this properly (dump inlined objects after dump_static_fields)
assert (!fld.field_descriptor ().is_inlined (), " static fields cannot be inlined" );
// value
dump_field_value (writer, sig-> char_at ( 0 ) , ik->java_mirror (), fld. offset () );
dump_field_value (writer, fld , ik->java_mirror (), 0 );
}
}
@@ -926,19 +984,35 @@ void DumperSupport::dump_static_fields(DumpWriter* writer, Klass* k) {
}
}
// dump the raw values of the instance fields of the given object
void DumperSupport::dump_instance_fields (DumpWriter* writer, oop o) {
InstanceKlass* ik = InstanceKlass::cast (o-> klass () );
void DumperSupport::dump_instance_fields (DumpWriter* writer, oop o, int offset, Klass *klass ) {
InstanceKlass* ik = InstanceKlass::cast (klass);
for (FieldStream fld (ik, false , false ); !fld.eos (); fld.next ()) {
if (!fld.access_flags ().is_static ()) {
Symbol* sig = fld.signature ();
dump_field_value (writer, sig->char_at (0 ), o, fld.offset ());
dump_field_value (writer, fld, o, offset);
}
}
}
// dumps the definition of the instance fields for a given class
void DumperSupport::dump_inlined_instance_fields (DumpWriter *writer, oop o, int offset, Klass *klass, InlinedObjectSupport &ios) {
InstanceKlass* ik = InstanceKlass::cast (klass);
assert (&ios != &writer->inlined_object_support (), " must be saved copy" );
for (FieldStream fld (ik, false , false ); !fld.eos (); fld.next ()) {
if (!fld.access_flags ().is_static ()) {
if (fld.field_descriptor ().is_inlined ()) {
InstanceKlass* holder_klass = fld.field_descriptor ().field_holder ();
InlineKlass* field_klass = InlineKlass::cast (holder_klass->get_inline_type_field_klass (fld.index ()));
dump_inlined_object (writer, o, offset + fld.offset (), field_klass, ios);
}
}
}
}
// gets the count of the instance fields for a given class
u2 DumperSupport::get_instance_fields_count (InstanceKlass* ik) {
u2 field_count = 0 ;
@@ -964,6 +1038,37 @@ void DumperSupport::dump_instance_field_descriptors(DumpWriter* writer, Klass* k
}
}
// creates HPROF_GC_INSTANCE_DUMP record for the given inlined object
void DumperSupport::dump_inlined_object (DumpWriter* writer, oop holder, int offset, InlineKlass* klass, InlinedObjectSupport& ios) {
u4 is = instance_size (klass);
u4 size = 1 + sizeof (address) + 4 + sizeof (address) + 4 + is;
writer->start_sub_record (HPROF_GC_INSTANCE_DUMP, size);
writer->write_inlinedObjectID (ios);
writer->write_u4 (STACK_TRACE_ID);
// class ID
writer->write_classID (klass);
// number of bytes that follow
writer->write_u4 (is);
// the object if flattened, so all fields are stored without headers
// update offset here instead of handling it in both dump_instance_fields and dump_inlined_instance_fields
offset -= klass->first_field_offset ();
InlinedObjectSupport saved_ios = writer->inlined_object_support ().save ();
// field values
dump_instance_fields (writer, holder, offset, klass);
writer->end_sub_record ();
// dump flattened fields
dump_inlined_instance_fields (writer, holder, offset, klass, saved_ios);
}
// creates HPROF_GC_INSTANCE_DUMP record for the given object
void DumperSupport::dump_instance (DumpWriter* writer, oop o) {
InstanceKlass* ik = InstanceKlass::cast (o->klass ());
@@ -980,10 +1085,15 @@ void DumperSupport::dump_instance(DumpWriter* writer, oop o) {
// number of bytes that follow
writer->write_u4 (is);
InlinedObjectSupport saved_ios = writer->inlined_object_support ().save ();
// field values
dump_instance_fields (writer, o);
dump_instance_fields (writer, o, 0 , o-> klass () );
writer->end_sub_record ();
// dump inlined fields
dump_inlined_instance_fields (writer, o, 0 , o->klass (), saved_ios);
}
// creates HPROF_GC_CLASS_DUMP record for the given class and each of
@@ -1078,8 +1188,8 @@ void DumperSupport::dump_class_and_array_classes(DumpWriter* writer, Klass* k) {
// creates HPROF_GC_CLASS_DUMP record for a given primitive array
// class (and each multi-dimensional array class too)
void DumperSupport::dump_basic_type_array_class (DumpWriter* writer, Klass* k) {
// array classes
while (k != NULL ) {
// array classes
while (k != NULL ) {
Klass* klass = k;
u4 size = 1 + sizeof (address) + 4 + 6 * sizeof (address) + 4 + 2 + 2 + 2 ;
@@ -1114,12 +1224,12 @@ void DumperSupport::dump_basic_type_array_class(DumpWriter* writer, Klass* k) {
// which means we need to truncate arrays that are too long.
int DumperSupport::calculate_array_max_length (DumpWriter* writer, arrayOop array, short header_size) {
BasicType type = ArrayKlass::cast (array->klass ())->element_type ();
assert (type >= T_BOOLEAN && type <= T_OBJECT, " invalid array element type" );
assert (( type >= T_BOOLEAN && type <= T_OBJECT) || type == T_INLINE_TYPE , " invalid array element type" );
int length = array->length ();
int type_size;
if (type == T_OBJECT) {
if (type == T_OBJECT || type == T_INLINE_TYPE ) {
type_size = sizeof (address);
} else {
type_size = type2aelembytes (type);
@@ -1139,7 +1249,7 @@ int DumperSupport::calculate_array_max_length(DumpWriter* writer, arrayOop array
}
// creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array
void DumperSupport::dump_object_array (DumpWriter* writer, objArrayOop array) {
void DumperSupport::dump_object_array (DumpWriter* writer, arrayOop array) {
// sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + sizeof(classID)
short header_size = 1 + 2 * 4 + 2 * sizeof (address);
int length = calculate_array_max_length (writer, array, header_size);
@@ -1153,20 +1263,43 @@ void DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) {
// array class ID
writer->write_classID (array->klass ());
// [id]* elements
for (int index = 0 ; index < length; index ++) {
oop o = array->obj_at (index );
if (o != NULL && log_is_enabled (Debug, cds, heap) && mask_dormant_archived_object (o) == NULL ) {
ResourceMark rm;
log_debug (cds, heap)(" skipped dormant archived object " INTPTR_FORMAT " (%s) referenced by " INTPTR_FORMAT " (%s)" ,
p2i (o), o->klass ()->external_name (),
p2i (array), array->klass ()->external_name ());
InlinedObjectSupport ios = writer->inlined_object_support ().save ();
if (array->is_objArray ()) {
// [id]* elements
objArrayOop objArray = objArrayOop (array);
for (int index = 0 ; index < length; index ++) {
oop o = objArray->obj_at (index );
if (o != NULL && log_is_enabled (Debug, cds, heap) && mask_dormant_archived_object (o) == NULL ) {
ResourceMark rm;
log_debug (cds, heap)(" skipped dormant archived object " INTPTR_FORMAT " (%s) referenced by " INTPTR_FORMAT " (%s)" ,
p2i (o), o->klass ()->external_name (),
p2i (array), array->klass ()->external_name ());
}
o = mask_dormant_archived_object (o);
writer->write_objectID (o);
}
} else { // flatArray
// [id]* elements
flatArrayOop flatArray = flatArrayOop (array);
for (int index = 0 ; index < length; index ++) {
writer->write_inlinedObjectID (writer->inlined_object_support ());
}
o = mask_dormant_archived_object (o);
writer->write_objectID (o);
}
writer->end_sub_record ();
if (array->is_flatArray ()) {
flatArrayOop flatArray = flatArrayOop (array);
FlatArrayKlass* vaklass = FlatArrayKlass::cast (flatArray->klass ());
InlineKlass* vklass = vaklass->element_klass ();
for (int index = 0 ; index < length; index ++) {
// need offset in the holder to read inlined object. calculate it from flatArrayOop::value_at_addr()
int offset = (int )((address)flatArray->value_at_addr (index , vaklass->layout_helper ())
- cast_from_oop<address>(flatArray));
dump_inlined_object (writer, flatArray, offset, vklass, ios);
}
}
}
#define WRITE_ARRAY (Array, Type, Size, Length ) \
@@ -1437,9 +1570,9 @@ void HeapObjectDumper::do_object(oop o) {
if (o->is_instance ()) {
// create a HPROF_GC_INSTANCE record for each object
DumperSupport::dump_instance (writer (), o);
} else if (o->is_objArray ()) {
} else if (o->is_objArray () || o-> is_flatArray () ) {
// create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array
DumperSupport::dump_object_array (writer (), objArrayOop (o));
DumperSupport::dump_object_array (writer (), arrayOop (o));
} else if (o->is_typeArray ()) {
// create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array
DumperSupport::dump_prim_array (writer (), typeArrayOop (o));