src/share/vm/oops/methodData.hpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
hotspot Cdiff src/share/vm/oops/methodData.hpp
src/share/vm/oops/methodData.hpp
Print this page
rev 5349 : 8023657: New type profiling points: arguments to call
Summary: x86 interpreter and c1 type profiling for arguments at calls
Reviewed-by:
rev 5350 : 8026054: New type profiling points: type of return values at calls
Summary: x86 interpreter and c1 type profiling for return values at calls
Reviewed-by:
*** 269,278 ****
--- 269,280 ----
//
// A ProfileData object is created to refer to a section of profiling
// data in a structured way.
class ProfileData : public ResourceObj {
friend class TypeEntries;
+ friend class TypeEntriesAtCall;
+ friend class ReturnTypeEntry;
friend class TypeStackSlotEntries;
private:
#ifndef PRODUCT
enum {
tab_width_one = 16,
*** 741,769 ****
stack_slot_entry,
type_entry,
per_arg_cell_count
};
// Start with a header if needed. It stores the number of cells used
! // for this call type information. Unless we collect only profiling
! // for a single argument the number of cells is unknown statically.
static int header_cell_count() {
! return (TypeProfileArgsLimit > 1) ? 1 : 0;
}
static int cell_count_local_offset() {
! assert(arguments_profiling_enabled() && TypeProfileArgsLimit > 1, "no cell count");
return 0;
}
int cell_count_global_offset() const {
return _base_off + cell_count_local_offset();
}
! // offset of cell for stack slot for entry i within ProfileData object
! int stack_slot_global_offset(int i) const {
! return _base_off + stack_slot_local_offset(i);
}
void check_number_of_arguments(uint total) {
assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
}
--- 743,923 ----
stack_slot_entry,
type_entry,
per_arg_cell_count
};
+ // offset of cell for stack slot for entry i within ProfileData object
+ int stack_slot_offset(int i) const {
+ return _base_off + stack_slot_local_offset(i);
+ }
+
+ protected:
+ const int _nb_entries;
+
+ // offset of cell for type for entry i within ProfileData object
+ int type_offset(int i) const {
+ return _base_off + type_local_offset(i);
+ }
+
+ public:
+
+ TypeStackSlotEntries(int base_off, ProfileData* pd, int nb_entries)
+ : TypeEntries(base_off, pd), _nb_entries(nb_entries) {}
+
+ static int compute_cell_count(Symbol* signature, int max);
+
+ void post_initialize(Symbol* signature, bool has_receiver);
+
+ // offset of cell for stack slot for entry i within this block of cells for a TypeStackSlotEntries
+ static int stack_slot_local_offset(int i) {
+ return i * per_arg_cell_count + stack_slot_entry;
+ }
+
+ // offset of cell for type for entry i within this block of cells for a TypeStackSlotEntries
+ static int type_local_offset(int i) {
+ return i * per_arg_cell_count + type_entry;
+ }
+
+ // stack slot for entry i
+ uint stack_slot(int i) const {
+ assert(i >= 0 && i < _nb_entries, "oob");
+ return _pd->uint_at(stack_slot_offset(i));
+ }
+
+ // set stack slot for entry i
+ void set_stack_slot(int i, uint num) {
+ assert(i >= 0 && i < _nb_entries, "oob");
+ _pd->set_uint_at(stack_slot_offset(i), num);
+ }
+
+ // type for entry i
+ intptr_t type(int i) const {
+ assert(i >= 0 && i < _nb_entries, "oob");
+ return _pd->intptr_at(type_offset(i));
+ }
+
+ // set type for entry i
+ void set_type(int i, intptr_t k) {
+ assert(i >= 0 && i < _nb_entries, "oob");
+ _pd->set_intptr_at(type_offset(i), k);
+ }
+
+ static ByteSize per_arg_size() {
+ return in_ByteSize(per_arg_cell_count * DataLayout::cell_size);
+ }
+
+ static int per_arg_count() {
+ return per_arg_cell_count ;
+ }
+
+ // GC support
+ void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
+
+ #ifndef PRODUCT
+ void print_data_on(outputStream* st) const;
+ #endif
+ };
+
+ // Type entry used for return from a call. A single cell to record the
+ // type.
+ class ReturnTypeEntry : public TypeEntries {
+
+ private:
+ enum {
+ cell_count = 1
+ };
+
+ public:
+ ReturnTypeEntry(int base_off, ProfileData* pd)
+ : TypeEntries(base_off, pd) {}
+
+ void post_initialize() {
+ set_type(type_none());
+ }
+
+ intptr_t type() const {
+ assert_profiling_enabled();
+ return _pd->intptr_at(_base_off);
+ }
+
+ void set_type(intptr_t k) {
+ assert_profiling_enabled();
+ _pd->set_intptr_at(_base_off, k);
+ }
+
+ static int static_cell_count() {
+ assert_profiling_enabled();
+ return cell_count;
+ }
+
+ static ByteSize size() {
+ assert_profiling_enabled();
+ return in_ByteSize(cell_count * DataLayout::cell_size);
+ }
+
+ ByteSize type_offset() {
+ assert_profiling_enabled();
+ return DataLayout::cell_offset(_base_off);
+ }
+
+ static bool profiling_enabled();
+
+ static void assert_profiling_enabled() {
+ assert(profiling_enabled(), "args profiling should be on");
+ }
+
+ // GC support
+ void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
+
+ #ifndef PRODUCT
+ void print_data_on(outputStream* st) const;
+ #endif
+ };
+
+ // Entries to collect type information at a call: contains arguments
+ // (TypeStackSlotEntries), a return type (ReturnTypeEntry) and a
+ // number of cells. Because the number of cells for the return type is
+ // smaller than the number of cells for the type of an arguments, the
+ // number of cells is used to tell how many arguments are profiled and
+ // whether a return value is profiled. See has_arguments() and
+ // has_return().
+ class TypeEntriesAtCall {
+
+ private:
+
+ // offset within the ProfileData object where the entries start
+ const int _base_off;
+ // entries for arguments if any
+ TypeStackSlotEntries _args;
+ // entry for return type if any
+ ReturnTypeEntry _ret;
+
// Start with a header if needed. It stores the number of cells used
! // for this call type information. Unless we collect only return
! // type profiling or only profiling for a single argument the number
! // of cells is unknown statically.
static int header_cell_count() {
! return (arguments_profiling_enabled() && (TypeProfileArgsLimit > 1 || return_profiling_enabled())) ? 1 : 0;
}
static int cell_count_local_offset() {
! assert(arguments_profiling_enabled() && (TypeProfileArgsLimit > 1 || return_profiling_enabled()), "no cell count");
return 0;
}
int cell_count_global_offset() const {
return _base_off + cell_count_local_offset();
}
! static int stack_slot_local_offset(int i) {
! assert_arguments_profiling_enabled();
! return header_cell_count() + TypeStackSlotEntries::stack_slot_local_offset(i);
! }
!
! static int argument_type_local_offset(int i) {
! assert_arguments_profiling_enabled();
! return header_cell_count() + TypeStackSlotEntries::type_local_offset(i);;
}
void check_number_of_arguments(uint total) {
assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
}
*** 775,871 ****
static bool arguments_profiling_enabled();
static void assert_arguments_profiling_enabled() {
assert(arguments_profiling_enabled(), "args profiling should be on");
}
protected:
! // offset of cell for type for entry i within ProfileData object
! int type_global_offset(int i) const {
! return _base_off + type_local_offset(i);
}
public:
!
! TypeStackSlotEntries(int base_off, ProfileData* pd)
! : TypeEntries(base_off, pd) {}
static int compute_cell_count(BytecodeStream* stream);
static void initialize(DataLayout* dl, int base, int cell_count) {
! if (TypeProfileArgsLimit > 1) {
int off = base + cell_count_local_offset();
dl->set_cell_at(off, cell_count - base - header_cell_count());
}
}
void post_initialize(BytecodeStream* stream);
uint number_of_arguments() const {
assert_arguments_profiling_enabled();
if (TypeProfileArgsLimit > 1) {
int cell_count = cell_count_no_header();
int nb = cell_count / TypeStackSlotEntries::per_arg_count();
! assert(nb > 0 && nb <= TypeProfileArgsLimit , "only when we profile args");
return nb;
} else {
assert(TypeProfileArgsLimit == 1, "at least one arg");
return 1;
}
}
int cell_count() const {
! assert_arguments_profiling_enabled();
! if (TypeProfileArgsLimit > 1) {
return _base_off + header_cell_count() + _pd->int_at_unchecked(cell_count_global_offset());
! } else {
return _base_off + TypeStackSlotEntries::per_arg_count();
}
}
! // offset of cell for stack slot for entry i within this block of cells for a TypeStackSlotEntries
! static int stack_slot_local_offset(int i) {
! assert_arguments_profiling_enabled();
! return header_cell_count() + i * per_arg_cell_count + stack_slot_entry;
! }
!
! // offset of cell for type for entry i within this block of cells for a TypeStackSlotEntries
! static int type_local_offset(int i) {
! return header_cell_count() + i * per_arg_cell_count + type_entry;
! }
!
! // stack slot for entry i
! uint stack_slot(int i) const {
! assert(i >= 0 && i < number_of_arguments(), "oob");
! return _pd->uint_at(stack_slot_global_offset(i));
! }
!
! // set stack slot for entry i
! void set_stack_slot(int i, uint num) {
! assert(i >= 0 && i < number_of_arguments(), "oob");
! _pd->set_uint_at(stack_slot_global_offset(i), num);
! }
!
! // type for entry i
! intptr_t type(int i) const {
! assert(i >= 0 && i < number_of_arguments(), "oob");
! return _pd->intptr_at(type_global_offset(i));
! }
! // set type for entry i
! void set_type(int i, intptr_t k) {
! assert(i >= 0 && i < number_of_arguments(), "oob");
! _pd->set_intptr_at(type_global_offset(i), k);
}
! static ByteSize per_arg_size() {
! return in_ByteSize(per_arg_cell_count * DataLayout::cell_size);
}
! static int per_arg_count() {
! return per_arg_cell_count ;
}
// Code generation support
static ByteSize cell_count_offset() {
return in_ByteSize(cell_count_local_offset() * DataLayout::cell_size);
--- 929,1026 ----
static bool arguments_profiling_enabled();
static void assert_arguments_profiling_enabled() {
assert(arguments_profiling_enabled(), "args profiling should be on");
}
+ static bool return_profiling_enabled() {
+ return ReturnTypeEntry::profiling_enabled();
+ }
+ static void assert_return_profiling_enabled() {
+ ReturnTypeEntry::assert_profiling_enabled();
+ }
protected:
! // ProfileData object these entries are part of
! ProfileData* _pd;
!
! // An entry for a return value takes less space than an entry for an
! // argument so if the number of cells exceeds the number of cells
! // needed for an argument, this object contains type information for
! // at least one argument.
! bool has_arguments() const {
! assert_arguments_profiling_enabled();
! return return_profiling_enabled() ? (cell_count_no_header() >= TypeStackSlotEntries::per_arg_count()) : true;
}
public:
! TypeEntriesAtCall(int base_off, ProfileData* pd)
! : _base_off(base_off), _pd(pd),
! _args(base_off + header_cell_count(), pd, arguments_profiling_enabled() ? number_of_arguments() : 0),
! _ret((arguments_profiling_enabled() && return_profiling_enabled()) ? cell_count() - ReturnTypeEntry::static_cell_count() : _base_off, pd)
! {}
static int compute_cell_count(BytecodeStream* stream);
static void initialize(DataLayout* dl, int base, int cell_count) {
! if (arguments_profiling_enabled() && (TypeProfileArgsLimit > 1 || return_profiling_enabled())) {
int off = base + cell_count_local_offset();
dl->set_cell_at(off, cell_count - base - header_cell_count());
}
}
void post_initialize(BytecodeStream* stream);
uint number_of_arguments() const {
assert_arguments_profiling_enabled();
if (TypeProfileArgsLimit > 1) {
+ // An entry for a return value takes less space than an entry
+ // for an argument, so number of cells divided by the number of
+ // cells for an argument is the number of arguments being
+ // profiled in this object.
int cell_count = cell_count_no_header();
+ assert(!return_profiling_enabled() || TypeStackSlotEntries::per_arg_count() > ReturnTypeEntry::static_cell_count(), "need each per arg entry to be bigger than ret entry");
int nb = cell_count / TypeStackSlotEntries::per_arg_count();
! assert((!has_arguments() && nb == 0) || (nb > 0 && nb <= TypeProfileArgsLimit) , "only when we profile args");
return nb;
} else {
assert(TypeProfileArgsLimit == 1, "at least one arg");
return 1;
}
}
int cell_count() const {
! if (arguments_profiling_enabled() && (TypeProfileArgsLimit > 1 || return_profiling_enabled())) {
return _base_off + header_cell_count() + _pd->int_at_unchecked(cell_count_global_offset());
! } else if (arguments_profiling_enabled()) {
return _base_off + TypeStackSlotEntries::per_arg_count();
+ } else {
+ assert_return_profiling_enabled();
+ return _base_off + ReturnTypeEntry::static_cell_count();
}
}
! const TypeStackSlotEntries* args_type_data() const { return &_args; }
! const ReturnTypeEntry* ret_type_data() const { return &_ret; }
! // An entry for a return value takes less space than an entry for an
! // argument, so if the remainder of the number of cells divided by
! // the number of cells for an argument is not null, a return value
! // is profiled in this object.
! bool has_return() const {
! assert_return_profiling_enabled();
! return arguments_profiling_enabled() ? (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0 : true;
}
! void set_argument_type(int i, Klass* k) {
! intptr_t current = _args.type(i);
! _args.set_type(i, TypeEntries::with_status(k, current));
}
! void set_return_type(Klass* k) {
! intptr_t current = _ret.type();
! _ret.set_type(TypeEntries::with_status(k, current));
}
// Code generation support
static ByteSize cell_count_offset() {
return in_ByteSize(cell_count_local_offset() * DataLayout::cell_size);
*** 877,888 ****
static ByteSize stack_slot_offset(int i) {
return in_ByteSize(stack_slot_local_offset(i) * DataLayout::cell_size);
}
! static ByteSize type_offset(int i) {
! return in_ByteSize(type_local_offset(i) * DataLayout::cell_size);
}
// GC support
void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
--- 1032,1047 ----
static ByteSize stack_slot_offset(int i) {
return in_ByteSize(stack_slot_local_offset(i) * DataLayout::cell_size);
}
! static ByteSize argument_type_offset(int i) {
! return in_ByteSize(argument_type_local_offset(i) * DataLayout::cell_size);
! }
!
! ByteSize return_type_offset() {
! return _ret.type_offset();
}
// GC support
void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
*** 892,953 ****
};
// CallTypeData
//
// A CallTypeData is used to access profiling information about a non
! // virtual call for which we collect type information about arguments.
class CallTypeData : public CounterData {
private:
! TypeStackSlotEntries _args;
public:
CallTypeData(DataLayout* layout) :
! CounterData(layout), _args(CounterData::static_cell_count(), this) {
assert(layout->tag() == DataLayout::call_type_data_tag, "wrong type");
}
! const TypeStackSlotEntries* args() const { return &_args; }
virtual bool is_CallTypeData() const { return true; }
static int static_cell_count() {
return -1;
}
static int compute_cell_count(BytecodeStream* stream) {
! return CounterData::static_cell_count() + TypeStackSlotEntries::compute_cell_count(stream);
}
static void initialize(DataLayout* dl, int cell_count) {
! TypeStackSlotEntries::initialize(dl, CounterData::static_cell_count(), cell_count);
}
virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {
! _args.post_initialize(stream);
}
virtual int cell_count() const {
! return _args.cell_count();
}
uint number_of_arguments() const {
! return args()->number_of_arguments();
}
void set_argument_type(int i, Klass* k) {
! intptr_t current = _args.type(i);
! _args.set_type(i, TypeEntries::with_status(k, current));
}
// Code generation support
static ByteSize args_data_offset() {
! return cell_offset(CounterData::static_cell_count()) + TypeStackSlotEntries::args_data_offset();
}
// GC support
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
! _args.clean_weak_klass_links(is_alive_closure);
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
#endif
--- 1051,1116 ----
};
// CallTypeData
//
// A CallTypeData is used to access profiling information about a non
! // virtual call for which we collect type information about arguments
! // and return value.
class CallTypeData : public CounterData {
private:
! TypeEntriesAtCall _args_and_ret;
public:
CallTypeData(DataLayout* layout) :
! CounterData(layout), _args_and_ret(CounterData::static_cell_count(), this) {
assert(layout->tag() == DataLayout::call_type_data_tag, "wrong type");
}
! const TypeEntriesAtCall* args_and_ret() const { return &_args_and_ret; }
virtual bool is_CallTypeData() const { return true; }
static int static_cell_count() {
return -1;
}
static int compute_cell_count(BytecodeStream* stream) {
! return CounterData::static_cell_count() + TypeEntriesAtCall::compute_cell_count(stream);
}
static void initialize(DataLayout* dl, int cell_count) {
! TypeEntriesAtCall::initialize(dl, CounterData::static_cell_count(), cell_count);
}
virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {
! _args_and_ret.post_initialize(stream);
}
virtual int cell_count() const {
! return _args_and_ret.cell_count();
}
uint number_of_arguments() const {
! return args_and_ret()->number_of_arguments();
}
void set_argument_type(int i, Klass* k) {
! _args_and_ret.set_argument_type(i, k);
! }
!
! void set_return_type(Klass* k) {
! _args_and_ret.set_return_type(k);
}
// Code generation support
static ByteSize args_data_offset() {
! return cell_offset(CounterData::static_cell_count()) + TypeEntriesAtCall::args_data_offset();
}
// GC support
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
! _args_and_ret.clean_weak_klass_links(is_alive_closure);
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
#endif
*** 1096,1158 ****
// VirtualCallTypeData
//
// A VirtualCallTypeData is used to access profiling information about
// a virtual call for which we collect type information about
! // arguments.
class VirtualCallTypeData : public VirtualCallData {
private:
! TypeStackSlotEntries _args;
public:
VirtualCallTypeData(DataLayout* layout) :
! VirtualCallData(layout), _args(VirtualCallData::static_cell_count(), this) {
assert(layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type");
}
! const TypeStackSlotEntries* args() const { return &_args; }
virtual bool is_VirtualCallTypeData() const { return true; }
static int static_cell_count() {
return -1;
}
static int compute_cell_count(BytecodeStream* stream) {
! return VirtualCallData::static_cell_count() + TypeStackSlotEntries::compute_cell_count(stream);
}
static void initialize(DataLayout* dl, int cell_count) {
! TypeStackSlotEntries::initialize(dl, VirtualCallData::static_cell_count(), cell_count);
}
virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {
! _args.post_initialize(stream);
}
virtual int cell_count() const {
! return _args.cell_count();
}
uint number_of_arguments() const {
! return args()->number_of_arguments();
}
void set_argument_type(int i, Klass* k) {
! intptr_t current = _args.type(i);
! _args.set_type(i, TypeEntries::with_status(k, current));
}
// Code generation support
static ByteSize args_data_offset() {
! return cell_offset(VirtualCallData::static_cell_count()) + TypeStackSlotEntries::args_data_offset();
}
// GC support
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
ReceiverTypeData::clean_weak_klass_links(is_alive_closure);
! _args.clean_weak_klass_links(is_alive_closure);
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
#endif
--- 1259,1324 ----
// VirtualCallTypeData
//
// A VirtualCallTypeData is used to access profiling information about
// a virtual call for which we collect type information about
! // arguments and return value.
class VirtualCallTypeData : public VirtualCallData {
private:
! TypeEntriesAtCall _args_and_ret;
public:
VirtualCallTypeData(DataLayout* layout) :
! VirtualCallData(layout), _args_and_ret(VirtualCallData::static_cell_count(), this) {
assert(layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type");
}
! const TypeEntriesAtCall* args_and_ret() const { return &_args_and_ret; }
virtual bool is_VirtualCallTypeData() const { return true; }
static int static_cell_count() {
return -1;
}
static int compute_cell_count(BytecodeStream* stream) {
! return VirtualCallData::static_cell_count() + TypeEntriesAtCall::compute_cell_count(stream);
}
static void initialize(DataLayout* dl, int cell_count) {
! TypeEntriesAtCall::initialize(dl, VirtualCallData::static_cell_count(), cell_count);
}
virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {
! _args_and_ret.post_initialize(stream);
}
virtual int cell_count() const {
! return _args_and_ret.cell_count();
}
uint number_of_arguments() const {
! return args_and_ret()->number_of_arguments();
}
void set_argument_type(int i, Klass* k) {
! _args_and_ret.set_argument_type(i, k);
! }
!
! void set_return_type(Klass* k) {
! _args_and_ret.set_return_type(k);
}
// Code generation support
static ByteSize args_data_offset() {
! return cell_offset(VirtualCallData::static_cell_count()) + TypeEntriesAtCall::args_data_offset();
}
// GC support
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
ReceiverTypeData::clean_weak_klass_links(is_alive_closure);
! _args_and_ret.clean_weak_klass_links(is_alive_closure);
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
#endif
*** 1680,1689 ****
--- 1846,1859 ----
static bool profile_jsr292(methodHandle m, int bci);
static int profile_arguments_flag();
static bool profile_arguments_jsr292_only();
static bool profile_all_arguments();
static bool profile_arguments_for_invoke(methodHandle m, int bci);
+ static int profile_return_flag();
+ static bool profile_return_jsr292_only();
+ static bool profile_all_return();
+ static bool profile_return_for_invoke(methodHandle m, int bci);
public:
static int header_size() {
return sizeof(MethodData)/wordSize;
}
*** 1922,1929 ****
--- 2092,2100 ----
// verification
void verify_on(outputStream* st);
void verify_data_on(outputStream* st);
static bool profile_arguments();
+ static bool profile_return();
};
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
src/share/vm/oops/methodData.hpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File