src/share/vm/oops/methodData.hpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
hotspot Cdiff src/share/vm/oops/methodData.hpp
src/share/vm/oops/methodData.hpp
Print this page
rev 5774 : 8031752: Failed speculative optimizations should be reattempted when root of compilation is different
Summary: support for speculative traps that keep track of the root of the compilation in which a trap occurs.
Reviewed-by:
rev 5775 : imported patch spectrap-chris
*** 118,128 ****
branch_data_tag,
multi_branch_data_tag,
arg_info_data_tag,
call_type_data_tag,
virtual_call_type_data_tag,
! parameters_type_data_tag
};
enum {
// The _struct._flags word is formatted as [trap_state:4 | flags:4].
// The trap state breaks down further as [recompile:1 | reason:3].
--- 118,129 ----
branch_data_tag,
multi_branch_data_tag,
arg_info_data_tag,
call_type_data_tag,
virtual_call_type_data_tag,
! parameters_type_data_tag,
! speculative_trap_data_tag
};
enum {
// The _struct._flags word is formatted as [trap_state:4 | flags:4].
// The trap state breaks down further as [recompile:1 | reason:3].
*** 187,198 ****
}
void set_header(intptr_t value) {
_header._bits = value;
}
! void release_set_header(intptr_t value) {
! OrderAccess::release_store_ptr(&_header._bits, value);
}
intptr_t header() {
return _header._bits;
}
void set_cell_at(int index, intptr_t value) {
--- 188,202 ----
}
void set_header(intptr_t value) {
_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;
}
void set_cell_at(int index, intptr_t value) {
*** 264,273 ****
--- 268,278 ----
class BranchData;
class ArrayData;
class MultiBranchData;
class ArgInfoData;
class ParametersTypeData;
+ class SpeculativeTrapData;
// ProfileData
//
// A ProfileData object is created to refer to a section of profiling
// data in a structured way.
*** 284,293 ****
--- 289,300 ----
#endif // !PRODUCT
// 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; }
enum {
*** 398,407 ****
--- 405,415 ----
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; }
+ virtual bool is_SpeculativeTrapData()const { return false; }
BitData* as_BitData() const {
assert(is_BitData(), "wrong type");
return is_BitData() ? (BitData*) this : NULL;
*** 452,461 ****
--- 460,473 ----
}
ParametersTypeData* as_ParametersTypeData() const {
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
virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {}
*** 467,482 ****
// 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(const ProfileData* data) {}
! virtual void print_data_on(outputStream* st) const {
ShouldNotReachHere();
}
#ifndef PRODUCT
! void print_shared(outputStream* st, const char* name) const;
void tab(outputStream* st, bool first = false) const;
#endif
};
// BitData
--- 479,496 ----
// 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(const ProfileData* data) {}
! 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 char* extra) const;
void tab(outputStream* st, bool first = false) const;
#endif
};
// BitData
*** 520,530 ****
static ByteSize bit_data_size() {
return cell_offset(bit_cell_count);
}
#ifndef PRODUCT
! void print_data_on(outputStream* st) const;
#endif
};
// CounterData
//
--- 534,544 ----
static ByteSize bit_data_size() {
return cell_offset(bit_cell_count);
}
#ifndef PRODUCT
! void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// CounterData
//
*** 564,574 ****
void set_count(uint count) {
set_uint_at(count_off, count);
}
#ifndef PRODUCT
! void print_data_on(outputStream* st) const;
#endif
};
// JumpData
//
--- 578,588 ----
void set_count(uint count) {
set_uint_at(count_off, count);
}
#ifndef PRODUCT
! void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// JumpData
//
*** 637,647 ****
// Specific initialization.
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
! 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
--- 651,661 ----
// Specific initialization.
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
! void print_data_on(outputStream* st, const char* extra = NULL) 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
*** 1048,1058 ****
_ret.clean_weak_klass_links(is_alive_closure);
}
}
#ifndef PRODUCT
! virtual void print_data_on(outputStream* st) const;
#endif
};
// ReceiverTypeData
//
--- 1062,1072 ----
_ret.clean_weak_klass_links(is_alive_closure);
}
}
#ifndef PRODUCT
! virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// ReceiverTypeData
//
*** 1156,1166 ****
// GC support
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
#ifndef PRODUCT
void print_receiver_data_on(outputStream* st) const;
! void print_data_on(outputStream* st) const;
#endif
};
// VirtualCallData
//
--- 1170,1180 ----
// GC support
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
#ifndef PRODUCT
void print_receiver_data_on(outputStream* st) const;
! void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// VirtualCallData
//
*** 1189,1199 ****
static ByteSize virtual_call_data_size() {
return cell_offset(static_cell_count());
}
#ifndef PRODUCT
! void print_data_on(outputStream* st) const;
#endif
};
// VirtualCallTypeData
//
--- 1203,1213 ----
static ByteSize virtual_call_data_size() {
return cell_offset(static_cell_count());
}
#ifndef PRODUCT
! void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// VirtualCallTypeData
//
*** 1315,1325 ****
_ret.clean_weak_klass_links(is_alive_closure);
}
}
#ifndef PRODUCT
! virtual void print_data_on(outputStream* st) const;
#endif
};
// RetData
//
--- 1329,1339 ----
_ret.clean_weak_klass_links(is_alive_closure);
}
}
#ifndef PRODUCT
! virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// RetData
//
*** 1414,1424 ****
// Specific initialization.
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
! void print_data_on(outputStream* st) const;
#endif
};
// BranchData
//
--- 1428,1438 ----
// Specific initialization.
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
! void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// BranchData
//
*** 1478,1488 ****
// Specific initialization.
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
! void print_data_on(outputStream* st) const;
#endif
};
// ArrayData
//
--- 1492,1502 ----
// Specific initialization.
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
! void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// ArrayData
//
*** 1635,1645 ****
// Specific initialization.
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
! void print_data_on(outputStream* st) const;
#endif
};
class ArgInfoData : public ArrayData {
--- 1649,1659 ----
// Specific initialization.
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
! void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
class ArgInfoData : public ArrayData {
*** 1662,1672 ****
void set_arg_modified(int arg, uint val) {
array_set_int_at(arg, val);
}
#ifndef PRODUCT
! void print_data_on(outputStream* st) const;
#endif
};
// ParametersTypeData
//
--- 1676,1686 ----
void set_arg_modified(int arg, uint val) {
array_set_int_at(arg, val);
}
#ifndef PRODUCT
! void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// ParametersTypeData
//
*** 1723,1733 ****
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));
}
--- 1737,1747 ----
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 char* extra = NULL) const;
#endif
static ByteSize stack_slot_offset(int i) {
return cell_offset(stack_slot_local_offset(i));
}
*** 1735,1744 ****
--- 1749,1806 ----
static ByteSize type_offset(int i) {
return cell_offset(type_local_offset(i));
}
};
+ // 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
// a method. Its layout looks like this:
//
*** 1801,1811 ****
bool is_methodData() const volatile { return true; }
// Whole-method sticky bits and flags
enum {
! _trap_hist_limit = 17, // decoupled from Deoptimization::Reason_LIMIT
_trap_hist_mask = max_jubyte,
_extra_data_count = 4 // extra DataLayout headers, for trap history
}; // Public flag values
private:
uint _nof_decompiles; // count of all nmethod removals
--- 1863,1873 ----
bool is_methodData() const volatile { return true; }
// Whole-method sticky bits and flags
enum {
! _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
private:
uint _nof_decompiles; // count of all nmethod removals
*** 1856,1865 ****
--- 1918,1928 ----
intptr_t _data[1];
// 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
DataLayout* data_layout_at(int data_index) const {
assert(data_index % sizeof(intptr_t) == 0, "unaligned");
*** 1899,1910 ****
}
// What is the index of the first data entry?
int first_di() const { return 0; }
// Find or create an extra ProfileData:
! ProfileData* bci_to_extra_data(int bci, bool create_if_missing);
// return the argument info cell
ArgInfoData *arg_info();
enum {
--- 1962,1974 ----
}
// 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, Method* m, bool create_if_missing);
// return the argument info cell
ArgInfoData *arg_info();
enum {
*** 1931,1941 ****
}
// 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);
// Determine if a given bytecode can have profile information.
static bool bytecode_has_profile(Bytecodes::Code code) {
return bytecode_cell_count(code) != no_profile_data;
}
--- 1995,2005 ----
}
// 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, bool needs_speculative_traps);
// Determine if a given bytecode can have profile information.
static bool bytecode_has_profile(Bytecodes::Code code) {
return bytecode_cell_count(code) != no_profile_data;
}
*** 2072,2092 ****
// Get the data at an arbitrary bci, or NULL if there is none.
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);
}
// Add a handful of extra data records, for trap tracking.
DataLayout* extra_data_base() const { return limit_data_position(); }
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))); }
// Return (uint)-1 for overflow.
uint trap_count(int reason) const {
assert((uint)reason < _trap_hist_limit, "oob");
return (int)((_trap_hist._array[reason]+1) & _trap_hist_mask) - 1;
--- 2136,2173 ----
// Get the data at an arbitrary bci, or NULL if there is none.
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, 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.
DataLayout* extra_data_base() const { return limit_data_position(); }
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 (uint)-1 for overflow.
uint trap_count(int reason) const {
assert((uint)reason < _trap_hist_limit, "oob");
return (int)((_trap_hist._array[reason]+1) & _trap_hist_mask) - 1;
*** 2182,2189 ****
--- 2263,2272 ----
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();
+
+ void clean_method_data(BoolObjectClosure* is_alive);
};
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
src/share/vm/oops/methodData.hpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File