--- old/src/share/vm/oops/methodData.hpp 2013-10-08 18:00:00.992110831 +0200 +++ new/src/share/vm/oops/methodData.hpp 2013-10-08 17:59:59.750999346 +0200 @@ -271,6 +271,8 @@ // data in a structured way. class ProfileData : public ResourceObj { friend class TypeEntries; + friend class TypeEntriesAtCall; + friend class ReturnTypeEntry; friend class TypeStackSlotEntries; private: #ifndef PRODUCT @@ -743,25 +745,177 @@ 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 profiling - // for a single argument the number of cells is unknown statically. + // 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 (TypeProfileArgsLimit > 1) ? 1 : 0; + return (arguments_profiling_enabled() && (TypeProfileArgsLimit > 1 || return_profiling_enabled())) ? 1 : 0; } static int cell_count_local_offset() { - assert(arguments_profiling_enabled() && TypeProfileArgsLimit > 1, "no cell count"); - return 0; - } + 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(); } - - // 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); + + 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) { @@ -772,28 +926,43 @@ int cell_count_no_header() const { return _pd->uint_at(cell_count_global_offset()); } - + 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: - // 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); + // 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: - - TypeStackSlotEntries(int base_off, ProfileData* pd) - : TypeEntries(base_off, pd) {} + 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 (TypeProfileArgsLimit > 1) { + 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()); } @@ -804,9 +973,14 @@ 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(nb > 0 && nb <= TypeProfileArgsLimit , "only when we profile args"); + assert((!has_arguments() && nb == 0) || (nb > 0 && nb <= TypeProfileArgsLimit) , "only when we profile args"); return nb; } else { assert(TypeProfileArgsLimit == 1, "at least one arg"); @@ -815,73 +989,58 @@ } int cell_count() const { - assert_arguments_profiling_enabled(); - if (TypeProfileArgsLimit > 1) { + if (arguments_profiling_enabled() && (TypeProfileArgsLimit > 1 || return_profiling_enabled())) { return _base_off + header_cell_count() + _pd->int_at_unchecked(cell_count_global_offset()); - } else { + } else if (arguments_profiling_enabled()) { return _base_off + TypeStackSlotEntries::per_arg_count(); - } + } else { + assert_return_profiling_enabled(); + return _base_off + ReturnTypeEntry::static_cell_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; + 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; } - // 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; + void set_argument_type(int i, Klass* k) { + intptr_t current = _args.type(i); + _args.set_type(i, TypeEntries::with_status(k, current)); } - // 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)); + void set_return_type(Klass* k) { + intptr_t current = _ret.type(); + _ret.set_type(TypeEntries::with_status(k, current)); } - // 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)); + // Code generation support + static ByteSize cell_count_offset() { + return in_ByteSize(cell_count_local_offset() * DataLayout::cell_size); } - // 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 args_data_offset() { + return in_ByteSize(header_cell_count() * DataLayout::cell_size); } - static ByteSize per_arg_size() { - return in_ByteSize(per_arg_cell_count * DataLayout::cell_size); + static ByteSize stack_slot_offset(int i) { + return in_ByteSize(stack_slot_local_offset(i) * DataLayout::cell_size); } - static int per_arg_count() { - return per_arg_cell_count ; + static ByteSize argument_type_offset(int i) { + return in_ByteSize(argument_type_local_offset(i) * DataLayout::cell_size); } - // Code generation support - static ByteSize cell_count_offset() { - return in_ByteSize(cell_count_local_offset() * DataLayout::cell_size); - } - - static ByteSize args_data_offset() { - return in_ByteSize(header_cell_count() * DataLayout::cell_size); - } - - 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); - } + ByteSize return_type_offset() { + return _ret.type_offset(); + } // GC support void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); @@ -894,18 +1053,19 @@ // CallTypeData // // A CallTypeData is used to access profiling information about a non -// virtual call for which we collect type information about arguments. +// virtual call for which we collect type information about arguments +// and return value. class CallTypeData : public CounterData { private: - TypeStackSlotEntries _args; + TypeEntriesAtCall _args_and_ret; public: CallTypeData(DataLayout* layout) : - CounterData(layout), _args(CounterData::static_cell_count(), this) { + CounterData(layout), _args_and_ret(CounterData::static_cell_count(), this) { assert(layout->tag() == DataLayout::call_type_data_tag, "wrong type"); } - const TypeStackSlotEntries* args() const { return &_args; } + const TypeEntriesAtCall* args_and_ret() const { return &_args_and_ret; } virtual bool is_CallTypeData() const { return true; } @@ -914,38 +1074,41 @@ } static int compute_cell_count(BytecodeStream* stream) { - return CounterData::static_cell_count() + TypeStackSlotEntries::compute_cell_count(stream); + return CounterData::static_cell_count() + TypeEntriesAtCall::compute_cell_count(stream); } static void initialize(DataLayout* dl, int cell_count) { - TypeStackSlotEntries::initialize(dl, CounterData::static_cell_count(), cell_count); + TypeEntriesAtCall::initialize(dl, CounterData::static_cell_count(), cell_count); } virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) { - _args.post_initialize(stream); + _args_and_ret.post_initialize(stream); } virtual int cell_count() const { - return _args.cell_count(); + return _args_and_ret.cell_count(); } uint number_of_arguments() const { - return args()->number_of_arguments(); + return args_and_ret()->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)); + _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()) + TypeStackSlotEntries::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.clean_weak_klass_links(is_alive_closure); + _args_and_ret.clean_weak_klass_links(is_alive_closure); } #ifndef PRODUCT @@ -1098,18 +1261,18 @@ // // A VirtualCallTypeData is used to access profiling information about // a virtual call for which we collect type information about -// arguments. +// arguments and return value. class VirtualCallTypeData : public VirtualCallData { private: - TypeStackSlotEntries _args; + TypeEntriesAtCall _args_and_ret; public: VirtualCallTypeData(DataLayout* layout) : - VirtualCallData(layout), _args(VirtualCallData::static_cell_count(), this) { + VirtualCallData(layout), _args_and_ret(VirtualCallData::static_cell_count(), this) { assert(layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); } - const TypeStackSlotEntries* args() const { return &_args; } + const TypeEntriesAtCall* args_and_ret() const { return &_args_and_ret; } virtual bool is_VirtualCallTypeData() const { return true; } @@ -1118,39 +1281,42 @@ } static int compute_cell_count(BytecodeStream* stream) { - return VirtualCallData::static_cell_count() + TypeStackSlotEntries::compute_cell_count(stream); + return VirtualCallData::static_cell_count() + TypeEntriesAtCall::compute_cell_count(stream); } static void initialize(DataLayout* dl, int cell_count) { - TypeStackSlotEntries::initialize(dl, VirtualCallData::static_cell_count(), cell_count); + TypeEntriesAtCall::initialize(dl, VirtualCallData::static_cell_count(), cell_count); } virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) { - _args.post_initialize(stream); + _args_and_ret.post_initialize(stream); } virtual int cell_count() const { - return _args.cell_count(); + return _args_and_ret.cell_count(); } uint number_of_arguments() const { - return args()->number_of_arguments(); + return args_and_ret()->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)); + _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()) + TypeStackSlotEntries::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.clean_weak_klass_links(is_alive_closure); + _args_and_ret.clean_weak_klass_links(is_alive_closure); } #ifndef PRODUCT @@ -1682,6 +1848,10 @@ 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() { @@ -1924,6 +2094,7 @@ void verify_data_on(outputStream* st); static bool profile_arguments(); + static bool profile_return(); }; #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP