diff -r 3068270ba476 -r 2b8e28fdf503 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Wed Oct 16 10:52:41 2013 +0200 +++ b/src/share/vm/oops/methodData.hpp Tue Nov 05 17:38:04 2013 -0800 @@ -72,6 +72,8 @@ // // Overlay for generic profiling data. class DataLayout VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + private: // Every data layout begins with a header. This header // contains a tag, which is used to indicate the size/layout @@ -115,7 +117,10 @@ ret_data_tag, branch_data_tag, multi_branch_data_tag, - arg_info_data_tag + arg_info_data_tag, + call_type_data_tag, + virtual_call_type_data_tag, + parameters_type_data_tag }; enum { @@ -163,7 +168,7 @@ // occurred, and the MDO shows N occurrences of X, we make the // simplifying assumption that all N occurrences can be blamed // on that BCI. - int trap_state() { + int trap_state() const { return ((_header._struct._flags >> trap_shift) & trap_mask); } @@ -173,11 +178,11 @@ _header._struct._flags = (new_state << trap_shift) | old_flags; } - u1 flags() { + u1 flags() const { return _header._struct._flags; } - u2 bci() { + u2 bci() const { return _header._struct._bci; } @@ -196,7 +201,7 @@ void release_set_cell_at(int index, intptr_t value) { OrderAccess::release_store_ptr(&_cells[index], value); } - intptr_t cell_at(int index) { + intptr_t cell_at(int index) const { return _cells[index]; } @@ -204,7 +209,7 @@ assert(flag_number < flag_limit, "oob"); _header._struct._flags |= (0x1 << flag_number); } - bool flag_at(int flag_number) { + bool flag_at(int flag_number) const { assert(flag_number < flag_limit, "oob"); return (_header._struct._flags & (0x1 << flag_number)) != 0; } @@ -257,19 +262,24 @@ class CounterData; class ReceiverTypeData; class VirtualCallData; +class VirtualCallTypeData; class RetData; +class CallTypeData; class JumpData; class BranchData; class ArrayData; class MultiBranchData; class ArgInfoData; - +class ParametersTypeData; // ProfileData // // 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 ReturnTypeEntry; + friend class TypeStackSlotEntries; private: #ifndef PRODUCT enum { @@ -283,6 +293,7 @@ protected: DataLayout* data() { return _data; } + const DataLayout* data() const { return _data; } enum { cell_size = DataLayout::cell_size @@ -290,7 +301,7 @@ public: // How many cells are in this? - virtual int cell_count() { + virtual int cell_count() const { ShouldNotReachHere(); return -1; } @@ -310,7 +321,7 @@ assert(0 <= index && index < cell_count(), "oob"); data()->release_set_cell_at(index, value); } - intptr_t intptr_at(int index) { + intptr_t intptr_at(int index) const { assert(0 <= index && index < cell_count(), "oob"); return data()->cell_at(index); } @@ -320,7 +331,7 @@ void release_set_uint_at(int index, uint value) { release_set_intptr_at(index, (intptr_t) value); } - uint uint_at(int index) { + uint uint_at(int index) const { return (uint)intptr_at(index); } void set_int_at(int index, int value) { @@ -329,23 +340,23 @@ void release_set_int_at(int index, int value) { release_set_intptr_at(index, (intptr_t) value); } - int int_at(int index) { + int int_at(int index) const { return (int)intptr_at(index); } - int int_at_unchecked(int index) { + int int_at_unchecked(int index) const { return (int)data()->cell_at(index); } void set_oop_at(int index, oop value) { - set_intptr_at(index, (intptr_t) value); + set_intptr_at(index, cast_from_oop(value)); } - oop oop_at(int index) { - return (oop)intptr_at(index); + oop oop_at(int index) const { + return cast_to_oop(intptr_at(index)); } void set_flag_at(int flag_number) { data()->set_flag_at(flag_number); } - bool flag_at(int flag_number) { + bool flag_at(int flag_number) const { return data()->flag_at(flag_number); } @@ -400,7 +411,7 @@ // Constructor for invalid ProfileData. ProfileData(); - u2 bci() { + u2 bci() const { return data()->bci(); } @@ -408,7 +419,7 @@ return (address)_data; } - int trap_state() { + int trap_state() const { return data()->trap_state(); } void set_trap_state(int new_state) { @@ -416,58 +427,73 @@ } // Type checking - virtual bool is_BitData() { return false; } - virtual bool is_CounterData() { return false; } - virtual bool is_JumpData() { return false; } - virtual bool is_ReceiverTypeData(){ return false; } - virtual bool is_VirtualCallData() { return false; } - virtual bool is_RetData() { return false; } - virtual bool is_BranchData() { return false; } - virtual bool is_ArrayData() { return false; } - virtual bool is_MultiBranchData() { return false; } - virtual bool is_ArgInfoData() { return false; } + virtual bool is_BitData() const { return false; } + virtual bool is_CounterData() const { return false; } + virtual bool is_JumpData() const { return false; } + virtual bool is_ReceiverTypeData()const { return false; } + virtual bool is_VirtualCallData() const { return false; } + virtual bool is_RetData() const { return false; } + virtual bool is_BranchData() const { return false; } + virtual bool is_ArrayData() const { return false; } + virtual bool is_MultiBranchData() const { return false; } + virtual bool is_ArgInfoData() const { return false; } + virtual bool is_CallTypeData() const { return false; } + virtual bool is_VirtualCallTypeData()const { return false; } + virtual bool is_ParametersTypeData() const { return false; } - BitData* as_BitData() { + BitData* as_BitData() const { assert(is_BitData(), "wrong type"); return is_BitData() ? (BitData*) this : NULL; } - CounterData* as_CounterData() { + CounterData* as_CounterData() const { assert(is_CounterData(), "wrong type"); return is_CounterData() ? (CounterData*) this : NULL; } - JumpData* as_JumpData() { + JumpData* as_JumpData() const { assert(is_JumpData(), "wrong type"); return is_JumpData() ? (JumpData*) this : NULL; } - ReceiverTypeData* as_ReceiverTypeData() { + ReceiverTypeData* as_ReceiverTypeData() const { assert(is_ReceiverTypeData(), "wrong type"); return is_ReceiverTypeData() ? (ReceiverTypeData*)this : NULL; } - VirtualCallData* as_VirtualCallData() { + VirtualCallData* as_VirtualCallData() const { assert(is_VirtualCallData(), "wrong type"); return is_VirtualCallData() ? (VirtualCallData*)this : NULL; } - RetData* as_RetData() { + RetData* as_RetData() const { assert(is_RetData(), "wrong type"); return is_RetData() ? (RetData*) this : NULL; } - BranchData* as_BranchData() { + BranchData* as_BranchData() const { assert(is_BranchData(), "wrong type"); return is_BranchData() ? (BranchData*) this : NULL; } - ArrayData* as_ArrayData() { + ArrayData* as_ArrayData() const { assert(is_ArrayData(), "wrong type"); return is_ArrayData() ? (ArrayData*) this : NULL; } - MultiBranchData* as_MultiBranchData() { + MultiBranchData* as_MultiBranchData() const { assert(is_MultiBranchData(), "wrong type"); return is_MultiBranchData() ? (MultiBranchData*)this : NULL; } - ArgInfoData* as_ArgInfoData() { + ArgInfoData* as_ArgInfoData() const { assert(is_ArgInfoData(), "wrong type"); return is_ArgInfoData() ? (ArgInfoData*)this : NULL; } + CallTypeData* as_CallTypeData() const { + assert(is_CallTypeData(), "wrong type"); + return is_CallTypeData() ? (CallTypeData*)this : NULL; + } + VirtualCallTypeData* as_VirtualCallTypeData() const { + assert(is_VirtualCallTypeData(), "wrong type"); + return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL; + } + ParametersTypeData* as_ParametersTypeData() const { + assert(is_ParametersTypeData(), "wrong type"); + return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL; + } // Subclass specific initialization @@ -481,15 +507,15 @@ // an oop in a ProfileData to the ci equivalent. Generally speaking, // most ProfileData don't require any translation, so we provide the null // translation here, and the required translators are in the ci subclasses. - virtual void translate_from(ProfileData* data) {} + virtual void translate_from(const ProfileData* data) {} - virtual void print_data_on(outputStream* st) { + virtual void print_data_on(outputStream* st) const { ShouldNotReachHere(); } #ifndef PRODUCT - void print_shared(outputStream* st, const char* name); - void tab(outputStream* st); + void print_shared(outputStream* st, const char* name) const; + void tab(outputStream* st, bool first = false) const; #endif }; @@ -508,13 +534,13 @@ BitData(DataLayout* layout) : ProfileData(layout) { } - virtual bool is_BitData() { return true; } + virtual bool is_BitData() const { return true; } static int static_cell_count() { return bit_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -550,7 +576,7 @@ #endif // CC_INTERP #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -566,18 +592,18 @@ public: CounterData(DataLayout* layout) : BitData(layout) {} - virtual bool is_CounterData() { return true; } + virtual bool is_CounterData() const { return true; } static int static_cell_count() { return counter_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint count() { + uint count() const { return uint_at(count_off); } @@ -613,7 +639,7 @@ #endif // CC_INTERP #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -641,18 +667,18 @@ layout->tag() == DataLayout::branch_data_tag, "wrong type"); } - virtual bool is_JumpData() { return true; } + virtual bool is_JumpData() const { return true; } static int static_cell_count() { return jump_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint taken() { + uint taken() const { return uint_at(taken_off_set); } @@ -669,7 +695,7 @@ return cnt; } - int displacement() { + int displacement() const { return int_at(displacement_off_set); } @@ -700,7 +726,417 @@ void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; +#endif +}; + +// Entries in a ProfileData object to record types: it can either be +// none (no profile), unknown (conflicting profile data) or a klass if +// a single one is seen. Whether a null reference was seen is also +// recorded. No counter is associated with the type and a single type +// is tracked (unlike VirtualCallData). +class TypeEntries { + +public: + + // A single cell is used to record information for a type: + // - the cell is initialized to 0 + // - when a type is discovered it is stored in the cell + // - bit zero of the cell is used to record whether a null reference + // was encountered or not + // - bit 1 is set to record a conflict in the type information + + enum { + null_seen = 1, + type_mask = ~null_seen, + type_unknown = 2, + status_bits = null_seen | type_unknown, + type_klass_mask = ~status_bits + }; + + // what to initialize a cell to + static intptr_t type_none() { + return 0; + } + + // null seen = bit 0 set? + static bool was_null_seen(intptr_t v) { + return (v & null_seen) != 0; + } + + // conflicting type information = bit 1 set? + static bool is_type_unknown(intptr_t v) { + return (v & type_unknown) != 0; + } + + // not type information yet = all bits cleared, ignoring bit 0? + static bool is_type_none(intptr_t v) { + return (v & type_mask) == 0; + } + + // recorded type: cell without bit 0 and 1 + static intptr_t klass_part(intptr_t v) { + intptr_t r = v & type_klass_mask; + assert (r != 0, "invalid"); + return r; + } + + // type recorded + static Klass* valid_klass(intptr_t k) { + if (!is_type_none(k) && + !is_type_unknown(k)) { + return (Klass*)klass_part(k); + } else { + return NULL; + } + } + + static intptr_t with_status(intptr_t k, intptr_t in) { + return k | (in & status_bits); + } + + static intptr_t with_status(Klass* k, intptr_t in) { + return with_status((intptr_t)k, in); + } + +#ifndef PRODUCT + static void print_klass(outputStream* st, intptr_t k); +#endif + + // GC support + static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p); + +protected: + // ProfileData object these entries are part of + ProfileData* _pd; + // offset within the ProfileData object where the entries start + const int _base_off; + + TypeEntries(int base_off) + : _base_off(base_off), _pd(NULL) {} + + void set_intptr_at(int index, intptr_t value) { + _pd->set_intptr_at(index, value); + } + + intptr_t intptr_at(int index) const { + return _pd->intptr_at(index); + } + +public: + void set_profile_data(ProfileData* pd) { + _pd = pd; + } +}; + +// Type entries used for arguments passed at a call and parameters on +// method entry. 2 cells per entry: one for the type encoded as in +// TypeEntries and one initialized with the stack slot where the +// profiled object is to be found so that the interpreter can locate +// it quickly. +class TypeStackSlotEntries : public TypeEntries { + +private: + enum { + 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 _number_of_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, int nb_entries) + : TypeEntries(base_off), _number_of_entries(nb_entries) {} + + static int compute_cell_count(Symbol* signature, bool include_receiver, int max); + + void post_initialize(Symbol* signature, bool has_receiver, bool include_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 < _number_of_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 < _number_of_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 < _number_of_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 < _number_of_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) + : TypeEntries(base_off) {} + + void post_initialize() { + set_type(type_none()); + } + + intptr_t type() const { + return _pd->intptr_at(_base_off); + } + + void set_type(intptr_t k) { + _pd->set_intptr_at(_base_off, k); + } + + static int static_cell_count() { + return cell_count; + } + + static ByteSize size() { + return in_ByteSize(cell_count * DataLayout::cell_size); + } + + ByteSize type_offset() { + return DataLayout::cell_offset(_base_off); + } + + // 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: + static int stack_slot_local_offset(int i) { + return header_cell_count() + TypeStackSlotEntries::stack_slot_local_offset(i); + } + + static int argument_type_local_offset(int i) { + return header_cell_count() + TypeStackSlotEntries::type_local_offset(i);; + } + +public: + + static int header_cell_count() { + return 1; + } + + static int cell_count_local_offset() { + return 0; + } + + static int compute_cell_count(BytecodeStream* stream); + + static void initialize(DataLayout* dl, int base, int cell_count) { + int off = base + cell_count_local_offset(); + dl->set_cell_at(off, cell_count - base - header_cell_count()); + } + + static bool arguments_profiling_enabled(); + static bool return_profiling_enabled(); + + // 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 argument_type_offset(int i) { + return in_ByteSize(argument_type_local_offset(i) * DataLayout::cell_size); + } +}; + +// 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: + // entries for arguments if any + TypeStackSlotEntries _args; + // entry for return type if any + ReturnTypeEntry _ret; + + int cell_count_global_offset() const { + return CounterData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset(); + } + + // number of cells not counting the header + int cell_count_no_header() const { + return uint_at(cell_count_global_offset()); + } + + void check_number_of_arguments(int total) { + assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); + } + +public: + CallTypeData(DataLayout* layout) : + CounterData(layout), + _args(CounterData::static_cell_count()+TypeEntriesAtCall::header_cell_count(), number_of_arguments()), + _ret(cell_count() - ReturnTypeEntry::static_cell_count()) + { + assert(layout->tag() == DataLayout::call_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _args.set_profile_data(this); + _ret.set_profile_data(this); + } + + const TypeStackSlotEntries* args() const { + assert(has_arguments(), "no profiling of arguments"); + return &_args; + } + + const ReturnTypeEntry* ret() const { + assert(has_return(), "no profiling of return value"); + return &_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); + + virtual int cell_count() const { + return CounterData::static_cell_count() + + TypeEntriesAtCall::header_cell_count() + + int_at_unchecked(cell_count_global_offset()); + } + + int number_of_arguments() const { + return cell_count_no_header() / TypeStackSlotEntries::per_arg_count(); + } + + void set_argument_type(int i, Klass* k) { + assert(has_arguments(), "no arguments!"); + intptr_t current = _args.type(i); + _args.set_type(i, TypeEntries::with_status(k, current)); + } + + void set_return_type(Klass* k) { + assert(has_return(), "no return!"); + intptr_t current = _ret.type(); + _ret.set_type(TypeEntries::with_status(k, current)); + } + + // 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 { + bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); + assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); + return res; + } + + // 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 { + bool res = (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0; + assert (!res || TypeEntriesAtCall::return_profiling_enabled(), "no profiling of return values"); + return res; + } + + // 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) { + if (has_arguments()) { + _args.clean_weak_klass_links(is_alive_closure); + } + if (has_return()) { + _ret.clean_weak_klass_links(is_alive_closure); + } + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; #endif }; @@ -721,16 +1157,17 @@ public: ReceiverTypeData(DataLayout* layout) : CounterData(layout) { assert(layout->tag() == DataLayout::receiver_type_data_tag || - layout->tag() == DataLayout::virtual_call_data_tag, "wrong type"); + layout->tag() == DataLayout::virtual_call_data_tag || + layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); } - virtual bool is_ReceiverTypeData() { return true; } + virtual bool is_ReceiverTypeData() const { return true; } static int static_cell_count() { return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -745,7 +1182,7 @@ return count0_offset + row * receiver_type_row_cell_count; } - Klass* receiver(uint row) { + Klass* receiver(uint row) const { assert(row < row_limit(), "oob"); Klass* recv = (Klass*)intptr_at(receiver_cell_index(row)); @@ -758,7 +1195,7 @@ set_intptr_at(receiver_cell_index(row), (uintptr_t)k); } - uint receiver_count(uint row) { + uint receiver_count(uint row) const { assert(row < row_limit(), "oob"); return uint_at(receiver_count_cell_index(row)); } @@ -843,8 +1280,8 @@ #endif // CC_INTERP #ifndef PRODUCT - void print_receiver_data_on(outputStream* st); - void print_data_on(outputStream* st); + void print_receiver_data_on(outputStream* st) const; + void print_data_on(outputStream* st) const; #endif }; @@ -855,10 +1292,11 @@ class VirtualCallData : public ReceiverTypeData { public: VirtualCallData(DataLayout* layout) : ReceiverTypeData(layout) { - assert(layout->tag() == DataLayout::virtual_call_data_tag, "wrong type"); + assert(layout->tag() == DataLayout::virtual_call_data_tag || + layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); } - virtual bool is_VirtualCallData() { return true; } + virtual bool is_VirtualCallData() const { return true; } static int static_cell_count() { // At this point we could add more profile state, e.g., for arguments. @@ -866,7 +1304,7 @@ return ReceiverTypeData::static_cell_count(); } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -886,7 +1324,133 @@ #endif // CC_INTERP #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; +#endif +}; + +// 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: + // entries for arguments if any + TypeStackSlotEntries _args; + // entry for return type if any + ReturnTypeEntry _ret; + + int cell_count_global_offset() const { + return VirtualCallData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset(); + } + + // number of cells not counting the header + int cell_count_no_header() const { + return uint_at(cell_count_global_offset()); + } + + void check_number_of_arguments(int total) { + assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); + } + +public: + VirtualCallTypeData(DataLayout* layout) : + VirtualCallData(layout), + _args(VirtualCallData::static_cell_count()+TypeEntriesAtCall::header_cell_count(), number_of_arguments()), + _ret(cell_count() - ReturnTypeEntry::static_cell_count()) + { + assert(layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _args.set_profile_data(this); + _ret.set_profile_data(this); + } + + const TypeStackSlotEntries* args() const { + assert(has_arguments(), "no profiling of arguments"); + return &_args; + } + + const ReturnTypeEntry* ret() const { + assert(has_return(), "no profiling of return value"); + return &_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); + + virtual int cell_count() const { + return VirtualCallData::static_cell_count() + + TypeEntriesAtCall::header_cell_count() + + int_at_unchecked(cell_count_global_offset()); + } + + int number_of_arguments() const { + return cell_count_no_header() / TypeStackSlotEntries::per_arg_count(); + } + + void set_argument_type(int i, Klass* k) { + assert(has_arguments(), "no arguments!"); + intptr_t current = _args.type(i); + _args.set_type(i, TypeEntries::with_status(k, current)); + } + + void set_return_type(Klass* k) { + assert(has_return(), "no return!"); + intptr_t current = _ret.type(); + _ret.set_type(TypeEntries::with_status(k, current)); + } + + // 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 { + bool res = (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0; + assert (!res || TypeEntriesAtCall::return_profiling_enabled(), "no profiling of return values"); + return res; + } + + // 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 { + bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); + assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); + return res; + } + + // 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); + if (has_arguments()) { + _args.clean_weak_klass_links(is_alive_closure); + } + if (has_return()) { + _ret.clean_weak_klass_links(is_alive_closure); + } + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; #endif }; @@ -929,7 +1493,7 @@ assert(layout->tag() == DataLayout::ret_data_tag, "wrong type"); } - virtual bool is_RetData() { return true; } + virtual bool is_RetData() const { return true; } enum { no_bci = -1 // value of bci when bci1/2 are not in use. @@ -939,7 +1503,7 @@ return counter_cell_count + (uint) BciProfileWidth * ret_row_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -957,13 +1521,13 @@ } // Direct accessors - int bci(uint row) { + int bci(uint row) const { return int_at(bci_cell_index(row)); } - uint bci_count(uint row) { + uint bci_count(uint row) const { return uint_at(bci_count_cell_index(row)); } - int bci_displacement(uint row) { + int bci_displacement(uint row) const { return int_at(bci_displacement_cell_index(row)); } @@ -989,7 +1553,7 @@ void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -1014,18 +1578,18 @@ assert(layout->tag() == DataLayout::branch_data_tag, "wrong type"); } - virtual bool is_BranchData() { return true; } + virtual bool is_BranchData() const { return true; } static int static_cell_count() { return branch_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint not_taken() { + uint not_taken() const { return uint_at(not_taken_off_set); } @@ -1067,7 +1631,7 @@ void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -1085,15 +1649,15 @@ array_start_off_set }; - uint array_uint_at(int index) { + uint array_uint_at(int index) const { int aindex = index + array_start_off_set; return uint_at(aindex); } - int array_int_at(int index) { + int array_int_at(int index) const { int aindex = index + array_start_off_set; return int_at(aindex); } - oop array_oop_at(int index) { + oop array_oop_at(int index) const { int aindex = index + array_start_off_set; return oop_at(aindex); } @@ -1124,17 +1688,17 @@ public: ArrayData(DataLayout* layout) : ProfileData(layout) {} - virtual bool is_ArrayData() { return true; } + virtual bool is_ArrayData() const { return true; } static int static_cell_count() { return -1; } - int array_len() { + int array_len() const { return int_at_unchecked(array_len_off_set); } - virtual int cell_count() { + virtual int cell_count() const { return array_len() + 1; } @@ -1181,29 +1745,29 @@ assert(layout->tag() == DataLayout::multi_branch_data_tag, "wrong type"); } - virtual bool is_MultiBranchData() { return true; } + virtual bool is_MultiBranchData() const { return true; } static int compute_cell_count(BytecodeStream* stream); - int number_of_cases() { + int number_of_cases() const { int alen = array_len() - 2; // get rid of default case here. assert(alen % per_case_cell_count == 0, "must be even"); return (alen / per_case_cell_count); } - uint default_count() { + uint default_count() const { return array_uint_at(default_count_off_set); } - int default_displacement() { + int default_displacement() const { return array_int_at(default_disaplacement_off_set); } - uint count_at(int index) { + uint count_at(int index) const { return array_uint_at(case_array_start + index * per_case_cell_count + relative_count_off_set); } - int displacement_at(int index) { + int displacement_at(int index) const { return array_int_at(case_array_start + index * per_case_cell_count + relative_displacement_off_set); @@ -1260,7 +1824,7 @@ void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -1271,14 +1835,14 @@ assert(layout->tag() == DataLayout::arg_info_data_tag, "wrong type"); } - virtual bool is_ArgInfoData() { return true; } + virtual bool is_ArgInfoData() const { return true; } - int number_of_args() { + int number_of_args() const { return array_len(); } - uint arg_modified(int arg) { + uint arg_modified(int arg) const { return array_uint_at(arg); } @@ -1287,10 +1851,79 @@ } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; +// ParametersTypeData +// +// A ParametersTypeData is used to access profiling information about +// types of parameters to a method +class ParametersTypeData : public ArrayData { + +private: + TypeStackSlotEntries _parameters; + + static int stack_slot_local_offset(int i) { + assert_profiling_enabled(); + return array_start_off_set + TypeStackSlotEntries::stack_slot_local_offset(i); + } + + static int type_local_offset(int i) { + assert_profiling_enabled(); + return array_start_off_set + TypeStackSlotEntries::type_local_offset(i); + } + + static bool profiling_enabled(); + static void assert_profiling_enabled() { + assert(profiling_enabled(), "method parameters profiling should be on"); + } + +public: + ParametersTypeData(DataLayout* layout) : ArrayData(layout), _parameters(1, number_of_parameters()) { + assert(layout->tag() == DataLayout::parameters_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _parameters.set_profile_data(this); + } + + static int compute_cell_count(Method* m); + + virtual bool is_ParametersTypeData() const { return true; } + + virtual void post_initialize(BytecodeStream* stream, MethodData* mdo); + + int number_of_parameters() const { + return array_len() / TypeStackSlotEntries::per_arg_count(); + } + + const TypeStackSlotEntries* parameters() const { return &_parameters; } + + uint stack_slot(int i) const { + return _parameters.stack_slot(i); + } + + void set_type(int i, Klass* k) { + intptr_t current = _parameters.type(i); + _parameters.set_type(i, TypeEntries::with_status((intptr_t)k, current)); + } + + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) { + _parameters.clean_weak_klass_links(is_alive_closure); + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; +#endif + + static ByteSize stack_slot_offset(int i) { + return cell_offset(stack_slot_local_offset(i)); + } + + static ByteSize type_offset(int i) { + return cell_offset(type_local_offset(i)); + } +}; + // MethodData* // // A MethodData* holds information which has been collected about @@ -1405,6 +2038,10 @@ // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; + // data index for the area dedicated to parameters. -1 if no + // parameter profiling. + int _parameters_type_data_di; + // Beginning of the data entries intptr_t _data[1]; @@ -1460,6 +2097,24 @@ // return the argument info cell ArgInfoData *arg_info(); + enum { + no_type_profile = 0, + type_profile_jsr292 = 1, + type_profile_all = 2 + }; + + 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_all_return(); + static bool profile_return_for_invoke(methodHandle m, int bci); + static int profile_parameters_flag(); + static bool profile_parameters_jsr292_only(); + static bool profile_all_parameters(); + public: static int header_size() { return sizeof(MethodData)/wordSize; @@ -1665,6 +2320,16 @@ } } + // Return pointer to area dedicated to parameters in MDO + ParametersTypeData* parameters_type_data() const { + return _parameters_type_data_di != -1 ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL; + } + + int parameters_type_data_di() const { + assert(_parameters_type_data_di != -1, "no args type data"); + return _parameters_type_data_di; + } + // Support for code generation static ByteSize data_offset() { return byte_offset_of(MethodData, _data[0]); @@ -1677,6 +2342,10 @@ return byte_offset_of(MethodData, _backedge_counter); } + static ByteSize parameters_type_data_di_offset() { + return byte_offset_of(MethodData, _parameters_type_data_di); + } + // Deallocation support - no pointer fields to deallocate void deallocate_contents(ClassLoaderData* loader_data) {} @@ -1699,6 +2368,12 @@ // verification void verify_on(outputStream* st); void verify_data_on(outputStream* st); + + static bool profile_parameters_for_method(methodHandle m); + static bool profile_arguments(); + static bool profile_return(); + static bool profile_parameters(); + static bool profile_return_jsr292_only(); }; #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP