8031752: Failed speculative optimizations should be reattempted when root of compilation is different

Support for speculative traps that keep track of the root of the compilation in which a trap occurs.

Reviewed-by: kvn, twisti
This commit is contained in:
Roland Westrelin 2014-02-25 18:16:24 +01:00
parent 532b570e81
commit 493557fc90
16 changed files with 772 additions and 164 deletions

View file

@ -120,7 +120,8 @@ public:
arg_info_data_tag,
call_type_data_tag,
virtual_call_type_data_tag,
parameters_type_data_tag
parameters_type_data_tag,
speculative_trap_data_tag
};
enum {
@ -189,8 +190,11 @@ public:
void set_header(intptr_t value) {
_header._bits = value;
}
void release_set_header(intptr_t value) {
OrderAccess::release_store_ptr(&_header._bits, value);
bool atomic_set_header(intptr_t value) {
if (Atomic::cmpxchg_ptr(value, (volatile intptr_t*)&_header._bits, 0) == 0) {
return true;
}
return false;
}
intptr_t header() {
return _header._bits;
@ -271,6 +275,7 @@ class ArrayData;
class MultiBranchData;
class ArgInfoData;
class ParametersTypeData;
class SpeculativeTrapData;
// ProfileData
//
@ -291,6 +296,8 @@ private:
// This is a pointer to a section of profiling data.
DataLayout* _data;
char* print_data_on_helper(const MethodData* md) const;
protected:
DataLayout* data() { return _data; }
const DataLayout* data() const { return _data; }
@ -440,6 +447,7 @@ public:
virtual bool is_CallTypeData() const { return false; }
virtual bool is_VirtualCallTypeData()const { return false; }
virtual bool is_ParametersTypeData() const { return false; }
virtual bool is_SpeculativeTrapData()const { return false; }
BitData* as_BitData() const {
@ -494,6 +502,10 @@ public:
assert(is_ParametersTypeData(), "wrong type");
return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL;
}
SpeculativeTrapData* as_SpeculativeTrapData() const {
assert(is_SpeculativeTrapData(), "wrong type");
return is_SpeculativeTrapData() ? (SpeculativeTrapData*)this : NULL;
}
// Subclass specific initialization
@ -509,12 +521,14 @@ public:
// translation here, and the required translators are in the ci subclasses.
virtual void translate_from(const ProfileData* data) {}
virtual void print_data_on(outputStream* st) const {
virtual void print_data_on(outputStream* st, const char* extra = NULL) const {
ShouldNotReachHere();
}
void print_data_on(outputStream* st, const MethodData* md) const;
#ifndef PRODUCT
void print_shared(outputStream* st, const char* name) const;
void print_shared(outputStream* st, const char* name, const char* extra) const;
void tab(outputStream* st, bool first = false) const;
#endif
};
@ -576,7 +590,7 @@ public:
#endif // CC_INTERP
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -639,7 +653,7 @@ public:
#endif // CC_INTERP
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -726,7 +740,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1137,7 +1151,7 @@ public:
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1282,7 +1296,7 @@ public:
#ifndef PRODUCT
void print_receiver_data_on(outputStream* st) const;
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1325,7 +1339,7 @@ public:
#endif // CC_INTERP
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1451,7 +1465,7 @@ public:
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1554,7 +1568,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1632,7 +1646,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1825,7 +1839,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1852,7 +1866,7 @@ public:
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1913,7 +1927,7 @@ public:
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
static ByteSize stack_slot_offset(int i) {
@ -1925,6 +1939,54 @@ public:
}
};
// SpeculativeTrapData
//
// A SpeculativeTrapData is used to record traps due to type
// speculation. It records the root of the compilation: that type
// speculation is wrong in the context of one compilation (for
// method1) doesn't mean it's wrong in the context of another one (for
// method2). Type speculation could have more/different data in the
// context of the compilation of method2 and it's worthwhile to try an
// optimization that failed for compilation of method1 in the context
// of compilation of method2.
// Space for SpeculativeTrapData entries is allocated from the extra
// data space in the MDO. If we run out of space, the trap data for
// the ProfileData at that bci is updated.
class SpeculativeTrapData : public ProfileData {
protected:
enum {
method_offset,
speculative_trap_cell_count
};
public:
SpeculativeTrapData(DataLayout* layout) : ProfileData(layout) {
assert(layout->tag() == DataLayout::speculative_trap_data_tag, "wrong type");
}
virtual bool is_SpeculativeTrapData() const { return true; }
static int static_cell_count() {
return speculative_trap_cell_count;
}
virtual int cell_count() const {
return static_cell_count();
}
// Direct accessor
Method* method() const {
return (Method*)intptr_at(method_offset);
}
void set_method(Method* m) {
set_intptr_at(method_offset, (intptr_t)m);
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// MethodData*
//
// A MethodData* holds information which has been collected about
@ -1994,7 +2056,7 @@ public:
// Whole-method sticky bits and flags
enum {
_trap_hist_limit = 17, // decoupled from Deoptimization::Reason_LIMIT
_trap_hist_limit = 18, // decoupled from Deoptimization::Reason_LIMIT
_trap_hist_mask = max_jubyte,
_extra_data_count = 4 // extra DataLayout headers, for trap history
}; // Public flag values
@ -2049,6 +2111,7 @@ private:
// Helper for size computation
static int compute_data_size(BytecodeStream* stream);
static int bytecode_cell_count(Bytecodes::Code code);
static bool is_speculative_trap_bytecode(Bytecodes::Code code);
enum { no_profile_data = -1, variable_cell_count = -2 };
// Helper for initialization
@ -2092,8 +2155,9 @@ private:
// What is the index of the first data entry?
int first_di() const { return 0; }
ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp);
// Find or create an extra ProfileData:
ProfileData* bci_to_extra_data(int bci, bool create_if_missing);
ProfileData* bci_to_extra_data(int bci, Method* m, bool create_if_missing);
// return the argument info cell
ArgInfoData *arg_info();
@ -2116,6 +2180,10 @@ private:
static bool profile_parameters_jsr292_only();
static bool profile_all_parameters();
void clean_extra_data(BoolObjectClosure* is_alive);
void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false);
void verify_extra_data_clean(BoolObjectClosure* is_alive);
public:
static int header_size() {
return sizeof(MethodData)/wordSize;
@ -2124,7 +2192,7 @@ public:
// Compute the size of a MethodData* before it is created.
static int compute_allocation_size_in_bytes(methodHandle method);
static int compute_allocation_size_in_words(methodHandle method);
static int compute_extra_data_count(int data_size, int empty_bc_count);
static int compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps);
// Determine if a given bytecode can have profile information.
static bool bytecode_has_profile(Bytecodes::Code code) {
@ -2265,9 +2333,26 @@ public:
ProfileData* bci_to_data(int bci);
// Same, but try to create an extra_data record if one is needed:
ProfileData* allocate_bci_to_data(int bci) {
ProfileData* data = bci_to_data(bci);
return (data != NULL) ? data : bci_to_extra_data(bci, true);
ProfileData* allocate_bci_to_data(int bci, Method* m) {
ProfileData* data = NULL;
// If m not NULL, try to allocate a SpeculativeTrapData entry
if (m == NULL) {
data = bci_to_data(bci);
}
if (data != NULL) {
return data;
}
data = bci_to_extra_data(bci, m, true);
if (data != NULL) {
return data;
}
// If SpeculativeTrapData allocation fails try to allocate a
// regular entry
data = bci_to_data(bci);
if (data != NULL) {
return data;
}
return bci_to_extra_data(bci, NULL, true);
}
// Add a handful of extra data records, for trap tracking.
@ -2275,7 +2360,7 @@ public:
DataLayout* extra_data_limit() const { return (DataLayout*)((address)this + size_in_bytes()); }
int extra_data_size() const { return (address)extra_data_limit()
- (address)extra_data_base(); }
static DataLayout* next_extra(DataLayout* dp) { return (DataLayout*)((address)dp + in_bytes(DataLayout::cell_offset(0))); }
static DataLayout* next_extra(DataLayout* dp);
// Return (uint)-1 for overflow.
uint trap_count(int reason) const {
@ -2375,6 +2460,8 @@ public:
static bool profile_return();
static bool profile_parameters();
static bool profile_return_jsr292_only();
void clean_method_data(BoolObjectClosure* is_alive);
};
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP