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
};