src/share/vm/oops/methodDataOop.hpp

Print this page
rev 2893 : 7121756: Improve C1 inlining policy by using profiling at call sites
Summary: profile based recompilation of methods with C1 with more inlining.
Reviewed-by:

*** 170,179 **** --- 170,184 ---- assert(ProfileTraps, "used only under +ProfileTraps"); uint old_flags = (_header._struct._flags & flag_mask); _header._struct._flags = (new_state << trap_shift) | old_flags; } + #ifdef COMPILER1 + void set_profile_state(int state) { assert(C1ProfileInlining, "c1 profiling only"); _header._struct._flags = state; } + int profile_state() { assert(C1ProfileInlining, "c1 profiling only"); return _header._struct._flags; } + #endif + u1 flags() { return _header._struct._flags; } u2 bci() {
*** 362,371 **** --- 367,382 ---- ProfileData(DataLayout* data) { _data = data; } + #ifdef COMPILER1 + protected: + void set_profile_state(int state) { data()->set_profile_state(state); } + int profile_state() { return data()->profile_state(); } + #endif + public: // Constructor for invalid ProfileData. ProfileData(); u2 bci() {
*** 531,541 **** CounterData(DataLayout* layout) : BitData(layout) {} virtual bool is_CounterData() { return true; } static int static_cell_count() { ! return counter_cell_count; } virtual int cell_count() { return static_cell_count(); } --- 542,552 ---- CounterData(DataLayout* layout) : BitData(layout) {} virtual bool is_CounterData() { return true; } static int static_cell_count() { ! return counter_cell_count + ( COMPILER1_PRESENT(C1ProfileInlining ? BytesPerLong/BytesPerWord :) 0 ); } virtual int cell_count() { return static_cell_count(); }
*** 548,567 **** // Code generation support static ByteSize count_offset() { return cell_offset(count_off); } static ByteSize counter_data_size() { ! return cell_offset(counter_cell_count); } void set_count(uint count) { set_uint_at(count_off, count); } #ifndef PRODUCT void print_data_on(outputStream* st); #endif }; // JumpData // // A JumpData is used to access profiling information for a direct --- 559,639 ---- // Code generation support static ByteSize count_offset() { return cell_offset(count_off); } static ByteSize counter_data_size() { ! return cell_offset(counter_cell_count + ( COMPILER1_PRESENT(C1ProfileInlining ? BytesPerLong/BytesPerWord :) 0 )); } void set_count(uint count) { set_uint_at(count_off, count); } #ifndef PRODUCT void print_data_on(outputStream* st); #endif + + #ifdef COMPILER1 + // C1 implements profile based inlining. To detect a hot call site, + // a count of the number of times the call is taken and a timestamp + // of the first time the call is taken are needed. Together, they + // are used to compute a call site frequency = + // count / (current time - timestamp) + // that, can can be compared to thresholds to identify hot or warm + // or cold call sites. The state of a call site is kept here as + // well. This way it persists during the execution: a hot call site + // can be marked as such once for all and subsequent compilation + // will attempt inlining. + private: + union stamp { + jlong l; + uint u[BytesPerLong/BytesPerWord]; + }; + + enum state { + unseen_yet = 0, + seen, + hot, + warm, + cold + }; + + public: + bool is_unseen_yet() { return profile_state() == unseen_yet; } + bool is_seen() { return profile_state() == seen; } + bool is_hot() { return profile_state() == hot; } + bool is_warm() { return profile_state() == warm; } + bool is_cold() { return profile_state() == cold; } + void set_seen() { set_profile_state(seen); } + void set_hot() { set_profile_state(hot); } + void set_warm() { set_profile_state(warm); } + void set_cold() { set_profile_state(cold); } + + jlong timestamp() { + union stamp ts; + for(int i = 0; i < BytesPerLong/BytesPerWord; i++) { + ts.u[i] = uint_at(counter_cell_count + i); + } + return ts.l; + } + + void set_timestamp(jlong stamp) { + union stamp ts; + ts.l = stamp; + for(int i = 0; i < BytesPerLong/BytesPerWord; i++) { + set_uint_at(counter_cell_count + i, ts.u[i]); + } + } + + void init_if_first_seen() { + if (is_unseen_yet()) { + set_seen(); + jlong now = os::javaTimeNanos(); + set_timestamp(now); + } + } + #endif }; // JumpData // // A JumpData is used to access profiling information for a direct
*** 642,652 **** // that the check is reached, and a series of (klassOop, count) pairs // which are used to store a type profile for the receiver of the check. class ReceiverTypeData : public CounterData { protected: enum { ! receiver0_offset = counter_cell_count, count0_offset, receiver_type_row_cell_count = (count0_offset + 1) - receiver0_offset }; public: --- 714,724 ---- // that the check is reached, and a series of (klassOop, count) pairs // which are used to store a type profile for the receiver of the check. class ReceiverTypeData : public CounterData { protected: enum { ! receiver0_offset, count0_offset, receiver_type_row_cell_count = (count0_offset + 1) - receiver0_offset }; public:
*** 656,666 **** } virtual bool is_ReceiverTypeData() { return true; } static int static_cell_count() { ! return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count; } virtual int cell_count() { return static_cell_count(); } --- 728,738 ---- } virtual bool is_ReceiverTypeData() { return true; } static int static_cell_count() { ! return CounterData::static_cell_count() + (uint) TypeProfileWidth * receiver_type_row_cell_count; } virtual int cell_count() { return static_cell_count(); }
*** 668,681 **** // Direct accessors static uint row_limit() { return TypeProfileWidth; } static int receiver_cell_index(uint row) { ! return receiver0_offset + row * receiver_type_row_cell_count; } static int receiver_count_cell_index(uint row) { ! return count0_offset + row * receiver_type_row_cell_count; } // Get the receiver at row. The 'unchecked' version is needed by parallel old // gc; it does not assert the receiver is a klass. During compaction of the // perm gen, the klass may already have moved, so the is_klass() predicate --- 740,753 ---- // Direct accessors static uint row_limit() { return TypeProfileWidth; } static int receiver_cell_index(uint row) { ! return CounterData::static_cell_count() + receiver0_offset + row * receiver_type_row_cell_count; } static int receiver_count_cell_index(uint row) { ! return CounterData::static_cell_count() + count0_offset + row * receiver_type_row_cell_count; } // Get the receiver at row. The 'unchecked' version is needed by parallel old // gc; it does not assert the receiver is a klass. During compaction of the // perm gen, the klass may already have moved, so the is_klass() predicate
*** 789,798 **** --- 861,882 ---- // Direct accessors static ByteSize virtual_call_data_size() { return cell_offset(static_cell_count()); } + void new_receiver(Handle r) { + assert(TypeProfileWidth >= 2, "should be"); + + if (receiver(0) == NULL || receiver(0) == r->klass()) { + set_receiver(0, r->klass()); + set_receiver_count(0, DataLayout::counter_increment); + } else if (row_limit() > 1 && (receiver(1) == NULL || receiver(1) == r->klass())) { + set_receiver(1, r->klass()); + set_receiver_count(1, DataLayout::counter_increment); + } + } + #ifndef PRODUCT void print_data_on(outputStream* st); #endif };