< prev index next > src/hotspot/share/classfile/fieldLayoutBuilder.hpp
Print this page
#include "classfile/classFileParser.hpp"
#include "classfile/classLoaderData.hpp"
#include "memory/allocation.hpp"
#include "oops/fieldStreams.hpp"
#include "utilities/growableArray.hpp"
// Classes below are used to compute the field layout of classes.
-
// A LayoutRawBlock describes an element of a layout.
// Each field is represented by a LayoutRawBlock.
// LayoutRawBlocks can also represent elements injected by the JVM:
// padding, empty blocks, inherited fields, etc.
// All LayoutRawBlocks must have a size and an alignment. The size is the
#include "classfile/classFileParser.hpp"
#include "classfile/classLoaderData.hpp"
#include "memory/allocation.hpp"
#include "oops/fieldStreams.hpp"
+ #include "oops/inlineKlass.hpp"
+ #include "oops/instanceKlass.hpp"
#include "utilities/growableArray.hpp"
// Classes below are used to compute the field layout of classes.
// A LayoutRawBlock describes an element of a layout.
// Each field is represented by a LayoutRawBlock.
// LayoutRawBlocks can also represent elements injected by the JVM:
// padding, empty blocks, inherited fields, etc.
// All LayoutRawBlocks must have a size and an alignment. The size is the
// - a GrowableArray in field group (the growable array contains pointers to LayoutRawBlocks)
//
// next/prev pointers are included in the LayoutRawBlock class to narrow
// the number of allocation required during the computation of a layout.
//
class LayoutRawBlock : public ResourceObj {
public:
// Some code relies on the order of values below.
enum Kind {
! EMPTY, // empty slot, space is taken from this to allocate fields
! RESERVED, // reserved for JVM usage (for instance object header)
! PADDING, // padding (because of alignment constraints or @Contended)
! REGULAR, // primitive or oop field (including non-flattened inline fields)
! FLATTENED, // flattened field
! INHERITED // field(s) inherited from super classes
};
private:
LayoutRawBlock* _next_block;
LayoutRawBlock* _prev_block;
! Kind _kind;
int _offset;
int _alignment;
int _size;
int _field_index;
! bool _is_reference;
public:
LayoutRawBlock(Kind kind, int size);
! LayoutRawBlock(int index, Kind kind, int size, int alignment, bool is_reference = false);
LayoutRawBlock* next_block() const { return _next_block; }
void set_next_block(LayoutRawBlock* next) { _next_block = next; }
LayoutRawBlock* prev_block() const { return _prev_block; }
void set_prev_block(LayoutRawBlock* prev) { _prev_block = prev; }
! Kind kind() const { return _kind; }
int offset() const {
assert(_offset >= 0, "Must be initialized");
return _offset;
}
void set_offset(int offset) { _offset = offset; }
// - a GrowableArray in field group (the growable array contains pointers to LayoutRawBlocks)
//
// next/prev pointers are included in the LayoutRawBlock class to narrow
// the number of allocation required during the computation of a layout.
//
+
+ #define MAX_ATOMIC_OP_SIZE sizeof(uint64_t)
+
class LayoutRawBlock : public ResourceObj {
public:
// Some code relies on the order of values below.
enum Kind {
! EMPTY, // empty slot, space is taken from this to allocate fields
! RESERVED, // reserved for JVM usage (for instance object header)
! PADDING, // padding (because of alignment constraints or @Contended)
! REGULAR, // primitive or oop field (including not flat inline type fields)
! FLAT, // flat field
! INHERITED, // field(s) inherited from super classes
+ NULL_MARKER // stores the null marker for a flat field
};
private:
LayoutRawBlock* _next_block;
LayoutRawBlock* _prev_block;
! InlineKlass* _inline_klass;
+ Kind _block_kind;
+ LayoutKind _layout_kind;
int _offset;
int _alignment;
int _size;
int _field_index;
! int _null_marker_offset;
public:
LayoutRawBlock(Kind kind, int size);
!
+ LayoutRawBlock(int index, Kind kind, int size, int alignment);
LayoutRawBlock* next_block() const { return _next_block; }
void set_next_block(LayoutRawBlock* next) { _next_block = next; }
LayoutRawBlock* prev_block() const { return _prev_block; }
void set_prev_block(LayoutRawBlock* prev) { _prev_block = prev; }
! Kind block_kind() const { return _block_kind; }
+ void set_block_kind(LayoutRawBlock::Kind kind) { _block_kind = kind; } // Dangerous operation, is only used by remove_null_marker();
int offset() const {
assert(_offset >= 0, "Must be initialized");
return _offset;
}
void set_offset(int offset) { _offset = offset; }
void set_size(int size) { _size = size; }
int field_index() const {
assert(_field_index != -1, "Must be initialized");
return _field_index;
}
! bool is_reference() const { return _is_reference; }
bool fit(int size, int alignment);
static int compare_offset(LayoutRawBlock** x, LayoutRawBlock** y) { return (*x)->offset() - (*y)->offset(); }
// compare_size_inverted() returns the opposite of a regular compare method in order to
void set_size(int size) { _size = size; }
int field_index() const {
assert(_field_index != -1, "Must be initialized");
return _field_index;
}
! void set_field_index(int field_index) {
+ assert(_field_index == -1, "Must not be initialized");
+ _field_index = field_index;
+ }
+ InlineKlass* inline_klass() const {
+ assert(_inline_klass != nullptr, "Must be initialized");
+ return _inline_klass;
+ }
+ void set_inline_klass(InlineKlass* inline_klass) { _inline_klass = inline_klass; }
+ void set_null_marker_offset(int offset) { _null_marker_offset = offset; }
+ int null_marker_offset() const { return _null_marker_offset; }
+
+ LayoutKind layout_kind() const { return _layout_kind; }
+ void set_layout_kind(LayoutKind kind) { _layout_kind = kind; }
bool fit(int size, int alignment);
static int compare_offset(LayoutRawBlock** x, LayoutRawBlock** y) { return (*x)->offset() - (*y)->offset(); }
// compare_size_inverted() returns the opposite of a regular compare method in order to
if (diff == 0) {
diff = (*x)->field_index() - (*y)->field_index();
}
return diff;
}
-
};
// A Field group represents a set of fields that have to be allocated together,
// this is the way the @Contended annotation is supported.
// Inside a FieldGroup, fields are sorted based on their kind: primitive,
! // oop, or flattened.
//
class FieldGroup : public ResourceObj {
private:
FieldGroup* _next;
! GrowableArray<LayoutRawBlock*>* _primitive_fields;
GrowableArray<LayoutRawBlock*>* _oop_fields;
int _contended_group;
int _oop_count;
static const int INITIAL_LIST_SIZE = 16;
public:
FieldGroup(int contended_group = -1);
FieldGroup* next() const { return _next; }
void set_next(FieldGroup* next) { _next = next; }
! GrowableArray<LayoutRawBlock*>* primitive_fields() const { return _primitive_fields; }
GrowableArray<LayoutRawBlock*>* oop_fields() const { return _oop_fields; }
int contended_group() const { return _contended_group; }
int oop_count() const { return _oop_count; }
void add_primitive_field(int idx, BasicType type);
void add_oop_field(int idx);
void sort_by_size();
};
// The FieldLayout class represents a set of fields organized
// in a layout.
// An instance of FieldLayout can either represent the layout
if (diff == 0) {
diff = (*x)->field_index() - (*y)->field_index();
}
return diff;
}
};
// A Field group represents a set of fields that have to be allocated together,
// this is the way the @Contended annotation is supported.
// Inside a FieldGroup, fields are sorted based on their kind: primitive,
! // oop, or flat.
//
class FieldGroup : public ResourceObj {
private:
FieldGroup* _next;
!
+ GrowableArray<LayoutRawBlock*>* _small_primitive_fields;
+ GrowableArray<LayoutRawBlock*>* _big_primitive_fields;
GrowableArray<LayoutRawBlock*>* _oop_fields;
int _contended_group;
int _oop_count;
static const int INITIAL_LIST_SIZE = 16;
public:
FieldGroup(int contended_group = -1);
FieldGroup* next() const { return _next; }
void set_next(FieldGroup* next) { _next = next; }
! GrowableArray<LayoutRawBlock*>* small_primitive_fields() const { return _small_primitive_fields; }
+ GrowableArray<LayoutRawBlock*>* big_primitive_fields() const { return _big_primitive_fields; }
GrowableArray<LayoutRawBlock*>* oop_fields() const { return _oop_fields; }
int contended_group() const { return _contended_group; }
int oop_count() const { return _oop_count; }
void add_primitive_field(int idx, BasicType type);
void add_oop_field(int idx);
+ void add_flat_field(int idx, InlineKlass* vk, LayoutKind lk, int size, int alignment);
+ void add_block(LayoutRawBlock** list, LayoutRawBlock* block);
void sort_by_size();
+ private:
+ void add_to_small_primitive_list(LayoutRawBlock* block);
+ void add_to_big_primitive_list(LayoutRawBlock* block);
};
// The FieldLayout class represents a set of fields organized
// in a layout.
// An instance of FieldLayout can either represent the layout
// field allocations.
//
class FieldLayout : public ResourceObj {
private:
GrowableArray<FieldInfo>* _field_info;
ConstantPool* _cp;
LayoutRawBlock* _blocks; // the layout being computed
LayoutRawBlock* _start; // points to the first block where a field can be inserted
LayoutRawBlock* _last; // points to the last block of the layout (big empty block)
public:
! FieldLayout(GrowableArray<FieldInfo>* field_info, ConstantPool* cp);
void initialize_static_layout();
void initialize_instance_layout(const InstanceKlass* ik);
LayoutRawBlock* first_empty_block() {
LayoutRawBlock* block = _start;
! while (block->kind() != LayoutRawBlock::EMPTY) {
block = block->next_block();
}
return block;
}
! LayoutRawBlock* start() { return _start; }
void set_start(LayoutRawBlock* start) { _start = start; }
! LayoutRawBlock* last_block() { return _last; }
LayoutRawBlock* first_field_block();
void add(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = nullptr);
void add_field_at_offset(LayoutRawBlock* blocks, int offset, LayoutRawBlock* start = nullptr);
void add_contiguously(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = nullptr);
LayoutRawBlock* insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block);
bool reconstruct_layout(const InstanceKlass* ik);
void fill_holes(const InstanceKlass* ik);
LayoutRawBlock* insert(LayoutRawBlock* slot, LayoutRawBlock* block);
void remove(LayoutRawBlock* block);
! void print(outputStream* output, bool is_static, const InstanceKlass* super);
};
// FieldLayoutBuilder is the main entry point for layout computation.
! // This class has three methods to generate layout: one for regular classes
! // and two for classes with hard coded offsets (java,lang.ref.Reference
! // and the boxing classes). The rationale for having multiple methods
! // is that each kind of class has a different set goals regarding
- // its layout, so instead of mixing several layout strategies into a
// single method, each kind has its own method (see comments below
// for more details about the allocation strategies).
//
// Computing the layout of a class always goes through 4 steps:
// 1 - Prologue: preparation of data structure and gathering of
// field allocations.
//
class FieldLayout : public ResourceObj {
private:
GrowableArray<FieldInfo>* _field_info;
+ Array<InlineLayoutInfo>* _inline_layout_info_array;
ConstantPool* _cp;
LayoutRawBlock* _blocks; // the layout being computed
LayoutRawBlock* _start; // points to the first block where a field can be inserted
LayoutRawBlock* _last; // points to the last block of the layout (big empty block)
+ int _super_first_field_offset;
+ int _super_alignment;
+ int _super_min_align_required;
+ int _default_value_offset; // offset of the default value in class mirror, only for static layout of inline classes
+ int _null_reset_value_offset; // offset of the reset value in class mirror, only for static layout of inline classes
+ bool _super_has_fields;
+ bool _has_inherited_fields;
public:
! FieldLayout(GrowableArray<FieldInfo>* field_info, Array<InlineLayoutInfo>* inline_layout_info_array, ConstantPool* cp);
void initialize_static_layout();
void initialize_instance_layout(const InstanceKlass* ik);
LayoutRawBlock* first_empty_block() {
LayoutRawBlock* block = _start;
! while (block->block_kind() != LayoutRawBlock::EMPTY) {
block = block->next_block();
}
return block;
}
! LayoutRawBlock* blocks() const { return _blocks; }
+
+ LayoutRawBlock* start() const { return _start; }
void set_start(LayoutRawBlock* start) { _start = start; }
! LayoutRawBlock* last_block() const { return _last; }
+ int super_first_field_offset() const { return _super_first_field_offset; }
+ int super_alignment() const { return _super_alignment; }
+ int super_min_align_required() const { return _super_min_align_required; }
+ int default_value_offset() const {
+ assert(_default_value_offset != -1, "Must have been set");
+ return _default_value_offset;
+ }
+ int null_reset_value_offset() const {
+ assert(_null_reset_value_offset != -1, "Must have been set");
+ return _null_reset_value_offset;
+ }
+ bool super_has_fields() const { return _super_has_fields; }
+ bool has_inherited_fields() const { return _has_inherited_fields; }
LayoutRawBlock* first_field_block();
void add(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = nullptr);
void add_field_at_offset(LayoutRawBlock* blocks, int offset, LayoutRawBlock* start = nullptr);
void add_contiguously(GrowableArray<LayoutRawBlock*>* list, LayoutRawBlock* start = nullptr);
LayoutRawBlock* insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block);
bool reconstruct_layout(const InstanceKlass* ik);
void fill_holes(const InstanceKlass* ik);
LayoutRawBlock* insert(LayoutRawBlock* slot, LayoutRawBlock* block);
void remove(LayoutRawBlock* block);
! void shift_fields(int shift);
+ LayoutRawBlock* find_null_marker();
+ void remove_null_marker();
+ void print(outputStream* output, bool is_static, const InstanceKlass* super, Array<InlineLayoutInfo>* inline_fields);
};
// FieldLayoutBuilder is the main entry point for layout computation.
! // This class has two methods to generate layout: one for identity classes
! // and one for inline classes. The rational for having two methods
! // is that each kind of classes has a different set goals regarding
! // its layout, so instead of mixing two layout strategies into a
// single method, each kind has its own method (see comments below
// for more details about the allocation strategies).
//
// Computing the layout of a class always goes through 4 steps:
// 1 - Prologue: preparation of data structure and gathering of
// 4 - Epilogue: oopmaps are generated, layout information is
// prepared so other VM components can use it (instance size,
// static field size, non-static field size, etc.)
//
// Steps 1 and 4 are common to all layout computations. Step 2 and 3
! // can vary with the allocation strategy.
//
class FieldLayoutBuilder : public ResourceObj {
- private:
const Symbol* _classname;
const InstanceKlass* _super_klass;
ConstantPool* _constant_pool;
GrowableArray<FieldInfo>* _field_info;
FieldLayoutInfo* _info;
FieldGroup* _root_group;
GrowableArray<FieldGroup*> _contended_groups;
FieldGroup* _static_fields;
FieldLayout* _layout;
FieldLayout* _static_layout;
int _nonstatic_oopmap_count;
! int _alignment;
bool _has_nonstatic_fields;
! bool _is_contended; // is a contended class?
public:
! FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool,
! GrowableArray<FieldInfo>* field_info, bool is_contended, FieldLayoutInfo* info);
! int get_alignment() {
! assert(_alignment != -1, "Uninitialized");
! return _alignment;
! }
void build_layout();
void compute_regular_layout();
void insert_contended_padding(LayoutRawBlock* slot);
! private:
void prologue();
void epilogue();
void regular_field_sorting();
! FieldGroup* get_or_create_contended_group(int g);
};
#endif // SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP
// 4 - Epilogue: oopmaps are generated, layout information is
// prepared so other VM components can use it (instance size,
// static field size, non-static field size, etc.)
//
// Steps 1 and 4 are common to all layout computations. Step 2 and 3
! // differ for inline classes and identity classes.
//
class FieldLayoutBuilder : public ResourceObj {
+ private:
const Symbol* _classname;
+ ClassLoaderData* _loader_data;
const InstanceKlass* _super_klass;
ConstantPool* _constant_pool;
GrowableArray<FieldInfo>* _field_info;
FieldLayoutInfo* _info;
+ Array<InlineLayoutInfo>* _inline_layout_info_array;
FieldGroup* _root_group;
GrowableArray<FieldGroup*> _contended_groups;
FieldGroup* _static_fields;
FieldLayout* _layout;
FieldLayout* _static_layout;
int _nonstatic_oopmap_count;
! int _payload_alignment;
+ int _first_field_offset;
+ int _null_marker_offset; // if any, -1 means no internal null marker
+ int _payload_size_in_bytes;
+ int _non_atomic_layout_size_in_bytes;
+ int _non_atomic_layout_alignment;
+ int _atomic_layout_size_in_bytes;
+ int _nullable_layout_size_in_bytes;
+ int _fields_size_sum;
+ int _declared_non_static_fields_count;
+ bool _has_non_naturally_atomic_fields;
+ bool _is_naturally_atomic;
+ bool _must_be_atomic;
bool _has_nonstatic_fields;
! bool _has_inline_type_fields;
+ bool _is_contended;
+ bool _is_inline_type;
+ bool _is_abstract_value;
+ bool _has_flattening_information;
+ bool _is_empty_inline_class;
+
+ FieldGroup* get_or_create_contended_group(int g);
public:
! FieldLayoutBuilder(const Symbol* classname, ClassLoaderData* loader_data, const InstanceKlass* super_klass, ConstantPool* constant_pool,
! GrowableArray<FieldInfo>* field_info, bool is_contended, bool is_inline_type, bool is_abstract_value,
+ bool must_be_atomic, FieldLayoutInfo* info, Array<InlineLayoutInfo>* inline_layout_info_array);
! int first_field_offset() const { assert(_first_field_offset != -1, "Uninitialized"); return _first_field_offset; }
! int payload_layout_size_in_bytes() const { return _payload_size_in_bytes; }
! int payload_layout_alignment() const { assert(_payload_alignment != -1, "Uninitialized"); return _payload_alignment; }
! bool has_non_atomic_flat_layout() const { return _non_atomic_layout_size_in_bytes != -1; }
+ int non_atomic_layout_size_in_bytes() const { return _non_atomic_layout_size_in_bytes; }
+ int non_atomic_layout_alignment() const { return _non_atomic_layout_alignment; }
+ bool has_atomic_layout() const { return _atomic_layout_size_in_bytes != -1; }
+ int atomic_layout_size_in_bytes() const { return _atomic_layout_size_in_bytes; }
+ bool has_nullable_layout() const { return _nullable_layout_size_in_bytes != -1; }
+ int nullable_layout_size_in_bytes() const { return _nullable_layout_size_in_bytes; }
+ int null_marker_offset() const { return _null_marker_offset; }
+ bool is_empty_inline_class() const { return _is_empty_inline_class; }
void build_layout();
void compute_regular_layout();
+ void compute_inline_class_layout();
void insert_contended_padding(LayoutRawBlock* slot);
! protected:
void prologue();
void epilogue();
void regular_field_sorting();
! void inline_class_field_sorting();
+ void add_flat_field_oopmap(OopMapBlocksBuilder* nonstatic_oop_map, InlineKlass* vk, int offset);
+ void register_embedded_oops_from_list(OopMapBlocksBuilder* nonstatic_oop_maps, GrowableArray<LayoutRawBlock*>* list);
+ void register_embedded_oops(OopMapBlocksBuilder* nonstatic_oop_maps, FieldGroup* group);
};
#endif // SHARE_CLASSFILE_FIELDLAYOUTBUILDER_HPP
< prev index next >